Skip to content
Snippets Groups Projects
Commit 9c116b4d authored by Jeremy McNamara's avatar Jeremy McNamara
Browse files

Allow dynamic conferences to be joined by channels without dynamic flag. Bug #743

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1932 65c4cc65-6c06-0410-ace0-fbb531ad65f3
parent be056ad7
No related branches found
No related tags found
No related merge requests found
...@@ -44,20 +44,21 @@ static char *synopsis2 = "MeetMe participant count"; ...@@ -44,20 +44,21 @@ static char *synopsis2 = "MeetMe participant count";
static char *descrip = static char *descrip =
" MeetMe(confno[|options]): Enters the user into a specified MeetMe conference.\n" " MeetMe(confno[|options]): Enters the user into a specified MeetMe conference.\n"
"If the conference number is omitted, the user will be prompted to enter\n" "If the conference number is omitted, the user will be prompted to enter\n"
"one. This application always returns -1. A ZAPTEL INTERFACE MUST BE\n" "one. This application always returns -1.\n"
"INSTALLED FOR CONFERENCING FUNCTIONALITY.\n"
"The option string may contain zero or more of the following characters:\n" "The option string may contain zero or more of the following characters:\n"
" 'a' -- set admin mode\n" " 'a' -- set admin mode\n"
" 'm' -- set monitor only mode\n" " 'm' -- set monitor only mode (Listen only, no talking\n"
" 't' -- set talk only mode. (Talk only, no listening)\n"
" 'p' -- allow user to exit the conference by pressing '#'\n" " 'p' -- allow user to exit the conference by pressing '#'\n"
" 's' -- send user to admin/user menu if '*' is received\n" " 's' -- send user to admin/user menu if '*' is received\n"
" 't' -- set talk only mode\n"
" 'd' -- dynamically add conference\n" " 'd' -- dynamically add conference\n"
" '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"
" 'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND} (Zap channels only)\n" " 'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND}\n"
" (does not work with non-Zap channels in the same conference)\n"; " Default: conf-background.agi\n"
" (Note: This does not work with non-Zap channels in the same conference)\n";
static char *descrip2 = static char *descrip2 =
" MeetMeCount(confno[|var]): Plays back the number of users in the specifiedi\n" " MeetMeCount(confno[|var]): Plays back the number of users in the specifiedi\n"
...@@ -69,13 +70,15 @@ STANDARD_LOCAL_USER; ...@@ -69,13 +70,15 @@ STANDARD_LOCAL_USER;
LOCAL_USER_DECL; LOCAL_USER_DECL;
static struct conf { static struct ast_conference {
char confno[80]; /* Conference */ char confno[AST_MAX_EXTENSION]; /* 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 */
time_t start; /* Start time (s) */ time_t start; /* Start time (s) */
struct conf *next; int isdynamic; /* Created on the fly? */
char pin[AST_MAX_EXTENSION]; /* If protected by a PIN */
struct ast_conference *next;
} *confs; } *confs;
static ast_mutex_t conflock = AST_MUTEX_INITIALIZER; static ast_mutex_t conflock = AST_MUTEX_INITIALIZER;
...@@ -117,7 +120,7 @@ static int careful_write(int fd, unsigned char *data, int len) ...@@ -117,7 +120,7 @@ static int careful_write(int fd, unsigned char *data, int len)
return 0; return 0;
} }
static void conf_play(struct conf *conf, int sound) static void conf_play(struct ast_conference *conf, int sound)
{ {
unsigned char *data; unsigned char *data;
int len; int len;
...@@ -140,9 +143,9 @@ static void conf_play(struct conf *conf, int sound) ...@@ -140,9 +143,9 @@ static void conf_play(struct conf *conf, int sound)
ast_mutex_unlock(&conflock); ast_mutex_unlock(&conflock);
} }
static struct conf *build_conf(char *confno, int make) static struct ast_conference *build_conf(char *confno, char *pin, int make, int dynamic)
{ {
struct conf *cnf; struct ast_conference *cnf;
struct zt_confinfo ztc; struct zt_confinfo ztc;
ast_mutex_lock(&conflock); ast_mutex_lock(&conflock);
cnf = confs; cnf = confs;
...@@ -151,12 +154,13 @@ static struct conf *build_conf(char *confno, int make) ...@@ -151,12 +154,13 @@ static struct conf *build_conf(char *confno, int make)
break; break;
cnf = cnf->next; cnf = cnf->next;
} }
if (!cnf && make) { if (!cnf && (make || dynamic)) {
cnf = malloc(sizeof(struct conf)); cnf = malloc(sizeof(struct ast_conference));
if (cnf) { if (cnf) {
/* Make a new one */ /* Make a new one */
memset(cnf, 0, sizeof(struct conf)); memset(cnf, 0, sizeof(struct ast_conference));
strncpy(cnf->confno, confno, sizeof(cnf->confno) - 1); strncpy(cnf->confno, confno, sizeof(cnf->confno) - 1);
strncpy(cnf->pin, pin, sizeof(cnf->pin) - 1);
cnf->fd = open("/dev/zap/pseudo", O_RDWR); cnf->fd = open("/dev/zap/pseudo", O_RDWR);
if (cnf->fd < 0) { if (cnf->fd < 0) {
ast_log(LOG_WARNING, "Unable to open pseudo channel\n"); ast_log(LOG_WARNING, "Unable to open pseudo channel\n");
...@@ -166,7 +170,7 @@ static struct conf *build_conf(char *confno, int make) ...@@ -166,7 +170,7 @@ static struct conf *build_conf(char *confno, int make)
} }
memset(&ztc, 0, sizeof(ztc)); memset(&ztc, 0, sizeof(ztc));
/* Setup a new zap conference */ /* Setup a new zap conference */
ztc.chan = 0; ztc.chan = 0;
ztc.confno = -1; ztc.confno = -1;
ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
if (ioctl(cnf->fd, ZT_SETCONF, &ztc)) { if (ioctl(cnf->fd, ZT_SETCONF, &ztc)) {
...@@ -178,6 +182,7 @@ static struct conf *build_conf(char *confno, int make) ...@@ -178,6 +182,7 @@ static struct conf *build_conf(char *confno, int make)
} }
cnf->start = time(NULL); cnf->start = time(NULL);
cnf->zapconf = ztc.confno; cnf->zapconf = ztc.confno;
cnf->isdynamic = dynamic;
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;
...@@ -194,26 +199,31 @@ cnfout: ...@@ -194,26 +199,31 @@ cnfout:
static int confs_show(int fd, int argc, char **argv) static int confs_show(int fd, int argc, char **argv)
{ {
struct conf *conf; struct ast_conference *conf;
int hr, min, sec; int hr, min, sec;
time_t now; time_t now;
char *header_format = "%14s %-14s %-8s %-8s\n";
char *data_format = "%-12.12s %4.4d %02d:%02d:%02d %-8s\n";
now = time(NULL); now = time(NULL);
if (argc != 2) if (argc != 2)
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
conf = confs; conf = confs;
if (!conf) { 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, "Conf Num Parties Activity\n"); ast_cli(fd, header_format, "Conf Num", "Parties", "Activity", "Creation");
while(conf) { while(conf) {
hr = (now - conf->start) / 3600; hr = (now - conf->start) / 3600;
min = ((now - conf->start) % 3600) / 60; min = ((now - conf->start) % 3600) / 60;
sec = (now - conf->start) % 60; sec = (now - conf->start) % 60;
ast_cli(fd, "%-12.12s %4.4d %02d:%02d:%02d\n", if (conf->isdynamic)
conf->confno, conf->users, hr, min, sec); ast_cli(fd, data_format, conf->confno, conf->users, hr, min, sec, "Dynamic");
else
ast_cli(fd, data_format, conf->confno, conf->users, hr, min, sec, "Static");
conf = conf->next; conf = conf->next;
} }
return RESULT_SUCCESS; return RESULT_SUCCESS;
...@@ -228,9 +238,9 @@ static struct ast_cli_entry cli_show_confs = { ...@@ -228,9 +238,9 @@ static struct ast_cli_entry cli_show_confs = {
{ "show", "conferences", NULL }, confs_show, { "show", "conferences", NULL }, confs_show,
"Show status of conferences", show_confs_usage, NULL }; "Show status of conferences", show_confs_usage, NULL };
static int conf_run(struct ast_channel *chan, struct conf *conf, int confflags) static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags)
{ {
struct conf *prev=NULL, *cur; struct ast_conference *prev=NULL, *cur;
int fd; int fd;
struct zt_confinfo ztc; struct zt_confinfo ztc;
struct ast_frame *f; struct ast_frame *f;
...@@ -515,34 +525,59 @@ outrun: ...@@ -515,34 +525,59 @@ outrun:
return ret; return ret;
} }
static struct conf *find_conf(char *confno, int make, int dynamic) static struct ast_conference *find_conf(char *confno, int make, int dynamic)
{ {
struct ast_config *cfg; struct ast_config *cfg;
struct ast_variable *var; struct ast_variable *var;
struct conf *cnf = NULL; struct ast_conference *cnf = confs;
cfg = ast_load("meetme.conf");
if (!cfg) { /* Check first in the conference list */
ast_log(LOG_WARNING, "No meetme.conf file :(\n"); ast_mutex_lock(&conflock);
return NULL; while (cnf) {
} if (!strcmp(confno, cnf->confno))
var = ast_variable_browse(cfg, "rooms");
while(var) {
if (!strcasecmp(var->name, "conf") &&
!strcasecmp(var->value, confno)) {
/* Bingo it's a valid conference */
cnf = build_conf(confno, make);
break; break;
} cnf = cnf->next;
var = var->next;
} }
if (!var) { ast_mutex_unlock(&conflock);
if (!cnf) {
if (dynamic) { if (dynamic) {
/* No need to parse meetme.conf */
ast_log(LOG_DEBUG, "Using dynamic conference '%s'\n", confno); ast_log(LOG_DEBUG, "Using dynamic conference '%s'\n", confno);
cnf = build_conf(confno, make); cnf = build_conf(confno, "", make, dynamic);
} else } else {
ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno); /* Check the config */
cfg = ast_load("meetme.conf");
if (!cfg) {
ast_log(LOG_WARNING, "No meetme.conf file :(\n");
return NULL;
}
var = ast_variable_browse(cfg, "rooms");
while(var) {
if (!strcasecmp(var->name, "conf")) {
/* Separate the PIN */
char *pin, *conf;
if ((pin = ast_strdupa(var->value))) {
conf = strsep(&pin, "|,");
if (!strcasecmp(conf, confno)) {
/* Bingo it's a valid conference */
if (pin)
cnf = build_conf(confno, pin, make, dynamic);
else
cnf = build_conf(confno, "", make, dynamic);
break;
}
}
}
var = var->next;
}
if (!var) {
ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno);
}
ast_destroy(cfg);
}
} }
ast_destroy(cfg);
return cnf; return cnf;
} }
...@@ -550,34 +585,32 @@ static int count_exec(struct ast_channel *chan, void *data) ...@@ -550,34 +585,32 @@ static int count_exec(struct ast_channel *chan, void *data)
{ {
struct localuser *u; struct localuser *u;
int res = 0; int res = 0;
struct conf *conf; struct ast_conference *conf;
int cnt; int count;
char *confnum,*localdata,*mhandle; char *confnum, *localdata;
char val[80] = "0"; char val[80] = "0";
if (!data || !strlen(data)) { if (!data || !strlen(data)) {
ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n"); ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
return -1; return -1;
} }
mhandle = alloca(strlen(data) + 1); localdata = ast_strdupa(data);
localdata = mhandle; /* this is to make sure I have the original pointer for the free below */
LOCAL_USER_ADD(u); LOCAL_USER_ADD(u);
strcpy(localdata,data);
confnum = strsep(&localdata,"|"); confnum = strsep(&localdata,"|");
conf = find_conf(confnum, 0, 1); conf = find_conf(confnum, 0, 0);
if (conf) if (conf)
cnt = conf->users; count = conf->users;
else else
cnt = 0; count = 0;
if(localdata && strlen(localdata)){ if (localdata && strlen(localdata)){
/* have var so load it and exit */ /* have var so load it and exit */
snprintf(val,sizeof(val), "%i",cnt); snprintf(val,sizeof(val), "%i",count);
pbx_builtin_setvar_helper(chan, localdata,val); pbx_builtin_setvar_helper(chan, localdata,val);
}else{ } else {
if (chan->_state != AST_STATE_UP) if (chan->_state != AST_STATE_UP)
ast_answer(chan); ast_answer(chan);
res = ast_say_number(chan, cnt, "", chan->language); res = ast_say_number(chan, count, "", chan->language);
} }
LOCAL_USER_REMOVE(u); LOCAL_USER_REMOVE(u);
return res; return res;
...@@ -587,14 +620,13 @@ static int conf_exec(struct ast_channel *chan, void *data) ...@@ -587,14 +620,13 @@ static int conf_exec(struct ast_channel *chan, void *data)
{ {
int res=-1; int res=-1;
struct localuser *u; struct localuser *u;
char confno[80] = ""; char confno[AST_MAX_EXTENSION] = "";
int allowretry = 0; int allowretry = 0;
int retrycnt = 0; int retrycnt = 0;
struct conf *cnf; struct ast_conference *cnf;
int confflags = 0; int confflags = 0;
int dynamic = 0; int dynamic = 0;
char info[256], *ptr, *inflags, *inpin; char *info, *inflags = NULL, *inpin = NULL;
if (!data || !strlen(data)) { if (!data || !strlen(data)) {
allowretry = 1; allowretry = 1;
...@@ -604,73 +636,73 @@ static int conf_exec(struct ast_channel *chan, void *data) ...@@ -604,73 +636,73 @@ static int conf_exec(struct ast_channel *chan, void *data)
if (chan->_state != AST_STATE_UP) if (chan->_state != AST_STATE_UP)
ast_answer(chan); ast_answer(chan);
strncpy(info, (char *)data, sizeof(info) - 1); info = ast_strdupa((char *)data);
ptr = info;
if (info) { if (info) {
inflags = strchr(info, '|'); char *tmp = strsep(&info, "|");
if (inflags) { strncpy(confno, tmp, sizeof(confno));
*inflags = '\0';
inflags++;
if (strchr(inflags, 'a'))
confflags |= CONFFLAG_ADMIN;
if (strchr(inflags, 'm'))
confflags |= CONFFLAG_MONITOR;
if (strchr(inflags, 'p'))
confflags |= CONFFLAG_POUNDEXIT;
if (strchr(inflags, 's'))
confflags |= CONFFLAG_STARMENU;
if (strchr(inflags, 't'))
confflags |= CONFFLAG_TALKER;
if (strchr(inflags, 'q'))
confflags |= CONFFLAG_QUIET;
if (strchr(inflags, 'M'))
confflags |= CONFFLAG_MOH;
if (strchr(inflags, 'b'))
confflags |= CONFFLAG_AGI;
if (strchr(inflags, 'd'))
dynamic = 1;
inpin = strchr(inflags, '|');
if (inpin) {
*inpin = '\0';
inpin++;
/* XXX Need to do something with pin XXX */
ast_log(LOG_WARNING, "MEETME WITH PIN=(%s)\n", inpin);
}
}
} }
if (info)
/* Parse out the stuff */ inflags = strsep(&info, "|");
strncpy(confno, info, sizeof(confno) - 1); if (info)
retry: inpin = strsep(&info, "|");
while(!strlen(confno) && (++retrycnt < 4)) {
/* Prompt user for conference number */ if (inflags) {
res = ast_app_getdata(chan, "conf-getconfno",confno, sizeof(confno) - 1, 0); if (strchr(inflags, 'a'))
if (res <0) goto out; confflags |= CONFFLAG_ADMIN;
if (strchr(inflags, 'm'))
confflags |= CONFFLAG_MONITOR;
if (strchr(inflags, 'p'))
confflags |= CONFFLAG_POUNDEXIT;
if (strchr(inflags, 's'))
confflags |= CONFFLAG_STARMENU;
if (strchr(inflags, 't'))
confflags |= CONFFLAG_TALKER;
if (strchr(inflags, 'q'))
confflags |= CONFFLAG_QUIET;
if (strchr(inflags, 'M'))
confflags |= CONFFLAG_MOH;
if (strchr(inflags, 'b'))
confflags |= CONFFLAG_AGI;
if (strchr(inflags, 'd'))
dynamic = 1;
} }
if (strlen(confno)) {
/* Check the validity of the conference */ do {
cnf = find_conf(confno, 1, dynamic); if (retrycnt > 3)
if (!cnf) { allowretry = 0;
res = ast_streamfile(chan, "conf-invalid", chan->language); while (allowretry && (!strlen(confno)) && (++retrycnt < 4)) {
if (res < 0) /* Prompt user for conference number */
goto out; res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
if (!res) if (res < 0) {
res = ast_waitstream(chan, ""); /* Don't try to validate when we catch an error */
res = -1;
if (allowretry) {
strcpy(confno, ""); strcpy(confno, "");
goto retry; allowretry = 0;
break;
} }
} else {
/* XXX Should prompt user for pin if pin is required XXX */
/* Run the conference */
res = conf_run(chan, cnf, confflags);
} }
} if (strlen(confno)) {
out: /* Check the validity of the conference */
cnf = find_conf(confno, 1, dynamic);
if (!cnf) {
res = ast_streamfile(chan, "conf-invalid", chan->language);
if (!res)
ast_waitstream(chan, "");
res = -1;
if (allowretry)
strcpy(confno, "");
} else {
if (strlen(cnf->pin)) {
/* XXX Should prompt user for pin if pin is required XXX */
}
allowretry = 0;
/* Run the conference */
res = conf_run(chan, cnf, confflags);
}
}
} while (allowretry);
/* Do the conference */ /* Do the conference */
LOCAL_USER_REMOVE(u); LOCAL_USER_REMOVE(u);
return res; return res;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment