" '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"
+" '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"
#define CONFFLAG_MOH (1 << 9) /* Set to have music on hold when user is alone in conference */
#define CONFFLAG_ADMINEXIT (1 << 10) /* If set the MeetMe will return if all marked with this flag left */
#define CONFFLAG_WAITMARKED (1 << 11) /* If set, the MeetMe will wait until a marked user enters */
+#define CONFFLAG_EXIT_CONTEXT (1 << 12) /* If set, the MeetMe will wait until a marked user enters */
static int careful_write(int fd, unsigned char *data, int len)
char *agifile;
char *agifiledefault = "conf-background.agi";
char meetmesecs[30] = "";
+ char exitcontext[AST_MAX_EXTENSION] = "";
ZT_BUFFERINFO bi;
char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
user->adminflags = 0;
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);
+ else
+ strncpy(exitcontext, chan->context, sizeof(exitcontext) - 1);
+ }
while((confflags & CONFFLAG_WAITMARKED) && (conf->markedusers < 0)) {
confflags &= ~CONFFLAG_QUIET;
confflags |= origquiet;
f = ast_read(c);
if (!f)
break;
- if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
+ 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->callerid)) {
+ strncpy(chan->context, exitcontext, sizeof(chan->context) - 1);
+ strncpy(chan->exten, tmp, sizeof(chan->exten) - 1);
+ chan->priority = 0;
+ 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)) {
confflags |= CONFFLAG_MOH;
if (strchr(inflags, 'x'))
confflags |= CONFFLAG_ADMINEXIT;
+ if (strchr(inflags, 'X'))
+ confflags |= CONFFLAG_EXIT_CONTEXT;
if (strchr(inflags, 'b'))
confflags |= CONFFLAG_AGI;
if (strchr(inflags, 'w'))
static int transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
/* Registrar for operations */
-static char *registrar = "res_parking";
+static char *registrar = "res_features";
static char *synopsis = "Answer a parked call";
"into the dialplan, although you should include the 'parkedcalls'\n"
"context.\n";
+
+static char *parkcall = "Park";
+
+static char *synopsis2 = "Park yourself";
+
+static char *descrip2 = "Park(exten):"
+"Used to park yourself (typically in combination with a supervised\n"
+"transfer to know the parking space. This Application is always\n"
+"registered internally and does not need to be explicitly added\n"
+"into the dialplan, although you should include the 'parkedcalls'\n"
+"context.\n";
+
struct parkeduser {
struct ast_channel *chan;
struct timeval start;
char exten[AST_MAX_EXTENSION];
int priority;
int parkingtime;
+ int notquiteyet;
struct parkeduser *next;
};
after these channels too */
struct parkeduser *pu, *cur;
int x;
+ char exten[AST_MAX_EXTENSION];
+ struct ast_context *con;
pu = malloc(sizeof(struct parkeduser));
if (pu) {
ast_mutex_lock(&parking_lock);
pu->chan = chan;
/* Start music on hold */
- ast_moh_start(pu->chan, NULL);
+ if (chan != peer)
+ ast_moh_start(pu->chan, NULL);
gettimeofday(&pu->start, NULL);
pu->parkingnum = x;
if (timeout > 0)
pu->priority = chan->priority;
pu->next = parkinglot;
parkinglot = pu;
+ /* If parking a channel directly, don't quiet yet get parking running on it */
+ if (peer == chan)
+ pu->notquiteyet = 1;
ast_mutex_unlock(&parking_lock);
/* Wake up the (presumably select()ing) thread */
pthread_kill(parking_thread, SIGURG);
,(pu->chan->callerid ? pu->chan->callerid : "")
);
- if (peer)
+ if (peer) {
ast_say_digits(peer, pu->parkingnum, "", peer->language);
+ if (pu->notquiteyet) {
+ /* Wake up parking thread if we're really done */
+ ast_moh_start(pu->chan, NULL);
+ pu->notquiteyet = 0;
+ pthread_kill(parking_thread, SIGURG);
+ }
+ }
+ con = ast_context_find(parking_con);
+ if (!con) {
+ con = ast_context_create(NULL,parking_con, registrar);
+ if (!con) {
+ ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
+ }
+ }
+ if (con) {
+ snprintf(exten, sizeof(exten), "%d", x);
+ ast_add_extension2(con, 1, exten, 1, NULL, parkedcall, strdup(exten), free, registrar);
+ }
return 0;
} else {
ast_log(LOG_WARNING, "No more parking spaces\n");
struct parkeduser *pu, *pl, *pt = NULL;
struct timeval tv;
struct ast_frame *f;
+ char exten[AST_MAX_EXTENSION];
+ struct ast_context *con;
int x;
fd_set rfds, efds;
fd_set nrfds, nefds;
FD_ZERO(&nrfds);
FD_ZERO(&nefds);
while(pu) {
+ if (pu->notquiteyet) {
+ /* Pretend this one isn't here yet */
+ pl = pu;
+ pu = pu->next;
+ continue;
+ }
tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
if (tms > pu->parkingtime) {
/* They've been waiting too long, send them back to where they came. Theoretically they
parkinglot = pu->next;
pt = pu;
pu = pu->next;
+ con = ast_context_find(parking_con);
+ if (con) {
+ snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
+ if (ast_context_remove_extension2(con, exten, 1, NULL))
+ ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
+ } else
+ ast_log(LOG_WARNING, "Whoa, no parking context?\n");
free(pt);
} else {
for (x=0;x<AST_MAX_FDS;x++) {
parkinglot = pu->next;
pt = pu;
pu = pu->next;
+ con = ast_context_find(parking_con);
+ if (con) {
+ snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
+ if (ast_context_remove_extension2(con, exten, 1, NULL))
+ ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
+ } else
+ ast_log(LOG_WARNING, "Whoa, no parking context?\n");
free(pt);
break;
} else {
return NULL; /* Never reached */
}
+static int park_call_exec(struct ast_channel *chan, void *data)
+{
+ /* Data is unused at the moment but could contain a parking
+ lot context eventually */
+ int res=0;
+ struct localuser *u;
+ LOCAL_USER_ADD(u);
+ /* Setup the exten/priority to be s/1 since we don't know
+ where this call should return */
+ strcpy(chan->exten, "s");
+ chan->priority = 1;
+ if (chan->_state != AST_STATE_UP)
+ res = ast_answer(chan);
+ if (!res)
+ res = ast_safe_sleep(chan, 1000);
+ if (!res)
+ res = ast_park_call(chan, chan, 0, NULL);
+ LOCAL_USER_REMOVE(u);
+ if (!res)
+ res = AST_PBX_KEEPALIVE;
+ return res;
+}
+
static int park_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct localuser *u;
struct ast_channel *peer=NULL;
struct parkeduser *pu, *pl=NULL;
+ char exten[AST_MAX_EXTENSION];
+ struct ast_context *con;
int park;
int dres;
struct ast_bridge_config config;
ast_mutex_unlock(&parking_lock);
if (pu) {
peer = pu->chan;
+ con = ast_context_find(parking_con);
+ if (con) {
+ snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
+ if (ast_context_remove_extension2(con, exten, 1, NULL))
+ ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
+ } else
+ ast_log(LOG_WARNING, "Whoa, no parking context?\n");
free(pu);
}
/* JK02: it helps to answer the channel if not already up */
int load_module(void)
{
int res;
- int x;
int start, end;
struct ast_context *con;
- char exten[AST_MAX_EXTENSION];
struct ast_config *cfg;
struct ast_variable *var;
return -1;
}
}
- for(x=parking_start; x<=parking_stop;x++) {
- snprintf(exten, sizeof(exten), "%d", x);
- ast_add_extension2(con, 1, exten, 1, NULL, parkedcall, strdup(exten), free, registrar);
- }
+ ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, parkcall, strdup(""),free, registrar);
pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
+ if (!res)
+ res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
if (!res) {
ast_manager_register( "ParkedCalls", 0, manager_parking_status, "List parked calls" );
}
ast_manager_unregister( "ParkedCalls" );
ast_cli_unregister(&showparked);
-
+ ast_unregister_application(parkcall);
return ast_unregister_application(parkedcall);
}