--- apps/app_meetme.c.orig 2005-04-07 18:25:20.053508183 -0600 +++ apps/app_meetme.c 2005-04-07 18:24:03.440364294 -0600 @@ -34,6 +34,7 @@ #include #include "../asterisk.h" #include "../astconf.h" +#include #ifdef __linux__ #include @@ -63,6 +64,10 @@ " '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" +" 'o' -- allow user to do outbound call and press * to add user in conf\n" +" outbound context defined using ${MEETME_OUTBOUNDCONTEXT}\n" +" user is added to conf with conf flags ${MEETME_INVITEECONFFLAGS}\n" +" (which defaults to 'Mwsx')\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" @@ -110,7 +115,14 @@ STANDARD_LOCAL_USER; LOCAL_USER_DECL; +struct ast_conferenceuserthread { + struct ast_channel *chan; + struct ast_conference *conf; + int confflags; + pthread_attr_t attr; + pthread_t userthread; +}; static struct ast_conference { char confno[AST_MAX_EXTENSION]; /* Conference */ struct ast_channel *chan; /* Announcements channel */ @@ -156,6 +168,8 @@ static int admin_exec(struct ast_channel *chan, void *data); static void *recordthread(void *args); +static void *meetmeuserthread(void *args); +int meetme_outbounddial(struct ast_channel *chan,struct ast_conference *conf, char* inviteeconfflags, char *dialcontext); #include "enter.h" #include "leave.h" @@ -169,6 +183,8 @@ #define CONF_SIZE 320 +#define MEETME_INVITEECONFFLAGS_DEFAULT "Mwsx" + #define CONFFLAG_ADMIN (1 << 1) /* If set the user has admin access on the conference */ #define CONFFLAG_MONITOR (1 << 2) /* If set the user can only receive audio from the conference */ #define CONFFLAG_POUNDEXIT (1 << 3) /* If set asterisk will exit conference when '#' is pressed */ @@ -191,7 +207,7 @@ #define CONFFLAG_EMPTYNOPIN (1 << 20) #define CONFFLAG_ALWAYSPROMPT (1 << 21) #define CONFFLAG_ANNOUNCEUSERCOUNT (1 << 22) /* If set, when user joins the conference, they will be told the number of users that are already in */ - +#define CONFFLAG_DIALOUTBOUND (1 << 23) /* If set, the user will be allowed to make outbound calls */ AST_DECLARE_OPTIONS(meetme_opts,{ ['a'] = { CONFFLAG_ADMIN }, @@ -210,6 +226,7 @@ ['b'] = { CONFFLAG_AGI }, ['w'] = { CONFFLAG_WAITMARKED }, ['r'] = { CONFFLAG_RECORDCONF }, + ['o'] = { CONFFLAG_DIALOUTBOUND }, ['d'] = { CONFFLAG_DYNAMIC }, ['D'] = { CONFFLAG_DYNAMICPIN }, ['e'] = { CONFFLAG_EMPTY }, @@ -600,6 +617,9 @@ char *agifiledefault = "conf-background.agi"; char meetmesecs[30] = ""; char exitcontext[AST_MAX_EXTENSION] = ""; + char *inviteeconfflags = ""; + char *dialcontext = ""; + char dialcontexttmp[AST_MAX_EXTENSION] = ""; char recordingtmp[AST_MAX_EXTENSION] = ""; int dtmf; @@ -673,6 +693,18 @@ user->talking = -1; ast_mutex_unlock(&conflock); origquiet = confflags & CONFFLAG_QUIET; + if (confflags & CONFFLAG_DIALOUTBOUND) { + dialcontext = pbx_builtin_getvar_helper(chan,"MEETME_OUTBOUNDCONTEXT"); + if (!dialcontext) { + snprintf(dialcontexttmp,sizeof(dialcontexttmp),chan->context); + dialcontext = ast_strdupa(dialcontexttmp); + } + inviteeconfflags = pbx_builtin_getvar_helper(chan, "MEETME_INVITEECONFFLAGS"); + if (!inviteeconfflags) { + inviteeconfflags = MEETME_INVITEECONFFLAGS_DEFAULT; + } + + } if (confflags & CONFFLAG_EXIT_CONTEXT) { if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) strncpy(exitcontext, agifile, sizeof(exitcontext) - 1); @@ -1145,6 +1177,14 @@ usr->adminflags |= ADMINFLAG_KICKME; ast_stopstream(chan); break; + case '4': /* Outbound Call */ + menu_active = 0; + if (confflags & CONFFLAG_DIALOUTBOUND) { + menu_active = 0; + meetme_outbounddial(chan, conf, inviteeconfflags, dialcontext); + break; + } + default: menu_active = 0; /* Play an error message! */ @@ -1826,7 +1866,139 @@ ast_mutex_unlock(&conflock); return 0; } +int meetme_outbounddial(struct ast_channel *chan,struct ast_conference *conf, char *inviteeconfflags, char *dialcontext) { + struct ast_conferenceuserthread *tmpconfuser; + struct ast_frame *fa; + struct ast_channel *watchers[2]; + struct ast_channel *peer=NULL; + struct ast_channel *winner; + struct ast_channel *outgoing; + int outstate; + int pos=2; + int *to; + char admin_input[80]; + char digit; + int ax; + struct tone_zone_sound *ts; + int res; + int transmitframe; + char app_arg[AST_MAX_EXTENSION]; + + to = &pos; + + ast_stopstream(chan); + + ts = ast_get_indication_tone(chan->zone,"dial"); + if (ts && ts->data[0]) + res = ast_playtones_start(chan, 0, ts->data, 0); + memset(&admin_input,0,sizeof(admin_input)); + for(ax=0;ax < AST_MAX_EXTENSION;ax++) { + digit = ast_waitfordigit(chan,4500); + if(!digit || digit == '#') + break; + if(digit && digit == '*') + return 0; + ast_playtones_stop(chan); + admin_input[ax] = digit; + } + if(admin_input && !ast_strlen_zero(admin_input)) { + ts = ast_get_indication_tone(chan->zone,"ring"); + if (ts && ts->data[0]) + res = ast_playtones_start(chan, 0, ts->data, 0); + sprintf(app_arg,"%s@%s",admin_input,dialcontext); + + outgoing = ast_request_and_dial("Local", ast_best_codec(chan->nativeformats), app_arg,30000, &outstate, chan->cid.cid_num, chan->cid.cid_name); + ast_playtones_stop(chan); + + if(outgoing) { + if (ast_set_write_format(outgoing, AST_FORMAT_SLINEAR) < 0) { + ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name); + ast_hangup(outgoing); + } + + /* Set it into linear mode (read) */ + if (ast_set_read_format(outgoing, AST_FORMAT_SLINEAR) < 0) { + ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name); + ast_hangup(outgoing); + } + if(outgoing->_state == AST_STATE_UP) { + if(option_verbose > 3) + ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", outgoing->name); + while (!peer) { + transmitframe = 0; + watchers[0] = chan; + watchers[1] = outgoing; + + winner = ast_waitfor_n(watchers,2,to); + if (winner == chan || winner == outgoing) { + fa = ast_read(winner); + if (fa && (fa->frametype == AST_FRAME_VOICE)) { + transmitframe = 1; + } else if (fa && fa->frametype == AST_FRAME_DTMF) { + switch (fa->subclass) { + case '#': + ast_frfree(fa); + ast_hangup(outgoing); + return -1; + case '*': + tmpconfuser = malloc(sizeof(struct ast_conferenceuserthread)); + /* Parse conference flags for outbound call */ + ast_parseoptions(meetme_opts, &tmpconfuser->confflags, NULL, inviteeconfflags); + /* tmpconfuser->confflags = meetme_options2flags(inviteeconfflags, 1); */ + tmpconfuser->conf = conf; + tmpconfuser->chan = outgoing; + pthread_attr_init(&tmpconfuser ->attr); + pthread_attr_setdetachstate(&tmpconfuser ->attr, PTHREAD_CREATE_DETACHED); + ast_pthread_create(&tmpconfuser->userthread, &tmpconfuser->attr, meetmeuserthread, tmpconfuser); + peer = outgoing; + break; + + default: + transmitframe = 1; + + } + } else if (!fa || (fa->frametype == AST_FRAME_CONTROL && fa->subclass == AST_CONTROL_HANGUP)) { + + if (fa) + ast_frfree(fa); + if (outgoing->_state == AST_STATE_UP) + ast_hangup(outgoing); + break; + } + if (transmitframe == 1 && (fa && (fa->frametype == AST_FRAME_DTMF || fa->frametype == AST_FRAME_VOICE))) { + if (winner == chan) + if (ast_write(outgoing, fa)) + ast_log(LOG_WARNING, "Unable to forward frame\n"); + if (winner == outgoing) + if (ast_write(chan, fa)) + ast_log(LOG_WARNING, "Unable to forward frame\n"); + } + ast_frfree(fa); + } + } + + } else { + if(option_verbose > 3) + ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", outgoing->name); + ast_hangup(outgoing); + } + } else { + ast_log(LOG_WARNING, "Unable to allocate channel.\n"); + } + } + return 0; + +} +static void *meetmeuserthread(void *args) +{ + struct ast_conferenceuserthread *confthread; + confthread = (struct ast_conferenceuserthread *)args; + conf_run(confthread->chan, confthread->conf, confthread->confflags); + if(confthread->chan) + ast_hangup(confthread->chan); + pthread_exit(0); +} static void *recordthread(void *args) { struct ast_conference *cnf;