547static const char app[] =
"ConfBridge";
548static const char app2[] =
"ConfKick";
551#define CONFERENCE_BRIDGE_BUCKETS 53
554#define RECORD_FILENAME_INITIAL_SPACE 128
571 const char *
name = obj;
596 const char *right_name = arg;
602 right_name = right->
name;
605 cmp = strcasecmp(left->
name, right_name);
608 cmp = strncasecmp(left->
name, right_name, strlen(right_name));
618 return S_OR(custom_sounds->
hasjoin,
"conf-hasjoin");
620 return S_OR(custom_sounds->
hasleft,
"conf-hasleft");
622 return S_OR(custom_sounds->
kicked,
"conf-kicked");
624 return S_OR(custom_sounds->
muted,
"conf-muted");
626 return S_OR(custom_sounds->
unmuted,
"conf-unmuted");
632 return S_OR(custom_sounds->
onlyone,
"conf-onlyone");
644 return S_OR(custom_sounds->
getpin,
"conf-getpin");
650 return S_OR(custom_sounds->
locked,
"conf-locked");
658 return S_OR(custom_sounds->
join,
"confbridge-join");
660 return S_OR(custom_sounds->
leave,
"confbridge-leave");
666 return S_OR(custom_sounds->
begin,
"confbridge-conf-begin");
680 "conference", conference->
name);
719 "conference", conference->
name);
731 if (!bridge_snapshot) {
763 "muted",
user->muted);
843 ext = strrchr(rec_file,
'.');
848 ast_str_set(filename, 0,
"%s-%u", rec_file, (
unsigned int) now);
862 if (!*orig_rec_file) {
1019 const char *filename)
1022 const char *stop_digits;
1268 ast_debug(1,
"Destroying conference bridge '%s'\n", conference->
name);
1317 handler =
user->conference->state->join_waitmarked;
1346 handler =
user->conference->state->leave_waitmarked;
1348 handler =
user->conference->state->leave_unmarked;
1373 mute_user =
user->muted;
1376 mute_system =
user->playing_moh
1381 || (!
user->conference->markedusers
1384 mute_effective = mute_user || mute_system;
1386 ast_debug(1,
"User %s is %s: user:%d system:%d.\n",
1388 mute_user, mute_system);
1389 user->features.mute = mute_effective;
1392 "Conference: %s\r\n"
1394 mute_effective ?
"muted" :
"unmuted",
1395 user->conference->b_profile.name,
1406 user->muted = mute ? 1 : 0;
1410 "Message: participant %s %s\r\n"
1411 "Conference: %s\r\n"
1414 mute ?
"muted" :
"unmuted",
1426 user->playing_moh = 0;
1427 if (!
user->suspended_moh) {
1453 user->playing_moh = 1;
1454 if (!
user->suspended_moh) {
1487 if (--
user->suspended_moh == 0 &&
user->playing_moh) {
1502 if (
user->suspended_moh++ == 0 &&
user->playing_moh) {
1535 if (!(action =
ast_calloc(1,
sizeof(*action)))) {
1605 ast_debug(1,
"Created announcer channel '%s' to conference bridge '%s'\n",
1609 "Confbridge/%s", conference->
name);
1653 char *confbr_name =
NULL;
1665 new_snapshot = msg->
target;
1692 comma = strchr(confbr_name,
',');
1720 if (!found_user && conference->waitingusers) {
1730 ast_log(
LOG_ERROR,
"Unable to find user profile for channel '%s' in bridge '%s'\n",
1731 old_snapshot->
base->
name, confbr_name);
1750 "muted",
user->muted);
1770 int max_members_reached = 0;
1775 ast_debug(1,
"Trying to find conference bridge '%s'\n", conference_name);
1786 ast_debug(1,
"Conference '%s' is locked and caller is not an admin\n", conference_name);
1799 ast_log(
LOG_ERROR,
"Conference '%s' could not be created.\n", conference_name);
1819 if (!conference->
bridge) {
1822 ast_log(
LOG_ERROR,
"Conference '%s' mixing bridge could not be created.\n", conference_name);
1869 "Conference '%s' could not be added to the conferences list.\n", conference_name);
1880 ast_log(
LOG_ERROR,
"Could not allocate announcer channel for conference '%s'\n", conference_name);
1888 ast_log(
LOG_ERROR,
"Could not add announcer channel for conference '%s' bridge\n", conference_name);
1906 ast_debug(1,
"Created conference '%s' and linked to container.\n", conference_name);
1912 user->conference = conference;
1928 user->suspended_moh = 1;
1949 user->u_profile.announcement)) {
1964 (conference->
activeusers >
user->u_profile.announce_user_count_all_after)) {
1974 if (user_count_res) {
2024 }
else if (say_number >= 0) {
2170 .
type =
"Confbridge async playback",
2206 if (async_datastore) {
2209 add = async_datastore->
data;
2216 if (!async_datastore) {
2221 if (!async_datastore->
data) {
2299 if (!async_datastore) {
2303 add = async_datastore->
data;
2385 if (!async_datastore) {
2389 add = async_datastore->
data;
2424 user->talking = talking;
2428 "talking_status", talking ?
"on" :
"off",
2430 if (!talking_extras) {
2441 char pin_guess[
MAX_PIN+1] = { 0, };
2442 const char *pin =
user->u_profile.pin;
2443 char *
tmp = pin_guess;
2453 for (i = 0; i < 3; i++) {
2457 if (!strcasecmp(pin, pin_guess)) {
2469 pin_guess[1] =
'\0';
2470 tmp = pin_guess + 1;
2500 snprintf(
user->name_rec_location,
sizeof(
user->name_rec_location),
2501 "%s/confbridge-name-%s-%s", destdir,
2507 user->name_rec_location,
2518 user->name_rec_location,
2527 user->name_rec_location[0] =
'\0';
2635 int res = 0, volume_adjustments[2];
2637 int async_delete_task_pushed = 0;
2639 const char *b_profile_name =
NULL;
2640 const char *u_profile_name =
NULL;
2641 const char *menu_profile_name =
NULL;
2647 .tech_args.drop_silence = 0,
2662 goto confbridge_cleanup;
2674 goto confbridge_cleanup;
2681 goto confbridge_cleanup;
2686 b_profile_name =
args.b_profile_name;
2690 ast_log(
LOG_WARNING,
"Conference bridge profile %s does not exist\n", b_profile_name ?
2693 goto confbridge_cleanup;
2698 u_profile_name =
args.u_profile_name;
2705 goto confbridge_cleanup;
2721 goto confbridge_cleanup;
2732 goto confbridge_cleanup;
2738 menu_profile_name =
args.menu_profile_name;
2743 ast_log(
LOG_WARNING,
"Conference menu profile %s does not exist\n", menu_profile_name ?
2746 goto confbridge_cleanup;
2751 user.features.dtmf_passthrough = 1;
2753 user.features.dtmf_passthrough = 0;
2758 user.features.text_messaging = 1;
2760 user.features.text_messaging = 0;
2764 if (
user.u_profile.talking_threshold) {
2765 user.tech_args.talking_threshold =
user.u_profile.talking_threshold;
2767 if (
user.u_profile.silence_threshold) {
2768 user.tech_args.silence_threshold =
user.u_profile.silence_threshold;
2777 goto confbridge_cleanup;
2785 goto confbridge_cleanup;
2793 user.tech_args.drop_silence = 1;
2834 if (
user.u_profile.timeout) {
2837 user.u_profile.timeout * 1000,
2849 join_hook_data =
ast_malloc(
sizeof(*join_hook_data));
2850 if (!join_hook_data) {
2852 goto confbridge_cleanup;
2862 goto confbridge_cleanup;
2865 leave_hook_data =
ast_malloc(
sizeof(*leave_hook_data));
2866 if (!leave_hook_data) {
2869 goto confbridge_cleanup;
2880 goto confbridge_cleanup;
2913 goto confbridge_cleanup;
2925 async_delete_task_pushed = 1;
2946 if (volume_adjustments[0]) {
2949 if (volume_adjustments[1]) {
2969 mute = !
user->muted;
2981 unsigned int binaural;
2994 const char *sound_to_play;
3006 cur_user->
muted = mute;
3051 const char *playback_file,
3052 const char *cur_dtmf,
3072 }
else if (
digit == -1) {
3094 dtmf[i] = cur_dtmf[i];
3112 &new_menu_entry, menu);
3128 ast_log(
LOG_WARNING,
"Only admin users can use the kick_last menu action. Channel %s of conf %s is not an admin.\n",
3145 }
else if (!last_user->
kicked) {
3165 args.no_hangup_chan = 1;
3207 int stop_prompts = 0;
3211 switch (menu_action->
id) {
3228 if (!stop_prompts) {
3231 "Message: %s\r\nChannel: %s",
3258 if (!(stop_prompts)) {
3330 const char *channel)
3335 int all = !strcasecmp(
"all", channel);
3336 int participants = !strcasecmp(
"participants", channel);
3381 int wordlen = strlen(
word);
3386 if (!strncasecmp(conference->
name,
word, wordlen) && ++which >
state) {
3404 int wordlen = strlen(
word);
3411 if (!strncasecmp(
"all",
word, wordlen) && ++which >
state) {
3415 if (!strncasecmp(
"participants",
word, wordlen) && ++which >
state) {
3445 e->
command =
"confbridge kick";
3447 "Usage: confbridge kick <conference> <channel>\n"
3448 " Kicks a channel out of the conference bridge.\n"
3449 " (all to kick everyone, participants to kick non-admins).\n";
3467 ast_cli(
a->fd,
"No conference bridge named '%s' found!\n",
a->argv[2]);
3473 if (!strcasecmp(
"all",
a->argv[3]) || !strcasecmp(
"participants",
a->argv[3])) {
3474 ast_cli(
a->fd,
"No participants found!\n");
3476 ast_cli(
a->fd,
"No participant named '%s' found!\n",
a->argv[3]);
3480 ast_cli(
a->fd,
"Kicked '%s' out of conference '%s'\n",
a->argv[3],
a->argv[2]);
3486 char flag_str[6 + 1];
3491 flag_str[pos++] =
'A';
3494 flag_str[pos++] =
'M';
3497 flag_str[pos++] =
'W';
3500 flag_str[pos++] =
'E';
3503 flag_str[pos++] =
'm';
3506 flag_str[pos++] =
'w';
3508 flag_str[pos] =
'\0';
3510 ast_cli(
a->fd,
"%-30s %-6s %-16s %-16s %-16s %s\n",
3513 user->u_profile.name,
3514 user->conference->b_profile.name,
3526 e->
command =
"confbridge list";
3528 "Usage: confbridge list [<name>]\n"
3529 " Lists all currently active conference bridges or a specific conference bridge.\n"
3531 " When a conference bridge name is provided, flags may be shown for users. Below\n"
3532 " are the flags and what they represent.\n"
3535 " A - The user is an admin\n"
3536 " M - The user is a marked user\n"
3537 " W - The user must wait for a marked user to join\n"
3538 " E - The user will be kicked after the last marked user leaves the conference\n"
3539 " m - The user is muted\n"
3540 " w - The user is waiting for a marked user to join\n";
3552 ast_cli(
a->fd,
"Conference Bridge Name Users Marked Locked Muted\n");
3553 ast_cli(
a->fd,
"================================ ====== ====== ====== =====\n");
3556 ast_cli(
a->fd,
"%-32s %6u %6u %-6s %s\n",
3573 ast_cli(
a->fd,
"No conference bridge named '%s' found!\n",
a->argv[2]);
3576 ast_cli(
a->fd,
"Channel Flags User Profile Bridge Profile Menu CallerID\n");
3577 ast_cli(
a->fd,
"============================== ====== ================ ================ ================ ================\n");
3625 const char *chan_name)
3629 int all = !strcasecmp(
"all", chan_name);
3630 int participants = !strcasecmp(
"participants", chan_name);
3675 ast_cli(
a->fd,
"No conference bridge named '%s' found!\n",
a->argv[2]);
3677 }
else if (res == -2) {
3678 if (!strcasecmp(
"all",
a->argv[3]) || !strcasecmp(
"participants",
a->argv[3])) {
3679 ast_cli(
a->fd,
"No participants found in conference %s\n",
a->argv[2]);
3681 ast_cli(
a->fd,
"No channel named '%s' found in conference %s\n",
a->argv[3],
a->argv[2]);
3685 ast_cli(
a->fd,
"%s %s from confbridge %s\n", mute ?
"Muting" :
"Unmuting",
a->argv[3],
a->argv[2]);
3693 e->
command =
"confbridge mute";
3695 "Usage: confbridge mute <conference> <channel>\n"
3696 " Mute a channel in a conference.\n"
3697 " (all to mute everyone, participants to mute non-admins)\n"
3698 " If the specified channel is a prefix,\n"
3699 " the action will be taken on the first\n"
3700 " matching channel.\n";
3724 e->
command =
"confbridge unmute";
3726 "Usage: confbridge unmute <conference> <channel>\n"
3727 " Unmute a channel in a conference.\n"
3728 " (all to unmute everyone, participants to unmute non-admins)\n"
3729 " If the specified channel is a prefix,\n"
3730 " the action will be taken on the first\n"
3731 " matching channel.\n";
3755 e->
command =
"confbridge lock";
3757 "Usage: confbridge lock <conference>\n"
3758 " Lock a conference. While locked, no new non-admins\n"
3759 " may join the conference.\n";
3771 ast_cli(
a->fd,
"Conference %s is not found\n",
a->argv[2]);
3773 ast_cli(
a->fd,
"Conference %s is locked.\n",
a->argv[2]);
3782 e->
command =
"confbridge unlock";
3784 "Usage: confbridge unlock <conference>\n"
3785 " Unlock a previously locked conference.\n";
3797 ast_cli(
a->fd,
"Conference %s is not found\n",
a->argv[2]);
3799 ast_cli(
a->fd,
"Conference %s is unlocked.\n",
a->argv[2]);
3806 const char *rec_file =
NULL;
3811 e->
command =
"confbridge record start";
3813 "Usage: confbridge record start <conference> <file>\n"
3814 " <file> is optional, Otherwise the bridge profile\n"
3815 " record file will be used. If the bridge profile\n"
3816 " has no record file specified, a file will automatically\n"
3817 " be generated in the monitor directory\n";
3829 rec_file =
a->argv[4];
3834 ast_cli(
a->fd,
"Conference not found.\n");
3839 ast_cli(
a->fd,
"Conference is already being recorded.\n");
3849 ast_cli(
a->fd,
"Could not start recording due to internal error.\n");
3856 ast_cli(
a->fd,
"Recording started\n");
3868 e->
command =
"confbridge record stop";
3870 "Usage: confbridge record stop <conference>\n"
3871 " Stop a previously started recording.\n";
3885 ast_cli(
a->fd,
"Conference not found.\n");
3891 ast_cli(
a->fd,
"Recording %sstopped.\n", ret ?
"could not be " :
"");
3907 .
name =
"CONFBRIDGE",
3913 .
name =
"CONFBRIDGE_INFO",
3919 char *parse, *outbuf;
3922 int bytes, count = 0;
3949 if (!strcasecmp(
args.type,
"parties")) {
3960 }
else if (!strcasecmp(
args.type,
"active")) {
3966 }
else if (!strcasecmp(
args.type,
"waiting")) {
3972 }
else if (!strcasecmp(
args.type,
"admins")) {
3980 }
else if (!strcasecmp(
args.type,
"marked")) {
3997 .
name =
"CONFBRIDGE_CHANNELS",
4018 "Event: ConfbridgeList\r\n"
4020 "Conference: %s\r\n"
4022 "MarkedUser: %s\r\n"
4023 "WaitMarked: %s\r\n"
4025 "EndMarkedAny: %s\r\n"
4029 "AnsweredTime: %d\r\n"
4062 snprintf(id_text,
sizeof(id_text),
"ActionID: %s\r\n", actionid);
4101 char id_text[512] =
"";
4105 snprintf(id_text,
sizeof(id_text),
"ActionID: %s\r\n", actionid);
4122 "Event: ConfbridgeListRooms\r\n"
4124 "Conference: %s\r\n"
4172 }
else if (res == -2) {
4245 astman_send_ack(s, m, !strcmp(
"all", channel) ?
"All participants kicked" :
"User kicked");
4406 if (!strcasecmp(
args.type,
"parties")) {
4413 }
else if (!strcasecmp(
args.type,
"admins")) {
4419 }
else if (!strcasecmp(
args.type,
"marked")) {
4425 }
else if (!strcasecmp(
args.type,
"locked")) {
4427 }
else if (!strcasecmp(
args.type,
"muted")) {
4432 snprintf(
buf,
len,
"%d", count);