diff --git a/apps/app_meetme.c b/apps/app_meetme.c index 2b77c0f6864502a5ca23d3df96c268f73c8b3e67..7dacfc57ebcbb512417794864cbcdad68a4b9fb2 100755 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -38,9 +38,11 @@ static char *tdesc = "Simple MeetMe conference bridge"; static char *app = "MeetMe"; static char *app2 = "MeetMeCount"; +static char *app3 = "MeetMeAdmin"; static char *synopsis = "Simple MeetMe conference bridge"; static char *synopsis2 = "MeetMe participant count"; +static char *synopsis3 = "Send Admin Commands to a conference"; static char *descrip = " MeetMe(confno[,[options][,pin]]): Enters the user into a specified MeetMe conference.\n" @@ -59,11 +61,11 @@ static char *descrip = " 'v' -- video mode\n" " 'q' -- quiet mode (don't play enter/leave sounds)\n" " 'M' -- enable music on hold when the conference has a single caller\n" +" 'x' -- exit the conference if the last marked user left\n" " 'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND}\n" " Default: conf-background.agi\n" " (Note: This does not work with non-Zap channels in the same conference)\n" -" Not implemented yet:\n" -" 's' -- send user to admin/user menu if '*' is received\n" +" 'u' -- send user to admin/user menu if '*' is received\n" " 'a' -- set admin mode\n"; static char *descrip2 = @@ -72,6 +74,8 @@ static char *descrip2 = "will be returned in the variable. Returns 0 on success or -1 on a hangup.\n" "A ZAPTEL INTERFACE MUST BE INSTALLED FOR CONFERENCING FUNCTIONALITY.\n"; +static char *descrip3 = ""; + STANDARD_LOCAL_USER; LOCAL_USER_DECL; @@ -81,14 +85,35 @@ static struct ast_conference { int fd; /* Announcements fd */ int zapconf; /* Zaptel Conf # */ int users; /* Number of active users */ + int markedusers; /* Number of marked users */ + struct ast_conf_user *firstuser; /* Pointer to the first user struct */ + struct ast_conf_user *lastuser; /* Pointer to the last user struct */ time_t start; /* Start time (s) */ int isdynamic; /* Created on the fly? */ + int locked; /* Is the conference locked? */ char pin[AST_MAX_EXTENSION]; /* If protected by a PIN */ struct ast_conference *next; } *confs; +struct ast_conf_user { + int user_no; /* User Number */ + struct ast_conf_user *prevuser; /* Pointer to the previous user */ + struct ast_conf_user *nextuser; /* Pointer to the next user */ + int userflags; /* Flags as set in the conference */ + int adminflags; /* Flags set by the Admin */ + struct ast_channel *chan; /* Connected channel */ + char usrvalue[50]; /* Custom User Value */ + time_t jointime; /* Time the user joined the conference */ +}; + +#define ADMINFLAG_MUTED (1 << 1) /* User is muted */ +#define ADMINFLAG_KICKME (1 << 2) /* User is kicked */ + + static ast_mutex_t conflock = AST_MUTEX_INITIALIZER; +static int admin_exec(struct ast_channel *chan, void *data); + #include "enter.h" #include "leave.h" @@ -106,6 +131,7 @@ static ast_mutex_t conflock = AST_MUTEX_INITIALIZER; #define CONFFLAG_VIDEO (1 << 7) /* Set to enable video mode */ #define CONFFLAG_AGI (1 << 8) /* Set to run AGI Script in Background */ #define CONFFLAG_MOH (1 << 9) /* Set to have music on hold when */ +#define CONFFLAG_ADMINEXIT (1 << 10) /* If set the MeetMe will return if all marked with this flag left */ static int careful_write(int fd, unsigned char *data, int len) @@ -186,9 +212,13 @@ static struct ast_conference *build_conf(char *confno, char *pin, int make, int cnf = NULL; goto cnfout; } + /* Fill the conference struct */ cnf->start = time(NULL); cnf->zapconf = ztc.confno; cnf->isdynamic = dynamic; + cnf->firstuser = NULL; + cnf->lastuser = NULL; + cnf->locked = 0; if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Created ZapTel conference %d for conference '%s'\n", cnf->zapconf, cnf->confno); cnf->next = confs; @@ -203,48 +233,209 @@ cnfout: static int confs_show(int fd, int argc, char **argv) { - struct ast_conference *conf; + ast_cli(fd, "Deprecated! Please use 'meetme' instead.\n"); + return RESULT_SUCCESS; +} + +static char show_confs_usage[] = +"Deprecated! Please use 'meetme' instead.\n"; + +static struct ast_cli_entry cli_show_confs = { + { "show", "conferences", NULL }, confs_show, + "Show status of conferences", show_confs_usage, NULL }; + +static int conf_cmd(int fd, int argc, char **argv) { + /* Process the command */ + struct ast_conference *cnf; + struct ast_conf_user *user; int hr, min, sec; + int i = 0; time_t now; char *header_format = "%-14s %-14s %-8s %-8s\n"; char *data_format = "%-12.12s %4.4d %02d:%02d:%02d %-8s\n"; - + char cmdline[1024] = ""; + if (argc > 8) + ast_cli(fd, "Invalid Arguments.\n"); + /* Check for length so no buffer will overflow... */ + for (i = 0; i < argc; i++) { + if (strlen(argv[i]) > 100) + ast_cli(fd, "Invalid Arguments.\n"); + } + if (argc == 1) { + /* List all the conferences */ now = time(NULL); - if (argc != 2) - return RESULT_SHOWUSAGE; - conf = confs; - if (!conf) { + cnf = confs; + if (!cnf) { ast_cli(fd, "No active conferences.\n"); return RESULT_SUCCESS; } ast_cli(fd, header_format, "Conf Num", "Parties", "Activity", "Creation"); - while(conf) { - hr = (now - conf->start) / 3600; - min = ((now - conf->start) % 3600) / 60; - sec = (now - conf->start) % 60; + while(cnf) { + hr = (now - cnf->start) / 3600; + min = ((now - cnf->start) % 3600) / 60; + sec = (now - cnf->start) % 60; - if (conf->isdynamic) - ast_cli(fd, data_format, conf->confno, conf->users, hr, min, sec, "Dynamic"); + if (cnf->isdynamic) + ast_cli(fd, data_format, cnf->confno, cnf->users, hr, min, sec, "Dynamic"); else - ast_cli(fd, data_format, conf->confno, conf->users, hr, min, sec, "Static"); + ast_cli(fd, data_format, cnf->confno, cnf->users, hr, min, sec, "Static"); - conf = conf->next; + cnf = cnf->next; } return RESULT_SUCCESS; + } + if (argc < 3) + return RESULT_SHOWUSAGE; + strncpy(cmdline, argv[2], 100); + if (strstr(argv[1], "lock")) { + if (strcmp(argv[1], "lock") == 0) { + /* Lock */ + strcat(cmdline, "|L"); + } else { + /* Unlock */ + strcat(cmdline, "|l"); + } + } else if (strstr(argv[1], "mute")) { + if (argc < 4) + return RESULT_SHOWUSAGE; + if (strcmp(argv[1], "mute") == 0) { + /* Mute */ + strcat(cmdline, "|M|"); + strcat(cmdline, argv[3]); + } else { + /* Unmute */ + strcat(cmdline, "|m|"); + strcat(cmdline, argv[3]); + } + } else if (strcmp(argv[1], "kick") == 0) { + if (argc < 4) + return RESULT_SHOWUSAGE; + if (strcmp(argv[3], "all") == 0) { + /* Kick all */ + strcat(cmdline, "|K"); + } else { + /* Kick a single user */ + strcat(cmdline, "|k|"); + strcat(cmdline, argv[3]); + } + } else if(strcmp(argv[1], "list") == 0) { + /* List all the users in a conference */ + if (!confs) { + ast_cli(fd, "No active conferences.\n"); + return RESULT_SUCCESS; + } + cnf = confs; + /* Find the right conference */ + while(cnf) { + if (strcmp(cnf->confno, argv[2]) == 0) + break; + if (cnf->next) { + cnf = cnf->next; + } else { + ast_cli(fd, "No such conference: %s.\n",argv[2]); + return RESULT_SUCCESS; + } + } + /* Show all the users */ + user = cnf->firstuser; + while(user) { + ast_cli(fd, "User Number: %i on Channel: %s\n", user->user_no, user->chan->name); + user = user->nextuser; + } + return RESULT_SUCCESS; + } else + return RESULT_SHOWUSAGE; + ast_log(LOG_NOTICE, "Cmdline: %s\n", cmdline); + admin_exec(NULL, cmdline); + return 0; } -static char show_confs_usage[] = -"Usage: show conferences\n" -" Provides summary information on conferences with active\n" -" participation.\n"; +static char *complete_confcmd(char *line, char *word, int pos, int state) { + #define CONF_COMMANDS 6 + int which = 0, x = 0; + struct ast_conference *cnf = NULL; + struct ast_conf_user *usr = NULL; + char *confno = NULL; + char usrno[50] = ""; + char cmds[CONF_COMMANDS][20] = {"lock", "unlock", "mute", "unmute", "kick", "list"}; + char *myline; + + if (pos == 1) { + /* Command */ + for (x = 0;x < CONF_COMMANDS; x++) { + if (!strncasecmp(cmds[x], word, strlen(word))) { + if (++which > state) { + return strdup(cmds[x]); + } + } + } + } else if (pos == 2) { + /* Conference Number */ + ast_mutex_lock(&conflock); + cnf = confs; + while(cnf) { + if (!strncasecmp(word, cnf->confno, strlen(word))) { + if (++which > state) + break; + } + cnf = cnf->next; + } + ast_mutex_unlock(&conflock); + return cnf ? strdup(cnf->confno) : NULL; + } else if (pos == 3) { + /* User Number || Conf Command option*/ + if (strstr(line, "mute") || strstr(line, "kick")) { + if ((state == 0) && (strstr(line, "kick")) && !(strncasecmp(word, "all", strlen(word)))) { + return strdup("all"); + } + which++; + ast_mutex_lock(&conflock); + cnf = confs; -static struct ast_cli_entry cli_show_confs = { - { "show", "conferences", NULL }, confs_show, - "Show status of conferences", show_confs_usage, NULL }; + /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */ + myline = strdupa(line); + if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) { + while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0)) + ; + } + + while(cnf) { + if (strcmp(confno, cnf->confno) == 0) { + break; + } + cnf = cnf->next; + } + if (cnf) { + /* Search for the user */ + usr = cnf->firstuser; + while(usr) { + sprintf(usrno, "%i", usr->user_no); + if (!strncasecmp(word, usrno, strlen(word))) { + if (++which > state) + break; + } + usr = usr->nextuser; + } + } + ast_mutex_unlock(&conflock); + return usr ? strdup(usrno) : NULL; + } + } + return NULL; +} + +static char conf_usage[] = +"Usage: meetme (un)lock|(un)mute|kick|list confno usernumber\n" +" Executes a command for the conference or on a conferee\n"; + +static struct ast_cli_entry cli_conf = { + { "meetme", NULL, NULL }, conf_cmd, + "Execute a command on a conference or conferee", conf_usage, complete_confcmd }; static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags) { struct ast_conference *prev=NULL, *cur; + struct ast_conf_user *user = malloc(sizeof(struct ast_conf_user)); int fd; struct zt_confinfo ztc; struct ast_frame *f; @@ -261,16 +452,62 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c int firstpass = 0; int ret = -1; int x; + int menu_active = 0; struct ast_app *app; char *agifile; char *agifiledefault = "conf-background.agi"; + char meetmesecs[30]; ZT_BUFFERINFO bi; char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET]; char *buf = __buf + AST_FRIENDLY_OFFSET; + user->user_no = 0; /* User number 0 means starting up user! (dead - not in the list!) */ + + if (conf->locked) { + /* Sorry, but this confernce is locked! */ + if (!ast_streamfile(chan, "conf-locked", chan->language)) + ast_waitstream(chan, ""); + goto outrun; + } + conf->users++; + if (confflags & CONFFLAG_ADMINEXIT) { + if (conf->markedusers == -1) { + conf->markedusers = 1; + } else { + conf->markedusers++; + } + } + + ast_mutex_lock(&conflock); + if (conf->firstuser == NULL) { + /* Fill the first new User struct */ + user->user_no = 1; + user->nextuser = NULL; + user->prevuser = NULL; + conf->firstuser = user; + conf->lastuser = user; + } else { + /* Fill the new user struct */ + user->user_no = conf->lastuser->user_no + 1; + user->prevuser = conf->lastuser; + user->nextuser = NULL; + if (conf->lastuser->nextuser != NULL) { + ast_log(LOG_WARNING, "Error in User Management!\n"); + goto outrun; + } else { + conf->lastuser->nextuser = user; + conf->lastuser = user; + } + } + strncpy(user->usrvalue, "test", sizeof(user->usrvalue)); + user->chan = chan; + user->userflags = confflags; + user->adminflags = 0; + ast_mutex_unlock(&conflock); + if (!(confflags & CONFFLAG_QUIET) && conf->users == 1) { if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) ast_waitstream(chan, ""); @@ -388,7 +625,6 @@ zapretry: "Meetme: %s\r\n", chan->name, chan->uniqueid, conf->confno); - if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) { firstpass = 1; if (!(confflags & CONFFLAG_QUIET)) @@ -422,10 +658,20 @@ zapretry: x = 0; ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0); } - } else for(;;) { + } else { + if (!strcasecmp(chan->type,"Zap") && (confflags & CONFFLAG_STARMENU)) { + /* Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */ + x = 1; + ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0); + } + for(;;) { outfd = -1; ms = -1; c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms); + + /* Update the struct with the actual confflags */ + user->userflags = confflags; + /* trying to add moh for single person conf */ if (confflags & CONFFLAG_MOH) { if (conf->users == 1) { @@ -440,7 +686,47 @@ zapretry: } } } - /* end modifications */ + + /* Leave if the last marked user left */ + if ((confflags & CONFFLAG_ADMINEXIT) && (conf->markedusers == 0)) { + ret = 0; + break; + } + + /* Check if the admin changed my modes */ + if (user->adminflags) { + /* Set the new modes */ + if ((user->adminflags & ADMINFLAG_MUTED) && (ztc.confmode & ZT_CONF_TALKER)) { + ztc.confmode ^= ZT_CONF_TALKER; + if (ioctl(fd, ZT_SETCONF, &ztc)) { + ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); + ret = -1; + break; + } + } + if (!(user->adminflags & ADMINFLAG_MUTED) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) { + ztc.confmode |= ZT_CONF_TALKER; + if (ioctl(fd, ZT_SETCONF, &ztc)) { + ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); + ret = -1; + break; + } + } + if (user->adminflags & ADMINFLAG_KICKME) { + //You have been kicked. + if (!ast_streamfile(chan, "conf-kicked", chan->language)) + ast_waitstream(chan, ""); + ret = 0; + break; + } + } else if (!(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) { + ztc.confmode |= ZT_CONF_TALKER; + if (ioctl(fd, ZT_SETCONF, &ztc)) { + ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); + ret = -1; + break; + } + } if (c) { if (c->fds[0] != origfd) { @@ -458,13 +744,105 @@ zapretry: if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) { ret = 0; break; - } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) { + } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) { + if (musiconhold) { + ast_moh_stop(chan); + } if ((confflags & CONFFLAG_ADMIN)) { - /* Do admin stuff here */ + /* Admin menu */ + if (!menu_active) { + menu_active = 1; + /* Record this sound! */ + if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) + ast_waitstream(chan, ""); } else { - /* Do user menu here */ + switch(f->subclass - 48) { + case 1: /* Un/Mute */ + menu_active = 0; + if (ztc.confmode & ZT_CONF_TALKER) { + ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER; + confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER; + } else { + ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; + confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER; + } + if (ioctl(fd, ZT_SETCONF, &ztc)) { + ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); + ret = -1; + break; + } + if (ztc.confmode & ZT_CONF_TALKER) { + if (!ast_streamfile(chan, "conf-unmuted", chan->language)) + ast_waitstream(chan, ""); + } else { + if (!ast_streamfile(chan, "conf-muted", chan->language)) + ast_waitstream(chan, ""); + } + break; + case 2: /* Un/Lock the Conference */ + menu_active = 0; + if (conf->locked) { + conf->locked = 0; + if (!ast_streamfile(chan, "conf-unlockednow", chan->language)) + ast_waitstream(chan, ""); + } else { + conf->locked = 1; + if (!ast_streamfile(chan, "conf-lockednow", chan->language)) + ast_waitstream(chan, ""); } + break; + default: + menu_active = 0; + /* Play an error message! */ + if (!ast_streamfile(chan, "conf-errormenu", chan->language)) + ast_waitstream(chan, ""); + break; + } + } + } else { + /* User menu */ + if (!menu_active) { + menu_active = 1; + /* Record this sound! */ + if (!ast_streamfile(chan, "conf-usermenu", chan->language)) + ast_waitstream(chan, ""); + } else { + switch(f->subclass - 48) { + case 1: /* Un/Mute */ + menu_active = 0; + if (ztc.confmode & ZT_CONF_TALKER) { + ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER; + confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER; + } else if (!(user->adminflags & ADMINFLAG_MUTED)) { + ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; + confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER; + } + if (ioctl(fd, ZT_SETCONF, &ztc)) { + ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); + ret = -1; + break; + } + if (ztc.confmode & ZT_CONF_TALKER) { + if (!ast_streamfile(chan, "conf-unmuted", chan->language)) + ast_waitstream(chan, ""); + } else { + if (!ast_streamfile(chan, "conf-muted", chan->language)) + ast_waitstream(chan, ""); + } + break; + default: + menu_active = 0; + /* Play an error message! */ + if (!ast_streamfile(chan, "errormenu", chan->language)) + ast_waitstream(chan, ""); + break; + } + } + } + if (musiconhold) { + ast_moh_start(chan, NULL); + } } else if (fd != chan->fds[0]) { if (f->frametype == AST_FRAME_VOICE) { if (f->subclass == AST_FORMAT_ULAW) { @@ -493,7 +871,7 @@ zapretry: ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno)); } } - + } if (fd != chan->fds[0]) close(fd); else { @@ -510,23 +888,17 @@ zapretry: conf_play(conf, LEAVE); outrun: - - ast_mutex_lock(&conflock); - /* Clean up */ - conf->users--; - - ast_log(LOG_DEBUG, "Removed channel %s from ZAP conf %d\n", chan->name, conf->zapconf); - + if (user->user_no) { /* Only cleanup users who really joined! */ manager_event(EVENT_FLAG_CALL, "MeetmeLeave", "Channel: %s\r\n" "Uniqueid: %s\r\n" "Meetme: %s\r\n", chan->name, chan->uniqueid, conf->confno); - - + ast_mutex_lock(&conflock); + conf->users--; + cur = confs; if (!conf->users) { /* No more users -- close this one out */ - cur = confs; while(cur) { if (cur == conf) { if (prev) @@ -542,7 +914,24 @@ outrun: ast_log(LOG_WARNING, "Conference not found\n"); close(conf->fd); free(conf); + } else { + /* Remove the user struct */ + if (user == cur->firstuser) { + cur->firstuser->nextuser->prevuser = NULL; + cur->firstuser = cur->firstuser->nextuser; + } else if (user == cur->lastuser){ + cur->lastuser->prevuser->nextuser = NULL; + cur->lastuser = cur->lastuser->prevuser; + } else { + user->nextuser->prevuser = user->prevuser; + user->prevuser->nextuser = user->nextuser; + } + /* Return the number of seconds the user was in the conf */ + sprintf(meetmesecs, "%i", (int) (user->jointime - time(NULL))); + pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs); + } } + free(user); ast_mutex_unlock(&conflock); return ret; } @@ -692,7 +1081,7 @@ static int conf_exec(struct ast_channel *chan, void *data) confflags |= CONFFLAG_MONITOR; if (strchr(inflags, 'p')) confflags |= CONFFLAG_POUNDEXIT; - if (strchr(inflags, 's')) + if (strchr(inflags, 'u')) confflags |= CONFFLAG_STARMENU; if (strchr(inflags, 't')) confflags |= CONFFLAG_TALKER; @@ -700,6 +1089,8 @@ static int conf_exec(struct ast_channel *chan, void *data) confflags |= CONFFLAG_QUIET; if (strchr(inflags, 'M')) confflags |= CONFFLAG_MOH; + if (strchr(inflags, 'x')) + confflags |= CONFFLAG_ADMINEXIT; if (strchr(inflags, 'b')) confflags |= CONFFLAG_AGI; if (strchr(inflags, 'd')) @@ -873,10 +1264,102 @@ static int conf_exec(struct ast_channel *chan, void *data) return res; } +static struct ast_conf_user* find_user(struct ast_conference *conf, char *callerident) { + struct ast_conf_user *user = NULL; + char usrno[1024] = ""; + if (conf && callerident) { + user = conf->firstuser; + while(user) { + sprintf(usrno, "%i", user->user_no); + if (strcmp(usrno, callerident) == 0) + return user; + user = user->nextuser; + } + } + return NULL; +} + +static int admin_exec(struct ast_channel *chan, void *data) { + /* MeetMeAdmin(confno, command, caller) */ + char *params, *command = NULL, *caller = NULL, *conf = NULL; + struct ast_conference *cnf; + struct ast_conf_user *user = NULL; + + ast_mutex_lock(&conflock); + /* The param has the conference number the user and the command to execute */ + if (data && strlen(data)) { + params = ast_strdupa((char *) data); + conf = strsep(¶ms, "|"); + command = strsep(¶ms, "|"); + caller = strsep(¶ms, "|"); + + ast_mutex_lock(&conflock); + cnf = confs; + while (cnf) { + if (strcmp(cnf->confno, conf) == 0) + break; + cnf = cnf->next; + } + ast_mutex_unlock(&conflock); + + if (caller) + user = find_user(cnf, caller); + + if (cnf) { + switch((int) (*command)) { + case 76: /* L: Lock */ + cnf->locked = 1; + break; + case 108: /* l: Unlock */ + cnf->locked = 0; + break; + case 75: /* K: kick all users*/ + user = cnf->firstuser; + while(user) { + user->adminflags |= ADMINFLAG_KICKME; + if (user->nextuser) { + user = user->nextuser; + } else { + break; + } + } + break; + case 77: /* M: Mute */ + if (user) { + user->adminflags |= ADMINFLAG_MUTED; + } else { + ast_log(LOG_NOTICE, "Specified User not found!"); + } + break; + case 109: /* m: Unmute */ + if (user && (user->adminflags & ADMINFLAG_MUTED)) { + user->adminflags ^= ADMINFLAG_MUTED; + } else { + ast_log(LOG_NOTICE, "Specified User not found or he muted himself!"); + } + break; + case 107: /* k: Kick user */ + if (user) { + user->adminflags |= ADMINFLAG_KICKME; + } else { + ast_log(LOG_NOTICE, "Specified User not found!"); + } + break; + } + } else { + ast_log(LOG_NOTICE, "Conference Number not found\n"); + } + } + ast_mutex_unlock(&conflock); + return 0; +} + int unload_module(void) { STANDARD_HANGUP_LOCALUSERS; ast_cli_unregister(&cli_show_confs); + ast_cli_unregister(&cli_conf); + ast_unregister_application(app3); ast_unregister_application(app2); return ast_unregister_application(app); } @@ -884,6 +1367,8 @@ int unload_module(void) int load_module(void) { ast_cli_register(&cli_show_confs); + ast_cli_register(&cli_conf); + ast_register_application(app3, admin_exec, synopsis3, descrip3); ast_register_application(app2, count_exec, synopsis2, descrip2); return ast_register_application(app, conf_exec, synopsis, descrip); } diff --git a/channel.c b/channel.c index 896fa89983d78438312c5ae5c991cd39b8c5aaa6..cd7aaeba87396c506106c390e9b5356ad4bdd86f 100755 --- a/channel.c +++ b/channel.c @@ -468,6 +468,19 @@ struct ast_channel *ast_channel_walk_locked(struct ast_channel *prev) } +struct ast_channel *ast_get_channel_by_name_locked(char *channame) +{ + struct ast_channel *chan; + chan = ast_channel_walk_locked(NULL); + while(chan) { + if (!strcasecmp(chan->name, channame)) + return chan; + ast_mutex_unlock(&chan->lock); + chan = ast_channel_walk_locked(NULL); + } + return NULL; +} + int ast_safe_sleep_conditional( struct ast_channel *chan, int ms, int (*cond)(void*), void *data ) { diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index baae962138d40a217684f4eaaae915b6551074b0..758670f2824ccbaa5332e992037752f9ef618d5e 100755 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -628,6 +628,9 @@ int ast_recvchar(struct ast_channel *chan, int timeout); */ struct ast_channel *ast_channel_walk_locked(struct ast_channel *prev); +//! Get channel by name (locks channel) +struct ast_channel *ast_get_channel_by_name_locked(char *channame); + //! Waits for a digit /*! * \param c channel to wait for a digit on diff --git a/manager.c b/manager.c index 53dcf6f094fbeb6df512ca201dbd1d69aa25e55a..b619baf044b5fa320eb3078da338da86d137c941 100755 --- a/manager.c +++ b/manager.c @@ -455,6 +455,7 @@ static int action_redirect(struct mansession *s, struct message *m) char *exten = astman_get_header(m, "Exten"); char *context = astman_get_header(m, "Context"); char *priority = astman_get_header(m, "Priority"); + struct ast_channel *chan, *chan2 = NULL; int pi = 0; int res; if (!name || !strlen(name)) { @@ -465,10 +466,16 @@ static int action_redirect(struct mansession *s, struct message *m) astman_send_error(s, m, "Invalid priority\n"); return 0; } - res = ast_async_goto_by_name(name, context, exten, pi); + chan = ast_get_channel_by_name_locked(name); + if (strlen(name2)) + chan2 = ast_get_channel_by_name_locked(name2); + res = ast_async_goto(chan, context, exten, pi); if (!res) { if (strlen(name2)) { - res = ast_async_goto_by_name(name2, context, exten, pi); + if (chan2) + res = ast_async_goto(chan2, context, exten, pi); + else + res = -1; if (!res) astman_send_ack(s, m, "Dual Redirect successful"); else @@ -477,6 +484,10 @@ static int action_redirect(struct mansession *s, struct message *m) astman_send_ack(s, m, "Redirect successful"); } else astman_send_error(s, m, "Redirect failed"); + if (chan) + ast_mutex_unlock(&chan->lock); + if (chan2) + ast_mutex_unlock(&chan2->lock); return 0; } diff --git a/sounds.txt b/sounds.txt index 419497c71a6bb08271f9352682c70b66e1b9cf13..ce7e5a4a87fdbffdcb1493ac6bd2002404647ccd 100755 --- a/sounds.txt +++ b/sounds.txt @@ -612,3 +612,21 @@ %plus.gsm%plus [+] %equals.gsm%equals [=] + +%conf-locked.gsm%This conference is locked! + +%conf-kicked.gsm%You have been kicked from this conference + +%conf-adminmenu.gsm%Please press 1 to mute or unmute yourself, or press 2 to lock or unlock the conference + +%conf-usermenu.gsm%Please press 1 to mute or unmute yourself + +%conf-errormenu.gsm%Invalid Choice + +%conf-muted.gsm%You are now muted + +%conf-unmuted.gsm%You are now unmuted + +%conf-lockednow.gsm%The conference is now locked + +%conf-unlockednow.gsm%The conference is now unlocked diff --git a/sounds/conf-adminmenu.gsm b/sounds/conf-adminmenu.gsm new file mode 100755 index 0000000000000000000000000000000000000000..ba5301717ecca001edee8ce1a29364af036ddb09 Binary files /dev/null and b/sounds/conf-adminmenu.gsm differ diff --git a/sounds/conf-errormenu.gsm b/sounds/conf-errormenu.gsm new file mode 100755 index 0000000000000000000000000000000000000000..6388c1c5201dd4ae69ab43b2c5ea594f8818fe48 Binary files /dev/null and b/sounds/conf-errormenu.gsm differ diff --git a/sounds/conf-kicked.gsm b/sounds/conf-kicked.gsm new file mode 100755 index 0000000000000000000000000000000000000000..33ef20cd66244d50bc0744648eb3174154e81575 Binary files /dev/null and b/sounds/conf-kicked.gsm differ diff --git a/sounds/conf-locked.gsm b/sounds/conf-locked.gsm new file mode 100755 index 0000000000000000000000000000000000000000..82b59be5d2805374724ceb741e0cb6e58af2a147 Binary files /dev/null and b/sounds/conf-locked.gsm differ diff --git a/sounds/conf-lockednow.gsm b/sounds/conf-lockednow.gsm new file mode 100755 index 0000000000000000000000000000000000000000..0288ff62b3edf048ca6abdbb60eccbb16cb6bcc0 Binary files /dev/null and b/sounds/conf-lockednow.gsm differ diff --git a/sounds/conf-muted.gsm b/sounds/conf-muted.gsm new file mode 100755 index 0000000000000000000000000000000000000000..014a58998b3d69cec7a468c26031083c6a64275a Binary files /dev/null and b/sounds/conf-muted.gsm differ diff --git a/sounds/conf-unlockednow.gsm b/sounds/conf-unlockednow.gsm new file mode 100755 index 0000000000000000000000000000000000000000..a9cfe0077c107a61f1705cc45c811c7366ae6c6d Binary files /dev/null and b/sounds/conf-unlockednow.gsm differ diff --git a/sounds/conf-unmuted.gsm b/sounds/conf-unmuted.gsm new file mode 100755 index 0000000000000000000000000000000000000000..44c26b935adcba7041bf6f9b0378e09a75332538 Binary files /dev/null and b/sounds/conf-unmuted.gsm differ diff --git a/sounds/conf-usermenu.gsm b/sounds/conf-usermenu.gsm new file mode 100755 index 0000000000000000000000000000000000000000..2ce525cd488371ea4b84932d94a335aa8ceecd6b Binary files /dev/null and b/sounds/conf-usermenu.gsm differ