Index: apps/app_meetme.c =================================================================== RCS file: /usr/cvsroot/asterisk/apps/app_meetme.c,v retrieving revision 1.92 diff -u -r1.92 app_meetme.c --- apps/app_meetme.c 29 Mar 2005 06:34:50 -0000 1.92 +++ apps/app_meetme.c 2 Apr 2005 17:52:49 -0000 @@ -52,60 +52,60 @@ static char *synopsis3 = "MeetMe conference Administration"; static char *descrip = -" MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe conference.\n" -"If the conference number is omitted, the user will be prompted to enter\n" -"one. \n" -"MeetMe returns 0 if user pressed # to exit (see option 'p'), otherwise -1.\n" -"Please note: A ZAPTEL INTERFACE MUST BE INSTALLED FOR CONFERENCING TO WORK!\n\n" - -"The option string may contain zero or more of the following characters:\n" -" 'm' -- set monitor only mode (Listen only, no talking)\n" -" 't' -- set talk only mode. (Talk only, no listening)\n" -" 'T' -- set talker detection (sent to manager interface and meetme list)\n" -" 'i' -- announce user join/leave\n" -" 'p' -- allow user to exit the conference by pressing '#'\n" -" 'X' -- allow user to exit the conference by entering a valid single\n" -" digit extension ${MEETME_EXIT_CONTEXT} or the current context\n" -" if that variable is not defined.\n" -" 'd' -- dynamically add conference\n" -" 'D' -- dynamically add conference, prompting for a PIN\n" -" 'e' -- select an empty conference\n" -" 'E' -- select an empty pinless conference\n" -" 'v' -- video mode\n" -" 'r' -- Record conference (records as ${MEETME_RECORDINGFILE}\n" -" using format ${MEETME_RECORDINGFORMAT}). Default filename is\n" -" meetme-conf-rec-${CONFNO}-${UNIQUEID} and the default format is wav.\n" -" 'q' -- quiet mode (don't play enter/leave sounds)\n" -" 'c' -- announce user(s) count on joining a conference\n" -" 'M' -- enable music on hold when the conference has a single caller\n" -" 'x' -- close the conference when last marked user exits\n" -" 'w' -- wait until the marked user enters the conference\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" -" 's' -- Present menu (user or admin) when '*' is received ('send' to menu)\n" -" 'a' -- set admin mode\n" -" 'A' -- set marked mode\n" -" 'P' -- always prompt for the pin even if it is specified\n"; + " MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe conference.\n" + "If the conference number is omitted, the user will be prompted to enter\n" + "one. \n" + "MeetMe returns 0 if user pressed # to exit (see option 'p'), otherwise -1.\n" + "Please note: A ZAPTEL INTERFACE MUST BE INSTALLED FOR CONFERENCING TO WORK!\n\n" + + "The option string may contain zero or more of the following characters:\n" + " 'm' -- set monitor only mode (Listen only, no talking)\n" + " 't' -- set talk only mode. (Talk only, no listening)\n" + " 'T' -- set talker detection (sent to manager interface and meetme list)\n" + " 'i' -- announce user join/leave\n" + " 'p' -- allow user to exit the conference by pressing '#'\n" + " 'X' -- allow user to exit the conference by entering a valid single\n" + " digit extension ${MEETME_EXIT_CONTEXT} or the current context\n" + " if that variable is not defined.\n" + " 'd' -- dynamically add conference\n" + " 'D' -- dynamically add conference, prompting for a PIN\n" + " 'e' -- select an empty conference\n" + " 'E' -- select an empty pinless conference\n" + " 'v' -- video mode\n" + " 'r' -- Record conference (records as ${MEETME_RECORDINGFILE}\n" + " using format ${MEETME_RECORDINGFORMAT}). Default filename is\n" + " meetme-conf-rec-${CONFNO}-${UNIQUEID} and the default format is wav.\n" + " 'q' -- quiet mode (don't play enter/leave sounds)\n" + " 'c' -- announce user(s) count on joining a conference\n" + " 'M' -- enable music on hold when the conference has a single caller\n" + " 'x' -- close the conference when last marked user exits\n" + " 'w' -- wait until the marked user enters the conference\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" + " 's' -- Present menu (user or admin) when '*' is received ('send' to menu)\n" + " 'a' -- set admin mode\n" + " 'A' -- set marked mode\n" + " 'P' -- always prompt for the pin even if it is specified\n"; static char *descrip2 = -" MeetMeCount(confno[|var]): Plays back the number of users in the specifiedi\n" -"MeetMe conference. If var is specified, playback will be skipped and the value\n" -"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 = -" MeetMeAdmin(confno,command[,user]): Run admin command for conference\n" -" 'K' -- Kick all users out of conference\n" -" 'k' -- Kick one user out of conference\n" -" 'e' -- Eject last user that joined\n" -" 'L' -- Lock conference\n" -" 'l' -- Unlock conference\n" -" 'M' -- Mute conference\n" -" 'm' -- Unmute conference\n" -" 'N' -- Mute entire conference (except admin)\n" -" 'n' -- Unmute entire conference (except admin)\n" -""; + " MeetMeCount(confno[|var]): Plays back the number of users in the specifiedi\n" + "MeetMe conference. If var is specified, playback will be skipped and the value\n" + "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 = + " MeetMeAdmin(confno,command[,user]): Run admin command for conference\n" + " 'K' -- Kick all users out of conference\n" + " 'k' -- Kick one user out of conference\n" + " 'e' -- Eject last user that joined\n" + " 'L' -- Lock conference\n" + " 'l' -- Unlock conference\n" + " 'M' -- Mute conference\n" + " 'm' -- Unmute conference\n" + " 'N' -- Mute entire conference (except admin)\n" + " 'n' -- Unmute entire conference (except admin)\n" + ""; STANDARD_LOCAL_USER; @@ -137,6 +137,8 @@ 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 */ + struct ast_conference *conf; + int fd; int userflags; /* Flags as set in the conference */ int adminflags; /* Flags set by the Admin */ struct ast_channel *chan; /* Connected channel */ @@ -144,18 +146,38 @@ char usrvalue[50]; /* Custom User Value */ char namerecloc[AST_MAX_EXTENSION]; /* Name Recorded file Location */ time_t jointime; /* Time the user joined the conference */ + /* User specific variables */ + char exitcontext[AST_MAX_EXTENSION]; + struct zt_confinfo ztc; + struct ast_dsp *dsp; + int using_pseudo; + int menu_active; + int lastmarked; + int currentmarked; + int musiconhold; + char *agifile; }; #define ADMINFLAG_MUTED (1 << 1) /* User is muted */ #define ADMINFLAG_KICKME (1 << 2) /* User is kicked */ #define MEETME_DELAYDETECTTALK 300 #define MEETME_DELAYDETECTENDTALK 1000 - +#define MEETME_DEFAULTAGI "conf-background.agi" AST_MUTEX_DEFINE_STATIC(conflock); static int admin_exec(struct ast_channel *chan, void *data); static void *recordthread(void *args); +int confmenu(struct ast_conf_user *user, struct ast_frame *f); +int verifyuserflags(struct ast_conf_user *user); +int waitmarkedenterleavecheck (struct ast_conf_user *user); +int waitmarkedprompt(struct ast_conf_user *user); +int activateagi(struct ast_conf_user *user); +int processframe(struct ast_conf_user *user, struct ast_frame *f); +void recordconference(struct ast_conf_user *user); +int adduserconference(struct ast_conference *conf, struct ast_conf_user *user); +int announceusercount(struct ast_conf_user *user); +int removeuserconference(struct ast_conference *conf, struct ast_conf_user *user); #include "enter.h" #include "leave.h" @@ -194,28 +216,28 @@ AST_DECLARE_OPTIONS(meetme_opts,{ - ['a'] = { CONFFLAG_ADMIN }, - ['c'] = { CONFFLAG_ANNOUNCEUSERCOUNT }, - ['T'] = { CONFFLAG_MONITORTALKER }, - ['i'] = { CONFFLAG_INTROUSER }, - ['m'] = { CONFFLAG_MONITOR }, - ['p'] = { CONFFLAG_POUNDEXIT }, - ['s'] = { CONFFLAG_STARMENU }, - ['t'] = { CONFFLAG_TALKER }, - ['q'] = { CONFFLAG_QUIET }, - ['M'] = { CONFFLAG_MOH }, - ['x'] = { CONFFLAG_MARKEDEXIT }, - ['X'] = { CONFFLAG_EXIT_CONTEXT }, - ['A'] = { CONFFLAG_MARKEDUSER }, - ['b'] = { CONFFLAG_AGI }, - ['w'] = { CONFFLAG_WAITMARKED }, - ['r'] = { CONFFLAG_RECORDCONF }, - ['d'] = { CONFFLAG_DYNAMIC }, - ['D'] = { CONFFLAG_DYNAMICPIN }, - ['e'] = { CONFFLAG_EMPTY }, - ['E'] = { CONFFLAG_EMPTYNOPIN }, - ['P'] = { CONFFLAG_ALWAYSPROMPT }, -}); + ['a'] = { CONFFLAG_ADMIN }, + ['c'] = { CONFFLAG_ANNOUNCEUSERCOUNT }, + ['T'] = { CONFFLAG_MONITORTALKER }, + ['i'] = { CONFFLAG_INTROUSER }, + ['m'] = { CONFFLAG_MONITOR }, + ['p'] = { CONFFLAG_POUNDEXIT }, + ['s'] = { CONFFLAG_STARMENU }, + ['t'] = { CONFFLAG_TALKER }, + ['q'] = { CONFFLAG_QUIET }, + ['M'] = { CONFFLAG_MOH }, + ['x'] = { CONFFLAG_MARKEDEXIT }, + ['X'] = { CONFFLAG_EXIT_CONTEXT }, + ['A'] = { CONFFLAG_MARKEDUSER }, + ['b'] = { CONFFLAG_AGI }, + ['w'] = { CONFFLAG_WAITMARKED }, + ['r'] = { CONFFLAG_RECORDCONF }, + ['d'] = { CONFFLAG_DYNAMIC }, + ['D'] = { CONFFLAG_DYNAMICPIN }, + ['e'] = { CONFFLAG_EMPTY }, + ['E'] = { CONFFLAG_EMPTYNOPIN }, + ['P'] = { CONFFLAG_ALWAYSPROMPT }, + }); static char *istalking(int x) { @@ -223,7 +245,7 @@ return "(talking)"; else if (x < 0) return "(unmonitored)"; - else + else return "(not talking)"; } @@ -270,10 +292,10 @@ data = NULL; len = 0; } - if (data) + if (data) careful_write(conf->fd, data, len); ast_mutex_unlock(&conflock); - if (!res) + if (!res) ast_autoservice_stop(chan); } @@ -284,7 +306,7 @@ ast_mutex_lock(&conflock); cnf = confs; while(cnf) { - if (!strcmp(confno, cnf->confno)) + if (!strcmp(confno, cnf->confno)) break; cnf = cnf->next; } @@ -336,7 +358,7 @@ ast_verbose(VERBOSE_PREFIX_3 "Created MeetMe conference %d for conference '%s'\n", cnf->zapconf, cnf->confno); cnf->next = confs; confs = cnf; - } else + } else ast_log(LOG_WARNING, "Out of memory\n"); } cnfout: @@ -351,12 +373,12 @@ } static char show_confs_usage[] = -"Deprecated! Please use 'meetme' instead.\n"; + "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 }; - + { "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; @@ -376,18 +398,18 @@ ast_cli(fd, "Invalid Arguments.\n"); } if (argc == 1) { - /* 'MeetMe': List all the conferences */ - now = time(NULL); + /* 'MeetMe': List all the conferences */ + now = time(NULL); cnf = confs; if (!cnf) { - ast_cli(fd, "No active MeetMe conferences.\n"); - return RESULT_SUCCESS; - } - ast_cli(fd, header_format, "Conf Num", "Parties", "Marked", "Activity", "Creation"); + ast_cli(fd, "No active MeetMe conferences.\n"); + return RESULT_SUCCESS; + } + ast_cli(fd, header_format, "Conf Num", "Parties", "Marked", "Activity", "Creation"); while(cnf) { if (cnf->markedusers == 0) strncpy(cmdline, "N/A ", sizeof(cmdline) - 1); - else + else snprintf(cmdline, sizeof(cmdline), "%4.4d", cnf->markedusers); hr = (now - cnf->start) / 3600; min = ((now - cnf->start) % 3600) / 60; @@ -395,7 +417,7 @@ ast_cli(fd, data_format, cnf->confno, cnf->users, cmdline, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static"); - total += cnf->users; + total += cnf->users; cnf = cnf->next; } ast_cli(fd, "* Total number of MeetMe users: %d\n", total); @@ -404,7 +426,7 @@ if (argc < 3) return RESULT_SHOWUSAGE; strncpy(cmdline, argv[2], sizeof(cmdline) - 1); /* Argv 2: conference number */ - if (strstr(argv[1], "lock")) { + if (strstr(argv[1], "lock")) { if (strcmp(argv[1], "lock") == 0) { /* Lock */ strncat(cmdline, "|L", sizeof(cmdline) - strlen(cmdline) - 1); @@ -412,21 +434,21 @@ /* Unlock */ strncat(cmdline, "|l", sizeof(cmdline) - strlen(cmdline) - 1); } - } else if (strstr(argv[1], "mute")) { + } else if (strstr(argv[1], "mute")) { if (argc < 4) return RESULT_SHOWUSAGE; if (strcmp(argv[1], "mute") == 0) { /* Mute */ if (strcmp(argv[3], "all") == 0) { - strncat(cmdline, "|N", sizeof(cmdline) - strlen(cmdline) - 1); + strncat(cmdline, "|N", sizeof(cmdline) - strlen(cmdline) - 1); } else { - strncat(cmdline, "|M|", sizeof(cmdline) - strlen(cmdline) - 1); + strncat(cmdline, "|M|", sizeof(cmdline) - strlen(cmdline) - 1); strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1); } } else { /* Unmute */ if (strcmp(argv[3], "all") == 0) { - strncat(cmdline, "|n", sizeof(cmdline) - strlen(cmdline) - 1); + strncat(cmdline, "|n", sizeof(cmdline) - strlen(cmdline) - 1); } else { strncat(cmdline, "|m|", sizeof(cmdline) - strlen(cmdline) - 1); strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1); @@ -442,12 +464,12 @@ /* Kick a single user */ strncat(cmdline, "|k|", sizeof(cmdline) - strlen(cmdline) - 1); strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1); - } + } } 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; + return RESULT_SUCCESS; } cnf = confs; /* Find the right conference */ @@ -455,7 +477,7 @@ if (strcmp(cnf->confno, argv[2]) == 0) break; if (cnf->next) { - cnf = cnf->next; + cnf = cnf->next; } else { ast_cli(fd, "No such conference: %s.\n",argv[2]); return RESULT_SUCCESS; @@ -469,7 +491,7 @@ } ast_cli(fd,"%d users in that conference.\n",cnf->users); return RESULT_SUCCESS; - } else + } else return RESULT_SHOWUSAGE; ast_log(LOG_DEBUG, "Cmdline: %s\n", cmdline); admin_exec(NULL, cmdline); @@ -485,7 +507,7 @@ 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++) { @@ -524,7 +546,7 @@ while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0)) ; } - + while(cnf) { if (strcmp(confno, cnf->confno) == 0) { break; @@ -549,14 +571,14 @@ } return NULL; } - + static char conf_usage[] = -"Usage: meetme (un)lock|(un)mute|kick|list \n" -" Executes a command for the conference or on a conferee\n"; + "Usage: meetme (un)lock|(un)mute|kick|list \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 }; + { "meetme", NULL, NULL }, conf_cmd, + "Execute a command on a conference or conferee", conf_usage, complete_confcmd }; static void conf_flush(int fd) { @@ -566,13 +588,154 @@ ast_log(LOG_WARNING, "Error flushing channel\n"); } +void recordconference(struct ast_conf_user *user) { + char recordingtmp[AST_MAX_EXTENSION] = ""; + + user->conf->recordingfilename = pbx_builtin_getvar_helper(user->chan,"MEETME_RECORDINGFILE"); + + if (!user->conf->recordingfilename) { + snprintf(recordingtmp,sizeof(recordingtmp),"meetme-conf-rec-%s-%s",user->conf->confno,user->chan->uniqueid); + user->conf->recordingfilename = ast_strdupa(recordingtmp); + } + user->conf->recordingformat = pbx_builtin_getvar_helper(user->chan, "MEETME_RECORDINGFORMAT"); + if (!user->conf->recordingformat) { + snprintf(recordingtmp,sizeof(recordingtmp), "wav"); + user->conf->recordingformat = ast_strdupa(recordingtmp); + } + pthread_attr_init(&user->conf->attr); + pthread_attr_setdetachstate(&user->conf->attr, PTHREAD_CREATE_DETACHED); + ast_verbose(VERBOSE_PREFIX_4 "Starting recording of MeetMe Conference %s into file %s.%s.\n", user->conf->confno, user->conf->recordingfilename, user->conf->recordingformat); + ast_pthread_create(&user->conf->recordthread, &user->conf->attr, recordthread, user->conf); +} + +int removeuserconference(struct ast_conference *conf, struct ast_conf_user *user) { + struct ast_conference *prev=NULL, *cur; + + conf->users--; + if (user->userflags & CONFFLAG_MARKEDUSER) + conf->markedusers--; + cur = confs; + if (!conf->users) { + /* No more users -- close this one out */ + while(cur) { + if (cur == conf) { + if (prev) + prev->next = conf->next; + else + confs = conf->next; + break; + } + prev = cur; + cur = cur->next; + } + if (!cur) + ast_log(LOG_WARNING, "Conference not found\n"); + if (conf->chan) + ast_hangup(conf->chan); + else + close(conf->fd); + free(conf); + } else { + /* Remove the user struct */ + if (user == conf->firstuser) { + if (user->nextuser) { + /* There is another entry */ + user->nextuser->prevuser = NULL; + } else { + /* We are the only entry */ + conf->lastuser = NULL; + } + /* In either case */ + conf->firstuser = user->nextuser; + } else if (user == conf->lastuser){ + if (user->prevuser) + user->prevuser->nextuser = NULL; + else + ast_log(LOG_ERROR, "Bad bad bad! We're the last, not the first, but nobody before us??\n"); + conf->lastuser = user->prevuser; + } else { + if (user->nextuser) + user->nextuser->prevuser = user->prevuser; + else + ast_log(LOG_ERROR, "Bad! Bad! Bad! user->nextuser is NULL but we're not the end!\n"); + if (user->prevuser) + user->prevuser->nextuser = user->nextuser; + else + ast_log(LOG_ERROR, "Bad! Bad! Bad! user->prevuser is NULL but we're not the beginning!\n"); + } + } + return 0; +} +int adduserconference(struct ast_conference *conf, struct ast_conf_user *user) { + 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"); + ast_mutex_unlock(&conflock); + return -1; + + } else { + conf->lastuser->nextuser = user; + conf->lastuser = user; + } + } + ast_mutex_unlock(&conflock); + return 0; +} + +int announceusercount(struct ast_conf_user *user) { + + int keepplaying=1; + int res; + + if (user->conf->users == 2) { + if (!ast_streamfile(user->chan,"conf-onlyone",user->chan->language)) { + res = ast_waitstream(user->chan, AST_DIGIT_ANY); + if (res > 0) + keepplaying=0; + else if (res == -1) + return -1; + } + } else { + if (!ast_streamfile(user->chan, "conf-thereare", user->chan->language)) { + res = ast_waitstream(user->chan, AST_DIGIT_ANY); + if (res > 0) + keepplaying=0; + else if (res == -1) + return -1; + } + if (keepplaying) { + res = ast_say_number(user->chan, user->conf->users - 1, AST_DIGIT_ANY, user->chan->language, (char *) NULL); + if (res > 0) + keepplaying=0; + else if (res == -1) + return -1; + } + if (keepplaying && !ast_streamfile(user->chan, "conf-otherinparty", user->chan->language)) { + res = ast_waitstream(user->chan, AST_DIGIT_ANY); + if (res > 0) + keepplaying=0; + else if (res == -1) + return -1; + } + } + return 0; +} + 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)); - struct ast_conf_user *usr = NULL; - int fd; - struct zt_confinfo ztc; struct ast_frame *f; struct ast_channel *c; struct ast_frame fr; @@ -583,152 +746,90 @@ int flags; int retryzap; int origfd; - int musiconhold = 0; - int firstpass = 0; - int origquiet; - int lastmarked = 0; - int currentmarked = 0; int ret = -1; int x; - int menu_active = 0; - int using_pseudo = 0; + int tmpret; int duration=20; - struct ast_dsp *dsp=NULL; - struct ast_app *app; - char *agifile; - char *agifiledefault = "conf-background.agi"; char meetmesecs[30] = ""; - char exitcontext[AST_MAX_EXTENSION] = ""; - char recordingtmp[AST_MAX_EXTENSION] = ""; - int dtmf; ZT_BUFFERINFO bi; char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET]; char *buf = __buf + AST_FRIENDLY_OFFSET; - + if (!user) { ast_log(LOG_ERROR, "Out of memory\n"); return(ret); } memset(user, 0, sizeof(struct ast_conf_user)); - - if (confflags & CONFFLAG_RECORDCONF && conf->recording !=MEETME_RECORD_ACTIVE) { - conf->recordingfilename = pbx_builtin_getvar_helper(chan,"MEETME_RECORDINGFILE"); - if (!conf->recordingfilename) { - snprintf(recordingtmp,sizeof(recordingtmp),"meetme-conf-rec-%s-%s",conf->confno,chan->uniqueid); - conf->recordingfilename = ast_strdupa(recordingtmp); - } - conf->recordingformat = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"); - if (!conf->recordingformat) { - snprintf(recordingtmp,sizeof(recordingtmp), "wav"); - conf->recordingformat = ast_strdupa(recordingtmp); - } - pthread_attr_init(&conf->attr); - pthread_attr_setdetachstate(&conf->attr, PTHREAD_CREATE_DETACHED); - ast_verbose(VERBOSE_PREFIX_4 "Starting recording of MeetMe Conference %s into file %s.%s.\n", conf->confno, conf->recordingfilename, conf->recordingformat); - ast_pthread_create(&conf->recordthread, &conf->attr, recordthread, conf); - } - + ast_mutex_lock(&conflock); user->user_no = 0; /* User number 0 means starting up user! (dead - not in the list!) */ - + user->using_pseudo = 0; + user->menu_active = 0; + user->lastmarked = 0 ; + user-> currentmarked = 0; + user->musiconhold = 0; + user->chan = chan; + user->conf = conf; + user->adminflags = 0; + user->talking = -1; + user->fd = -1; time(&user->jointime); + user->userflags = confflags; + ast_mutex_unlock(&conflock); if (conf->locked) { - /* Sorry, but this confernce is locked! */ + /* Sorry, but this confernce is locked! */ if (!ast_streamfile(chan, "conf-locked", chan->language)) ast_waitstream(chan, ""); goto outrun; } + if (confflags & CONFFLAG_RECORDCONF && conf->recording != MEETME_RECORD_ACTIVE) { + recordconference(user); + } + ast_mutex_lock(&conflock); conf->users++; - if (confflags & CONFFLAG_MARKEDUSER) + tmpret = adduserconference(conf,user); + if (user->userflags & CONFFLAG_MARKEDUSER) 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"); - ast_mutex_unlock(&conflock); - goto outrun; - } else { - conf->lastuser->nextuser = user; - conf->lastuser = user; - } + + if (tmpret == -1) { + ast_mutex_unlock(&conflock); + goto outrun; } - user->chan = chan; - user->userflags = confflags; - user->adminflags = 0; - user->talking = -1; ast_mutex_unlock(&conflock); - origquiet = confflags & CONFFLAG_QUIET; - if (confflags & CONFFLAG_EXIT_CONTEXT) { - if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) - strncpy(exitcontext, agifile, sizeof(exitcontext) - 1); - else if (!ast_strlen_zero(chan->macrocontext)) - strncpy(exitcontext, chan->macrocontext, sizeof(exitcontext) - 1); + + /* prepare the exit context variable */ + if (user->userflags & CONFFLAG_EXIT_CONTEXT) { + if ((user->agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) + strncpy(user->exitcontext, user->agifile, sizeof(user->exitcontext) - 1); + else if (!ast_strlen_zero(chan->macrocontext)) + strncpy(user->exitcontext, chan->macrocontext, sizeof(user->exitcontext) - 1); else - strncpy(exitcontext, chan->context, sizeof(exitcontext) - 1); + strncpy(user->exitcontext, chan->context, sizeof(user->exitcontext) - 1); } - if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_INTROUSER)) { + /* record the person name */ + if (!(user->userflags & CONFFLAG_QUIET) && (user->userflags & CONFFLAG_INTROUSER)) { snprintf(user->namerecloc,sizeof(user->namerecloc),"%s/meetme/meetme-username-%s-%d",ast_config_AST_SPOOL_DIR,conf->confno,user->user_no); ast_record_review(chan,"vm-rec-name",user->namerecloc, 10,"sln", &duration, NULL); } - if (!(confflags & CONFFLAG_QUIET)) { - if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED)) + /* If your alone in the conference, it play it back */ + if (!(user->userflags & CONFFLAG_QUIET)) { + if (conf->users == 1 && !(user->userflags & CONFFLAG_WAITMARKED)) if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) ast_waitstream(chan, ""); - if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0) + if ((user->userflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0) if (!ast_streamfile(chan, "conf-waitforleader", chan->language)) ast_waitstream(chan, ""); } - - if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) { - int keepplaying=1; - - if (conf->users == 2) { - if (!ast_streamfile(chan,"conf-onlyone",chan->language)) { - res = ast_waitstream(chan, AST_DIGIT_ANY); - if (res > 0) - keepplaying=0; - else if (res == -1) - goto outrun; - } - } else { - if (!ast_streamfile(chan, "conf-thereare", chan->language)) { - res = ast_waitstream(chan, AST_DIGIT_ANY); - if (res > 0) - keepplaying=0; - else if (res == -1) - goto outrun; - } - if (keepplaying) { - res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL); - if (res > 0) - keepplaying=0; - else if (res == -1) - goto outrun; - } - if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) { - res = ast_waitstream(chan, AST_DIGIT_ANY); - if (res > 0) - keepplaying=0; - else if (res == -1) - goto outrun; - } + /* announce the number of people in the conference */ + if (!(user->userflags & CONFFLAG_QUIET) && (user->userflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) { + tmpret = announceusercount(user); + if (tmpret == -1) { + goto outrun; } } @@ -748,22 +849,22 @@ zapretry: origfd = chan->fds[0]; if (retryzap) { - fd = open("/dev/zap/pseudo", O_RDWR); - if (fd < 0) { + user->fd = open("/dev/zap/pseudo", O_RDWR); + if (user->fd < 0) { ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno)); goto outrun; } - using_pseudo = 1; + user->using_pseudo = 1; /* Make non-blocking */ - flags = fcntl(fd, F_GETFL); + flags = fcntl(user->fd, F_GETFL); if (flags < 0) { ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno)); - close(fd); + close(user->fd); goto outrun; } - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { + if (fcntl(user->fd, F_SETFL, flags | O_NONBLOCK)) { ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno)); - close(fd); + close(user->fd); goto outrun; } /* Setup buffering information */ @@ -772,32 +873,32 @@ bi.txbufpolicy = ZT_POLICY_IMMEDIATE; bi.rxbufpolicy = ZT_POLICY_IMMEDIATE; bi.numbufs = 4; - if (ioctl(fd, ZT_SET_BUFINFO, &bi)) { + if (ioctl(user->fd, ZT_SET_BUFINFO, &bi)) { ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno)); - close(fd); + close(user->fd); goto outrun; } x = 1; - if (ioctl(fd, ZT_SETLINEAR, &x)) { + if (ioctl(user->fd, ZT_SETLINEAR, &x)) { ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno)); - close(fd); + close(user->fd); goto outrun; } nfds = 1; } else { /* XXX Make sure we're not running on a pseudo channel XXX */ - fd = chan->fds[0]; + user->fd = chan->fds[0]; nfds = 0; } - memset(&ztc, 0, sizeof(ztc)); + memset(&user->ztc, 0, sizeof(user->ztc)); /* Check to see if we're in a conference... */ - ztc.chan = 0; - if (ioctl(fd, ZT_GETCONF, &ztc)) { + user->ztc.chan = 0; + if (ioctl(user->fd, ZT_GETCONF, &user->ztc)) { ast_log(LOG_WARNING, "Error getting conference\n"); - close(fd); + close(user->fd); goto outrun; } - if (ztc.confmode) { + if (user->ztc.confmode) { /* Whoa, already in a conference... Retry... */ if (!retryzap) { ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n"); @@ -805,12 +906,14 @@ goto zapretry; } } - memset(&ztc, 0, sizeof(ztc)); + memset(&user->ztc, 0, sizeof(user->ztc)); /* Add us to the conference */ - ztc.chan = 0; - ztc.confno = conf->zapconf; + user->ztc.chan = 0; + user->ztc.confno = conf->zapconf; ast_mutex_lock(&conflock); - if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_INTROUSER) && conf->users > 1) { + + /* playback the previoustly recorded name */ + if (!(user->userflags & CONFFLAG_QUIET) && (user->userflags & CONFFLAG_INTROUSER) && conf->users > 1) { if (conf->chan && ast_fileexists(user->namerecloc, NULL, NULL)) { if (!ast_streamfile(conf->chan, user->namerecloc, chan->language)) ast_waitstream(conf->chan, ""); @@ -819,399 +922,123 @@ } } - if (confflags & CONFFLAG_MONITOR) - ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER; - else if (confflags & CONFFLAG_TALKER) - ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER; - else - ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; + if (user->userflags & CONFFLAG_MONITOR) + user->ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER; + else if (user->userflags & CONFFLAG_TALKER) + user->ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER; + else + user->ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; - if (ioctl(fd, ZT_SETCONF, &ztc)) { + if (ioctl(user->fd, ZT_SETCONF, &user->ztc)) { ast_log(LOG_WARNING, "Error setting conference\n"); - close(fd); + close(user->fd); ast_mutex_unlock(&conflock); goto outrun; } ast_log(LOG_DEBUG, "Placed channel %s in ZAP conf %d\n", chan->name, conf->zapconf); - manager_event(EVENT_FLAG_CALL, "MeetmeJoin", - "Channel: %s\r\n" - "Uniqueid: %s\r\n" - "Meetme: %s\r\n" - "Usernum: %i\r\n", - chan->name, chan->uniqueid, conf->confno, user->user_no); - - if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) { - firstpass = 1; - if (!(confflags & CONFFLAG_QUIET)) - if (!(confflags & CONFFLAG_WAITMARKED) || (conf->markedusers >= 1)) + manager_event(EVENT_FLAG_CALL, "MeetmeJoin", + "Channel: %s\r\n" + "Uniqueid: %s\r\n" + "Meetme: %s\r\n" + "Usernum: %i\r\n", + chan->name, chan->uniqueid, conf->confno, user->user_no); + + /* Play the Enter to everyone */ + if (!(user->userflags & CONFFLAG_MONITOR) && !(user->userflags & CONFFLAG_ADMIN)) { + if (!(user->userflags & CONFFLAG_QUIET)) + if (!(user->userflags & CONFFLAG_WAITMARKED) || (conf->markedusers >= 1)) conf_play(chan, conf, ENTER); } - conf_flush(fd); - ast_mutex_unlock(&conflock); - if (confflags & CONFFLAG_AGI) { - /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND) - or use default filename of conf-background.agi */ + conf_flush(user->fd); - agifile = pbx_builtin_getvar_helper(chan,"MEETME_AGI_BACKGROUND"); - if (!agifile) - agifile = agifiledefault; + ast_mutex_unlock(&conflock); - if (!strcasecmp(chan->type,"Zap")) { - /* Set CONFMUTE mode on Zap channel to mute DTMF tones */ - x = 1; - ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0); - } - /* Find a pointer to the agi app and execute the script */ - app = pbx_findapp("agi"); - if (app) { - ret = pbx_exec(chan, app, agifile, 1); - } else { - ast_log(LOG_WARNING, "Could not find application (agi)\n"); - ret = -2; - } - if (!strcasecmp(chan->type,"Zap")) { - /* Remove CONFMUTE mode on Zap channel */ - x = 0; - ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0); - } + if (user->userflags & CONFFLAG_AGI) { + ret = activateagi(user); } else { - if (!strcasecmp(chan->type,"Zap") && (confflags & CONFFLAG_STARMENU)) { + if (!strcasecmp(chan->type,"Zap") && (user->userflags & 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); - } - if (confflags & CONFFLAG_MONITORTALKER && !(dsp = ast_dsp_new())) { + } + if (user->userflags & CONFFLAG_MONITORTALKER && !(user->dsp = ast_dsp_new())) { ast_log(LOG_WARNING, "Unable to allocate DSP!\n"); res = -1; } + /* Here start the actual conference user loop */ for(;;) { outfd = -1; ms = -1; - currentmarked = conf->markedusers; - if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_MARKEDUSER) && (confflags & CONFFLAG_WAITMARKED) && lastmarked == 0) { - if (currentmarked == 1 && conf->users > 1) { - ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL); - if (conf->users - 1 == 1) { - if (!ast_streamfile(chan, "conf-userwilljoin", chan->language)) - ast_waitstream(chan, ""); - } else { - if (!ast_streamfile(chan, "conf-userswilljoin", chan->language)) - ast_waitstream(chan, ""); - } - } - if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER)) - if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) - ast_waitstream(chan, ""); - } + user->currentmarked = conf->markedusers; - c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms); - - /* Update the struct with the actual confflags */ - user->userflags = confflags; - - if (confflags & CONFFLAG_WAITMARKED) { - if(currentmarked == 0) { - if (lastmarked != 0) { - if (!(confflags & CONFFLAG_QUIET)) - if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language)) - ast_waitstream(chan, ""); - if(confflags & CONFFLAG_MARKEDEXIT) - break; - else { - ztc.confmode = ZT_CONF_CONF; - if (ioctl(fd, ZT_SETCONF, &ztc)) { - ast_log(LOG_WARNING, "Error setting conference\n"); - close(fd); - goto outrun; - } - } - } - if (musiconhold == 0 && (confflags & CONFFLAG_MOH)) { - ast_moh_start(chan, NULL); - musiconhold = 1; - } else { - ztc.confmode = ZT_CONF_CONF; - if (ioctl(fd, ZT_SETCONF, &ztc)) { - ast_log(LOG_WARNING, "Error setting conference\n"); - close(fd); - goto outrun; - } - } - } else if(currentmarked >= 1 && lastmarked == 0) { - if (confflags & CONFFLAG_MONITOR) - ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER; - else if (confflags & CONFFLAG_TALKER) - ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER; - else - ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; - if (ioctl(fd, ZT_SETCONF, &ztc)) { - ast_log(LOG_WARNING, "Error setting conference\n"); - close(fd); - goto outrun; - } - if (musiconhold && (confflags & CONFFLAG_MOH)) { - ast_moh_stop(chan); - musiconhold = 0; - } - if ( !(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) { - if (!ast_streamfile(chan, "conf-placeintoconf", chan->language)) - ast_waitstream(chan, ""); - conf_play(chan, conf, ENTER); - } - } - } + waitmarkedprompt(user); + c = ast_waitfor_nandfds(&chan, 1, &user->fd, nfds, NULL, &outfd, &ms); + + tmpret = waitmarkedenterleavecheck(user); + //tmpret = 0; + if (tmpret == 1) { + ret = 0; + break; + } else if (tmpret == 2) { + ret = -1; + break; + } else if (tmpret == -2) { + goto outrun; + } /* trying to add moh for single person conf */ - if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) { + if ((user->userflags & CONFFLAG_MOH) && !(user->userflags & CONFFLAG_WAITMARKED)) { if (conf->users == 1) { - if (musiconhold == 0) { + if (user->musiconhold == 0) { ast_moh_start(chan, NULL); - musiconhold = 1; - } + user->musiconhold = 1; + } } else { - if (musiconhold) { + if (user->musiconhold) { ast_moh_stop(chan); - musiconhold = 0; + user->musiconhold = 0; } } } - - /* Leave if the last marked user left */ - if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) { + + tmpret = verifyuserflags(user); + //tmpret = 0; + if (tmpret == 1) { + ret = 0; + break; + } else if (tmpret == 2) { ret = -1; break; + } else if (tmpret == -2) { + goto outrun; } - - /* 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) { - if (using_pseudo) { + if (user->using_pseudo) { /* Kill old pseudo */ - close(fd); + close(user->fd); } ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n"); retryzap = 0; - using_pseudo = 0; + user->using_pseudo = 0; goto zapretry; } f = ast_read(c); - if (!f) + if (!f) { break; - if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) { - if (confflags & CONFFLAG_MONITORTALKER) { - int totalsilence; - if (user->talking == -1) - user->talking = 0; - - res = ast_dsp_silence(dsp, f, &totalsilence); - if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) { - user->talking = 1; - manager_event(EVENT_FLAG_CALL, "MeetmeTalking", - "Channel: %s\r\n" - "Uniqueid: %s\r\n" - "Meetme: %s\r\n" - "Usernum: %i\r\n", - chan->name, chan->uniqueid, conf->confno, user->user_no); - } - if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) { - user->talking = 0; - manager_event(EVENT_FLAG_CALL, "MeetmeStopTalking", - "Channel: %s\r\n" - "Uniqueid: %s\r\n" - "Meetme: %s\r\n" - "Usernum: %i\r\n", - chan->name, chan->uniqueid, conf->confno, user->user_no); - } - } - if (using_pseudo) { - /* Carefully write */ - careful_write(fd, f->data, f->datalen); - } - } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) { - char tmp[2]; - tmp[0] = f->subclass; - tmp[1] = '\0'; - if (ast_exists_extension(chan, exitcontext, tmp, 1, chan->cid.cid_num)) { - strncpy(chan->context, exitcontext, sizeof(chan->context) - 1); - strncpy(chan->exten, tmp, sizeof(chan->exten) - 1); - chan->priority = 0; + } else { + tmpret = processframe(user,f); + if (tmpret == 1) { ret = 0; break; - } - } else 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)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) { - int oldconfmode = 0; - oldconfmode = ztc.confmode; - ztc.confmode = 0; - if (ioctl(fd, ZT_SETCONF, &ztc)) { - ast_log(LOG_WARNING, "Error setting conference\n"); - close(fd); - ast_mutex_unlock(&conflock); - goto outrun; - } - if (musiconhold) { - ast_moh_stop(chan); - } - if ((confflags & CONFFLAG_ADMIN)) { - /* Admin menu */ - if (!menu_active) { - menu_active = 1; - /* Record this sound! */ - if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) - dtmf = ast_waitstream(chan, AST_DIGIT_ANY); - else - dtmf = 0; - } else - dtmf = f->subclass; - if (dtmf) { - switch(dtmf) { - 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; - case '3': /* Eject last user */ - menu_active = 0; - usr = conf->lastuser; - if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) { - if(!ast_streamfile(chan, "conf-errormenu", chan->language)) - ast_waitstream(chan, ""); - } else - usr->adminflags |= ADMINFLAG_KICKME; - ast_stopstream(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)) - dtmf = ast_waitstream(chan, AST_DIGIT_ANY); - else - dtmf = 0; - } else - dtmf = f->subclass; - if (dtmf) { - switch(dtmf) { - 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, "conf-errormenu", chan->language)) - ast_waitstream(chan, ""); - break; - } - } - } - if (musiconhold) { - ast_moh_start(chan, NULL); - } - ztc.confmode = oldconfmode; - if (ioctl(fd, ZT_SETCONF, &ztc)) { - ast_log(LOG_WARNING, "Error setting conference\n"); - close(fd); - ast_mutex_unlock(&conflock); + } else if (tmpret == 2) { + ret = -1; + break; + } else if (tmpret == -2) { goto outrun; } - conf_flush(fd); - } else if (option_debug) { - ast_log(LOG_DEBUG, "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",chan->name,f->frametype,f->subclass); } ast_frfree(f); } else if (outfd > -1) { @@ -1228,30 +1055,31 @@ ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno)); /* break; */ } - } else + } else ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno)); } - lastmarked = currentmarked; + user->lastmarked = user->currentmarked; } } - if (using_pseudo) - close(fd); + if (user->using_pseudo) + close(user->fd); else { /* Take out of conference */ /* Add us to the conference */ - ztc.chan = 0; - ztc.confno = 0; - ztc.confmode = 0; - if (ioctl(fd, ZT_SETCONF, &ztc)) { + user->ztc.chan = 0; + user->ztc.confno = 0; + user->ztc.confmode = 0; + if (ioctl(user->fd, ZT_SETCONF, &user->ztc)) { ast_log(LOG_WARNING, "Error setting conference\n"); } } ast_mutex_lock(&conflock); - if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) + if (!(user->userflags & CONFFLAG_QUIET) && !(user->userflags & CONFFLAG_MONITOR) && !(user->userflags & CONFFLAG_ADMIN)) conf_play(chan, conf, LEAVE); - if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_INTROUSER)) { + /* Playback if the username if user leave the conference */ + if (!(user->userflags & CONFFLAG_QUIET) && (user->userflags & CONFFLAG_INTROUSER)) { if (ast_fileexists(user->namerecloc, NULL, NULL)) { if ((conf->chan) && (conf->users > 1)) { if (!ast_streamfile(conf->chan, user->namerecloc, chan->language)) @@ -1267,80 +1095,30 @@ outrun: ast_mutex_lock(&conflock); - if (confflags & CONFFLAG_MONITORTALKER && dsp) - ast_dsp_free(dsp); - + /* if DSP is active, free it */ + if (user->userflags & CONFFLAG_MONITORTALKER && user->dsp) + ast_dsp_free(user->dsp); + + /* if user havent joined yet, then dont clean it up */ 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" - "Usernum: %i\r\n", - chan->name, chan->uniqueid, conf->confno, user->user_no); - prev = NULL; - conf->users--; - if (confflags & CONFFLAG_MARKEDUSER) - conf->markedusers--; - cur = confs; - if (!conf->users) { - /* No more users -- close this one out */ - while(cur) { - if (cur == conf) { - if (prev) - prev->next = conf->next; - else - confs = conf->next; + manager_event(EVENT_FLAG_CALL, "MeetmeLeave", + "Channel: %s\r\n" + "Uniqueid: %s\r\n" + "Meetme: %s\r\n" + "Usernum: %i\r\n", + chan->name, chan->uniqueid, conf->confno, user->user_no); + if (!conf->users && conf->recording == MEETME_RECORD_ACTIVE) { + conf->recording = MEETME_RECORD_TERMINATE; + ast_mutex_unlock(&conflock); + while (1) { + ast_mutex_lock(&conflock); + if (conf->recording == MEETME_RECORD_OFF) break; - } - prev = cur; - cur = cur->next; - } - if (!cur) - ast_log(LOG_WARNING, "Conference not found\n"); - if (conf->recording == MEETME_RECORD_ACTIVE) { - conf->recording = MEETME_RECORD_TERMINATE; ast_mutex_unlock(&conflock); - while (1) { - ast_mutex_lock(&conflock); - if (conf->recording == MEETME_RECORD_OFF) - break; - ast_mutex_unlock(&conflock); - } - } - if (conf->chan) - ast_hangup(conf->chan); - else - close(conf->fd); - free(conf); - } else { - /* Remove the user struct */ - if (user == conf->firstuser) { - if (user->nextuser) { - /* There is another entry */ - user->nextuser->prevuser = NULL; - } else { - /* We are the only entry */ - conf->lastuser = NULL; - } - /* In either case */ - conf->firstuser = user->nextuser; - } else if (user == conf->lastuser){ - if (user->prevuser) - user->prevuser->nextuser = NULL; - else - ast_log(LOG_ERROR, "Bad bad bad! We're the last, not the first, but nobody before us??\n"); - conf->lastuser = user->prevuser; - } else { - if (user->nextuser) - user->nextuser->prevuser = user->prevuser; - else - ast_log(LOG_ERROR, "Bad! Bad! Bad! user->nextuser is NULL but we're not the end!\n"); - if (user->prevuser) - user->prevuser->nextuser = user->nextuser; - else - ast_log(LOG_ERROR, "Bad! Bad! Bad! user->prevuser is NULL but we're not the beginning!\n"); } } + removeuserconference(conf,user); + /* Return the number of seconds the user was in the conf */ snprintf(meetmesecs, sizeof(meetmesecs), "%i", (int) (time(NULL) - user->jointime)); pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs); @@ -1360,7 +1138,7 @@ ast_mutex_lock(&conflock); cnf = confs; while (cnf) { - if (!strcmp(confno, cnf->confno)) + if (!strcmp(confno, cnf->confno)) break; cnf = cnf->next; } @@ -1436,7 +1214,7 @@ struct ast_conference *conf; int count; char *confnum, *localdata; - char val[80] = "0"; + char val[80] = "0"; if (!data || ast_strlen_zero(data)) { ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n"); @@ -1444,7 +1222,7 @@ } localdata = ast_strdupa(data); LOCAL_USER_ADD(u); - confnum = strsep(&localdata,"|"); + confnum = strsep(&localdata,"|"); conf = find_conf(chan, confnum, 0, 0, NULL); if (conf) count = conf->users; @@ -1573,10 +1351,10 @@ if (!found) { /* At this point, we have a confno_tmp (static conference) that is empty */ if ((empty_no_pin && ((!stringp) || (stringp && (stringp[0] == '\0')))) || (!empty_no_pin)) { - /* Case 1: empty_no_pin and pin is nonexistant (NULL) - * Case 2: empty_no_pin and pin is blank (but not NULL) - * Case 3: not empty_no_pin - */ + /* Case 1: empty_no_pin and pin is nonexistant (NULL) + * Case 2: empty_no_pin and pin is blank (but not NULL) + * Case 3: not empty_no_pin + */ strncpy(confno, confno_tmp, sizeof(confno) - 1); break; /* XXX the map is not complete (but we do have a confno) */ @@ -1658,7 +1436,7 @@ /* Pin correct */ allowretry = 0; - if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) + if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) ast_set_flag(&confflags, CONFFLAG_ADMIN); /* Run the conference */ res = conf_run(chan, cnf, confflags.flags); @@ -1726,12 +1504,12 @@ ast_mutex_lock(&conflock); /* The param has the conference number the user and the command to execute */ - if (data && !ast_strlen_zero(data)) { + if (data && !ast_strlen_zero(data)) { params = ast_strdupa((char *) data); conf = strsep(¶ms, "|"); command = strsep(¶ms, "|"); caller = strsep(¶ms, "|"); - + if (!command) { ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n"); ast_mutex_unlock(&conflock); @@ -1739,87 +1517,87 @@ } cnf = confs; while (cnf) { - if (strcmp(cnf->confno, conf) == 0) + if (strcmp(cnf->confno, conf) == 0) break; cnf = cnf->next; } - + 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 101: /* e: Eject last user*/ - user = cnf->lastuser; - if (!(user->userflags & CONFFLAG_ADMIN)) { - user->adminflags |= ADMINFLAG_KICKME; + 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; - } else - ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n"); + } + } + break; + case 101: /* e: Eject last user*/ + user = cnf->lastuser; + if (!(user->userflags & CONFFLAG_ADMIN)) { + user->adminflags |= ADMINFLAG_KICKME; break; - case 77: /* M: Mute */ - if (user) { + } else + ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n"); + break; + case 77: /* M: Mute */ + if (user) { + user->adminflags |= ADMINFLAG_MUTED; + } else { + ast_log(LOG_NOTICE, "Specified User not found!\n"); + } + break; + case 78: /* N: Mute all users */ + user = cnf->firstuser; + while(user) { + if (user && !(user->userflags & CONFFLAG_ADMIN)) user->adminflags |= ADMINFLAG_MUTED; + if (user->nextuser) { + user = user->nextuser; } else { - ast_log(LOG_NOTICE, "Specified User not found!\n"); - } - break; - case 78: /* N: Mute all users */ - user = cnf->firstuser; - while(user) { - if (user && !(user->userflags & CONFFLAG_ADMIN)) - user->adminflags |= ADMINFLAG_MUTED; - if (user->nextuser) { - user = user->nextuser; - } else { - break; - } + break; } - break; - case 109: /* m: Unmute */ - if (user && (user->adminflags & ADMINFLAG_MUTED)) { + } + 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 110: /* n: Unmute all users */ + user = cnf->firstuser; + while(user) { + 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 110: /* n: Unmute all users */ - user = cnf->firstuser; - while(user) { - if (user && (user-> adminflags & ADMINFLAG_MUTED)) { - user->adminflags ^= ADMINFLAG_MUTED; - } - if (user->nextuser) { - user = user->nextuser; - } else { - break; - } - } - break; - case 107: /* k: Kick user */ - if (user) { - user->adminflags |= ADMINFLAG_KICKME; + if (user->nextuser) { + user = user->nextuser; } else { - ast_log(LOG_NOTICE, "Specified User not found!"); + break; } - break; + } + 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"); @@ -1855,7 +1633,7 @@ } if (f->frametype == AST_FRAME_VOICE) { res = ast_writestream(s, f); - if (res) + if (res) break; } ast_frfree(f); @@ -1871,6 +1649,344 @@ pthread_exit(0); } +int waitmarkedprompt(struct ast_conf_user *user) { + int ret = 0; + + if (!(user->userflags & CONFFLAG_QUIET) && (user->userflags & CONFFLAG_MARKEDUSER) && (user->userflags & CONFFLAG_WAITMARKED) && user->lastmarked == 0) { + if (user->currentmarked == 1 && user->conf->users > 1) { + ast_say_number(user->chan, user->conf->users - 1, AST_DIGIT_ANY, user->chan->language, (char *) NULL); + if (user->conf->users - 1 == 1) { + if (!ast_streamfile(user->chan, "conf-userwilljoin", user->chan->language)) + ast_waitstream(user->chan, ""); + } else { + if (!ast_streamfile(user->chan, "conf-userswilljoin", user->chan->language)) + ast_waitstream(user->chan, ""); + } + } + if (user->conf->users == 1 && ! (user->userflags & CONFFLAG_MARKEDUSER)) + if (!ast_streamfile(user->chan, "conf-onlyperson", user->chan->language)) + ast_waitstream(user->chan, ""); + } + return ret; + /* waitmarkedprompt -- End */ +} +int waitmarkedenterleavecheck (struct ast_conf_user *user) { + int ret = 0; + /* waitmarkedenterleavecheck -- Does the management of incoming/outgoing of waitmarked */ + if (user->userflags & CONFFLAG_WAITMARKED) { + if(user->currentmarked == 0) { + if (user->lastmarked != 0) { + if (!(user->userflags & CONFFLAG_QUIET)) + if (!ast_streamfile(user->chan, "conf-leaderhasleft", user->chan->language)) + ast_waitstream(user->chan, ""); + if(user->userflags & CONFFLAG_MARKEDEXIT) + return 1; + else { + user->ztc.confmode = ZT_CONF_CONF; + if (ioctl(user->fd, ZT_SETCONF, &user->ztc)) { + ast_log(LOG_WARNING, "Error setting conference\n"); + close(user->fd); + return -2; + } + } + } + if (user->musiconhold == 0 && (user->userflags & CONFFLAG_MOH)) { + ast_moh_start(user->chan, NULL); + user->musiconhold = 1; + } else { + user->ztc.confmode = ZT_CONF_CONF; + if (ioctl(user->fd, ZT_SETCONF, &user->ztc)) { + ast_log(LOG_WARNING, "Error setting conference\n"); + close(user->fd); + return -2; + } + } + } else if(user->currentmarked >= 1 && user->lastmarked == 0) { + if (user->userflags & CONFFLAG_MONITOR) + user->ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER; + else if (user->userflags & CONFFLAG_TALKER) + user->ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER; + else + user->ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; + if (ioctl(user->fd, ZT_SETCONF, &user->ztc)) { + ast_log(LOG_WARNING, "Error setting conference\n"); + close(user->fd); + return -2; + } + if (user->musiconhold && (user->userflags & CONFFLAG_MOH)) { + ast_moh_stop(user->chan); + user->musiconhold = 0; + } + if ( !(user->userflags & CONFFLAG_QUIET) && !(user->userflags & CONFFLAG_MARKEDUSER)) { + if (!ast_streamfile(user->chan, "conf-placeintoconf", user->chan->language)) + ast_waitstream(user->chan, ""); + conf_play(user->chan, user->conf, ENTER); + } + } + } + return ret; +} + +int verifyuserflags(struct ast_conf_user *user) { + int ret = 0; + + /* verifyuserflags -- Check if the admin changed my modes */ + if (user->adminflags) { + /* Set the new modes */ + if ((user->adminflags & ADMINFLAG_MUTED) && (user->ztc.confmode & ZT_CONF_TALKER)) { + user->ztc.confmode ^= ZT_CONF_TALKER; + if (ioctl(user->fd, ZT_SETCONF, &user->ztc)) { + ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); + return 2; + } + } + if (!(user->adminflags & ADMINFLAG_MUTED) && !(user->userflags & CONFFLAG_MONITOR) && !(user->ztc.confmode & ZT_CONF_TALKER)) { + user->ztc.confmode |= ZT_CONF_TALKER; + if (ioctl(user->fd, ZT_SETCONF, &user->ztc)) { + ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); + return 2; + } + } + if (user->adminflags & ADMINFLAG_KICKME) { + /* You have been kicked. */ + if (!ast_streamfile(user->chan, "conf-kicked", user->chan->language)) + ast_waitstream(user->chan, ""); + return 1; + } + } else if (!(user->userflags & CONFFLAG_MONITOR) && !(user->ztc.confmode & ZT_CONF_TALKER)) { + user->ztc.confmode |= ZT_CONF_TALKER; + if (ioctl(user->fd, ZT_SETCONF, &user->ztc)) { + ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); + return 2; + } + } + return ret; +} + +int activateagi(struct ast_conf_user *user) { + struct ast_app *app; + int ret = 0; + int x; + + /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND) + or use default filename of conf-background.agi */ + + user->agifile = pbx_builtin_getvar_helper(user->chan,"MEETME_AGI_BACKGROUND"); + if (!user->agifile) + user->agifile = MEETME_DEFAULTAGI; + + if (!strcasecmp(user->chan->type,"Zap")) { + /* Set CONFMUTE mode on Zap channel to mute DTMF tones */ + x = 1; + ast_channel_setoption(user->chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0); + } + /* Find a pointer to the agi app and execute the script */ + app = pbx_findapp("agi"); + if (app) { + ret = pbx_exec(user->chan, app, user->agifile, 1); + } else { + ast_log(LOG_WARNING, "Could not find application (agi)\n"); + ret = -2; + } + if (!strcasecmp(user->chan->type,"Zap")) { + /* Remove CONFMUTE mode on Zap channel */ + x = 0; + ast_channel_setoption(user->chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0); + } + return ret; +} +int confmenu(struct ast_conf_user *user, struct ast_frame *f) { + int ret = 0; + int dtmf; + + if ((user->userflags & CONFFLAG_ADMIN)) { + /* Admin menu */ + if (!user->menu_active) { + user->menu_active = 1; + /* Record this sound! */ + if (!ast_streamfile(user->chan, "conf-adminmenu", user->chan->language)) + dtmf = ast_waitstream(user->chan, AST_DIGIT_ANY); + else + dtmf = 0; + } else + dtmf = f->subclass; + if (dtmf) { + switch(dtmf) { + case '1': /* Un/Mute */ + user->menu_active = 0; + if (user->userflags & CONFFLAG_TALKER) { + user->ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER; + user->userflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER; + } else { + user->ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; + user->userflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER; + } + if (ioctl(user->fd, ZT_SETCONF, &user->ztc)) { + ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); + ret = -1; + break; + } + if (user->ztc.confmode & ZT_CONF_TALKER) { + if (!ast_streamfile(user->chan, "conf-unmuted", user->chan->language)) + ast_waitstream(user->chan, ""); + } else { + if (!ast_streamfile(user->chan, "conf-muted", user->chan->language)) + ast_waitstream(user->chan, ""); + } + break; + case '2': /* Un/Lock the Conference */ + user->menu_active = 0; + if (user->conf->locked) { + user->conf->locked = 0; + if (!ast_streamfile(user->chan, "conf-unlockednow", user->chan->language)) + ast_waitstream(user->chan, ""); + } else { + user->conf->locked = 1; + if (!ast_streamfile(user->chan, "conf-lockednow", user->chan->language)) + ast_waitstream(user->chan, ""); + } + break; + case '3': /* Eject last user */ + user->menu_active = 0; + user = user->conf->lastuser; + if ((user->chan->name == user->chan->name)||(user->userflags & CONFFLAG_ADMIN)) { + if(!ast_streamfile(user->chan, "conf-errormenu", user->chan->language)) + ast_waitstream(user->chan, ""); + } else + user->adminflags |= ADMINFLAG_KICKME; + ast_stopstream(user->chan); + break; + default: + user->menu_active = 0; + /* Play an error message! */ + if (!ast_streamfile(user->chan, "conf-errormenu", user->chan->language)) + ast_waitstream(user->chan, ""); + break; + } + } + } else { + /* User menu */ + if (!user->menu_active) { + user->menu_active = 1; + /* Record this sound! */ + if (!ast_streamfile(user->chan, "conf-usermenu", user->chan->language)) + dtmf = ast_waitstream(user->chan, AST_DIGIT_ANY); + else + dtmf = 0; + } else + dtmf = f->subclass; + if (dtmf) { + switch(dtmf) { + case '1': /* Un/Mute */ + user->menu_active = 0; + if (user->ztc.confmode & ZT_CONF_TALKER) { + user->ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER; + user->userflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER; + } else if (!(user->adminflags & ADMINFLAG_MUTED)) { + user->ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; + user->userflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER; + } + if (ioctl(user->fd, ZT_SETCONF, &user->ztc)) { + ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); + ret = -1; + break; + } + if (user->ztc.confmode & ZT_CONF_TALKER) { + if (!ast_streamfile(user->chan, "conf-unmuted", user->chan->language)) + ast_waitstream(user->chan, ""); + } else { + if (!ast_streamfile(user->chan, "conf-muted", user->chan->language)) + ast_waitstream(user->chan, ""); + } + break; + default: + user->menu_active = 0; + /* Play an error message! */ + if (!ast_streamfile(user->chan, "conf-errormenu", user->chan->language)) + ast_waitstream(user->chan, ""); + break; + } + } + } + return ret; +} +int processframe(struct ast_conf_user *user, struct ast_frame *f) { + int ret = 0; + + if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) { + if (user->userflags & CONFFLAG_MONITORTALKER) { + int totalsilence; + if (user->talking == -1) + user->talking = 0; + + ast_dsp_silence(user->dsp, f, &totalsilence); + if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) { + user->talking = 1; + manager_event(EVENT_FLAG_CALL, "MeetmeTalking", + "Channel: %s\r\n" + "Uniqueid: %s\r\n" + "Meetme: %s\r\n" + "Usernum: %i\r\n", + user->chan->name, user->chan->uniqueid, user->conf->confno, user->user_no); + } + if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) { + user->talking = 0; + manager_event(EVENT_FLAG_CALL, "MeetmeStopTalking", + "Channel: %s\r\n" + "Uniqueid: %s\r\n" + "Meetme: %s\r\n" + "Usernum: %i\r\n", + user->chan->name, user->chan->uniqueid, user->conf->confno, user->user_no); + } + } + if (user->using_pseudo) { + /* Carefully write */ + careful_write(user->fd, f->data, f->datalen); + } + } else if ((f->frametype == AST_FRAME_DTMF) && (user->userflags & CONFFLAG_EXIT_CONTEXT)) { + char tmp[2]; + tmp[0] = f->subclass; + tmp[1] = '\0'; + if (ast_exists_extension(user->chan, user->exitcontext, tmp, 1, user->chan->cid.cid_num)) { + strncpy(user->chan->context, user->exitcontext, sizeof(user->chan->context) - 1); + strncpy(user->chan->exten, tmp, sizeof(user->chan->exten) - 1); + user->chan->priority = 0; + ret = 0; + return 1; + } + } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (user->userflags & CONFFLAG_POUNDEXIT)) { + ret = 0; + return 1; + } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (user->userflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && user->menu_active)) { + struct zt_confinfo ztc_empty; + memset(&ztc_empty, 0, sizeof(ztc_empty)); + + if (ioctl(user->fd, ZT_SETCONF, &ztc_empty)) { + ast_log(LOG_WARNING, "Error setting conference: %s\n",strerror(errno)); + close(user->fd); + ast_mutex_unlock(&conflock); + return -2; + } + if (user->musiconhold) { + ast_moh_stop(user->chan); + } + confmenu( user, f); + if (user->musiconhold) { + ast_moh_start(user->chan, NULL); + } + if (ioctl(user->fd, ZT_SETCONF, &user->ztc)) { + ast_log(LOG_WARNING, "Error setting conference\n"); + close(user->fd); + ast_mutex_unlock(&conflock); + return -2; + } + conf_flush(user->fd); + } else if (option_debug) { + ast_log(LOG_DEBUG, "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",user->chan->name,f->frametype,f->subclass); + } + + return ret; +} int unload_module(void) { STANDARD_HANGUP_LOCALUSERS; @@ -1907,4 +2023,3 @@ { return ASTERISK_GPL_KEY; } -