Merge fabeman's extensive meetme improvements (bug #1624)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@3038 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.0
Mark Spencer 22 years ago
parent ad67680ed3
commit a0486afb83

@ -38,9 +38,11 @@ static char *tdesc = "Simple MeetMe conference bridge";
static char *app = "MeetMe"; static char *app = "MeetMe";
static char *app2 = "MeetMeCount"; static char *app2 = "MeetMeCount";
static char *app3 = "MeetMeAdmin";
static char *synopsis = "Simple MeetMe conference bridge"; static char *synopsis = "Simple MeetMe conference bridge";
static char *synopsis2 = "MeetMe participant count"; static char *synopsis2 = "MeetMe participant count";
static char *synopsis3 = "Send Admin Commands to a conference";
static char *descrip = static char *descrip =
" MeetMe(confno[,[options][,pin]]): Enters the user into a specified MeetMe conference.\n" " MeetMe(confno[,[options][,pin]]): Enters the user into a specified MeetMe conference.\n"
@ -59,11 +61,11 @@ static char *descrip =
" 'v' -- video mode\n" " 'v' -- video mode\n"
" 'q' -- quiet mode (don't play enter/leave sounds)\n" " 'q' -- quiet mode (don't play enter/leave sounds)\n"
" 'M' -- enable music on hold when the conference has a single caller\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" " 'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND}\n"
" Default: conf-background.agi\n" " Default: conf-background.agi\n"
" (Note: This does not work with non-Zap channels in the same conference)\n" " (Note: This does not work with non-Zap channels in the same conference)\n"
" Not implemented yet:\n" " 'u' -- send user to admin/user menu if '*' is received\n"
" 's' -- send user to admin/user menu if '*' is received\n"
" 'a' -- set admin mode\n"; " 'a' -- set admin mode\n";
static char *descrip2 = 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" "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"; "A ZAPTEL INTERFACE MUST BE INSTALLED FOR CONFERENCING FUNCTIONALITY.\n";
static char *descrip3 = "";
STANDARD_LOCAL_USER; STANDARD_LOCAL_USER;
LOCAL_USER_DECL; LOCAL_USER_DECL;
@ -81,14 +85,35 @@ static struct ast_conference {
int fd; /* Announcements fd */ int fd; /* Announcements fd */
int zapconf; /* Zaptel Conf # */ int zapconf; /* Zaptel Conf # */
int users; /* Number of active users */ 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) */ time_t start; /* Start time (s) */
int isdynamic; /* Created on the fly? */ int isdynamic; /* Created on the fly? */
int locked; /* Is the conference locked? */
char pin[AST_MAX_EXTENSION]; /* If protected by a PIN */ char pin[AST_MAX_EXTENSION]; /* If protected by a PIN */
struct ast_conference *next; struct ast_conference *next;
} *confs; } *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 ast_mutex_t conflock = AST_MUTEX_INITIALIZER;
static int admin_exec(struct ast_channel *chan, void *data);
#include "enter.h" #include "enter.h"
#include "leave.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_VIDEO (1 << 7) /* Set to enable video mode */
#define CONFFLAG_AGI (1 << 8) /* Set to run AGI Script in Background */ #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_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) 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; cnf = NULL;
goto cnfout; goto cnfout;
} }
/* Fill the conference struct */
cnf->start = time(NULL); cnf->start = time(NULL);
cnf->zapconf = ztc.confno; cnf->zapconf = ztc.confno;
cnf->isdynamic = dynamic; cnf->isdynamic = dynamic;
cnf->firstuser = NULL;
cnf->lastuser = NULL;
cnf->locked = 0;
if (option_verbose > 2) if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Created ZapTel conference %d for conference '%s'\n", cnf->zapconf, cnf->confno); ast_verbose(VERBOSE_PREFIX_3 "Created ZapTel conference %d for conference '%s'\n", cnf->zapconf, cnf->confno);
cnf->next = confs; cnf->next = confs;
@ -203,48 +233,209 @@ cnfout:
static int confs_show(int fd, int argc, char **argv) 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 hr, min, sec;
int i = 0;
time_t now; time_t now;
char *header_format = "%-14s %-14s %-8s %-8s\n"; char *header_format = "%-14s %-14s %-8s %-8s\n";
char *data_format = "%-12.12s %4.4d %02d:%02d:%02d %-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); now = time(NULL);
if (argc != 2) cnf = confs;
return RESULT_SHOWUSAGE; if (!cnf) {
conf = confs;
if (!conf) {
ast_cli(fd, "No active conferences.\n"); ast_cli(fd, "No active conferences.\n");
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ast_cli(fd, header_format, "Conf Num", "Parties", "Activity", "Creation"); ast_cli(fd, header_format, "Conf Num", "Parties", "Activity", "Creation");
while(conf) { while(cnf) {
hr = (now - conf->start) / 3600; hr = (now - cnf->start) / 3600;
min = ((now - conf->start) % 3600) / 60; min = ((now - cnf->start) % 3600) / 60;
sec = (now - conf->start) % 60; sec = (now - cnf->start) % 60;
if (conf->isdynamic) if (cnf->isdynamic)
ast_cli(fd, data_format, conf->confno, conf->users, hr, min, sec, "Dynamic"); ast_cli(fd, data_format, cnf->confno, cnf->users, hr, min, sec, "Dynamic");
else 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; 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[] = static char *complete_confcmd(char *line, char *word, int pos, int state) {
"Usage: show conferences\n" #define CONF_COMMANDS 6
" Provides summary information on conferences with active\n" int which = 0, x = 0;
" participation.\n"; 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;
static struct ast_cli_entry cli_show_confs = { if (pos == 1) {
{ "show", "conferences", NULL }, confs_show, /* Command */
"Show status of conferences", show_confs_usage, NULL }; 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;
/* 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) static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags)
{ {
struct ast_conference *prev=NULL, *cur; struct ast_conference *prev=NULL, *cur;
struct ast_conf_user *user = malloc(sizeof(struct ast_conf_user));
int fd; int fd;
struct zt_confinfo ztc; struct zt_confinfo ztc;
struct ast_frame *f; 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 firstpass = 0;
int ret = -1; int ret = -1;
int x; int x;
int menu_active = 0;
struct ast_app *app; struct ast_app *app;
char *agifile; char *agifile;
char *agifiledefault = "conf-background.agi"; char *agifiledefault = "conf-background.agi";
char meetmesecs[30];
ZT_BUFFERINFO bi; ZT_BUFFERINFO bi;
char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET]; char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
char *buf = __buf + 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++; 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 (!(confflags & CONFFLAG_QUIET) && conf->users == 1) {
if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
ast_waitstream(chan, ""); ast_waitstream(chan, "");
@ -388,7 +625,6 @@ zapretry:
"Meetme: %s\r\n", "Meetme: %s\r\n",
chan->name, chan->uniqueid, conf->confno); chan->name, chan->uniqueid, conf->confno);
if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) { if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
firstpass = 1; firstpass = 1;
if (!(confflags & CONFFLAG_QUIET)) if (!(confflags & CONFFLAG_QUIET))
@ -422,10 +658,20 @@ zapretry:
x = 0; x = 0;
ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),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; outfd = -1;
ms = -1; ms = -1;
c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms); 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 */ /* trying to add moh for single person conf */
if (confflags & CONFFLAG_MOH) { if (confflags & CONFFLAG_MOH) {
if (conf->users == 1) { 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) {
if (c->fds[0] != origfd) { if (c->fds[0] != origfd) {
@ -458,13 +744,105 @@ zapretry:
if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) { if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
ret = 0; ret = 0;
break; 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)) { 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 {
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 { } else {
/* Do user menu here */ 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]) { } else if (fd != chan->fds[0]) {
if (f->frametype == AST_FRAME_VOICE) { if (f->frametype == AST_FRAME_VOICE) {
if (f->subclass == AST_FORMAT_ULAW) { if (f->subclass == AST_FORMAT_ULAW) {
@ -493,7 +871,7 @@ zapretry:
ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno)); ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
} }
} }
}
if (fd != chan->fds[0]) if (fd != chan->fds[0])
close(fd); close(fd);
else { else {
@ -510,23 +888,17 @@ zapretry:
conf_play(conf, LEAVE); conf_play(conf, LEAVE);
outrun: outrun:
if (user->user_no) { /* Only cleanup users who really joined! */
ast_mutex_lock(&conflock);
/* Clean up */
conf->users--;
ast_log(LOG_DEBUG, "Removed channel %s from ZAP conf %d\n", chan->name, conf->zapconf);
manager_event(EVENT_FLAG_CALL, "MeetmeLeave", manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
"Channel: %s\r\n" "Channel: %s\r\n"
"Uniqueid: %s\r\n" "Uniqueid: %s\r\n"
"Meetme: %s\r\n", "Meetme: %s\r\n",
chan->name, chan->uniqueid, conf->confno); chan->name, chan->uniqueid, conf->confno);
ast_mutex_lock(&conflock);
conf->users--;
cur = confs;
if (!conf->users) { if (!conf->users) {
/* No more users -- close this one out */ /* No more users -- close this one out */
cur = confs;
while(cur) { while(cur) {
if (cur == conf) { if (cur == conf) {
if (prev) if (prev)
@ -542,7 +914,24 @@ outrun:
ast_log(LOG_WARNING, "Conference not found\n"); ast_log(LOG_WARNING, "Conference not found\n");
close(conf->fd); close(conf->fd);
free(conf); 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); ast_mutex_unlock(&conflock);
return ret; return ret;
} }
@ -692,7 +1081,7 @@ static int conf_exec(struct ast_channel *chan, void *data)
confflags |= CONFFLAG_MONITOR; confflags |= CONFFLAG_MONITOR;
if (strchr(inflags, 'p')) if (strchr(inflags, 'p'))
confflags |= CONFFLAG_POUNDEXIT; confflags |= CONFFLAG_POUNDEXIT;
if (strchr(inflags, 's')) if (strchr(inflags, 'u'))
confflags |= CONFFLAG_STARMENU; confflags |= CONFFLAG_STARMENU;
if (strchr(inflags, 't')) if (strchr(inflags, 't'))
confflags |= CONFFLAG_TALKER; confflags |= CONFFLAG_TALKER;
@ -700,6 +1089,8 @@ static int conf_exec(struct ast_channel *chan, void *data)
confflags |= CONFFLAG_QUIET; confflags |= CONFFLAG_QUIET;
if (strchr(inflags, 'M')) if (strchr(inflags, 'M'))
confflags |= CONFFLAG_MOH; confflags |= CONFFLAG_MOH;
if (strchr(inflags, 'x'))
confflags |= CONFFLAG_ADMINEXIT;
if (strchr(inflags, 'b')) if (strchr(inflags, 'b'))
confflags |= CONFFLAG_AGI; confflags |= CONFFLAG_AGI;
if (strchr(inflags, 'd')) if (strchr(inflags, 'd'))
@ -873,10 +1264,102 @@ static int conf_exec(struct ast_channel *chan, void *data)
return res; 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(&params, "|");
command = strsep(&params, "|");
caller = strsep(&params, "|");
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) int unload_module(void)
{ {
STANDARD_HANGUP_LOCALUSERS; STANDARD_HANGUP_LOCALUSERS;
ast_cli_unregister(&cli_show_confs); ast_cli_unregister(&cli_show_confs);
ast_cli_unregister(&cli_conf);
ast_unregister_application(app3);
ast_unregister_application(app2); ast_unregister_application(app2);
return ast_unregister_application(app); return ast_unregister_application(app);
} }
@ -884,6 +1367,8 @@ int unload_module(void)
int load_module(void) int load_module(void)
{ {
ast_cli_register(&cli_show_confs); 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); ast_register_application(app2, count_exec, synopsis2, descrip2);
return ast_register_application(app, conf_exec, synopsis, descrip); return ast_register_application(app, conf_exec, synopsis, descrip);
} }

@ -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 ast_safe_sleep_conditional( struct ast_channel *chan, int ms,
int (*cond)(void*), void *data ) int (*cond)(void*), void *data )
{ {

@ -628,6 +628,9 @@ int ast_recvchar(struct ast_channel *chan, int timeout);
*/ */
struct ast_channel *ast_channel_walk_locked(struct ast_channel *prev); 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 //! Waits for a digit
/*! /*!
* \param c channel to wait for a digit on * \param c channel to wait for a digit on

@ -455,6 +455,7 @@ static int action_redirect(struct mansession *s, struct message *m)
char *exten = astman_get_header(m, "Exten"); char *exten = astman_get_header(m, "Exten");
char *context = astman_get_header(m, "Context"); char *context = astman_get_header(m, "Context");
char *priority = astman_get_header(m, "Priority"); char *priority = astman_get_header(m, "Priority");
struct ast_channel *chan, *chan2 = NULL;
int pi = 0; int pi = 0;
int res; int res;
if (!name || !strlen(name)) { 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"); astman_send_error(s, m, "Invalid priority\n");
return 0; 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 (!res) {
if (strlen(name2)) { 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) if (!res)
astman_send_ack(s, m, "Dual Redirect successful"); astman_send_ack(s, m, "Dual Redirect successful");
else else
@ -477,6 +484,10 @@ static int action_redirect(struct mansession *s, struct message *m)
astman_send_ack(s, m, "Redirect successful"); astman_send_ack(s, m, "Redirect successful");
} else } else
astman_send_error(s, m, "Redirect failed"); astman_send_error(s, m, "Redirect failed");
if (chan)
ast_mutex_unlock(&chan->lock);
if (chan2)
ast_mutex_unlock(&chan2->lock);
return 0; return 0;
} }

@ -612,3 +612,21 @@
%plus.gsm%plus [+] %plus.gsm%plus [+]
%equals.gsm%equals [=] %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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.
Loading…
Cancel
Save