diff options
Diffstat (limited to 'pbx.c')
-rwxr-xr-x | pbx.c | 350 |
1 files changed, 338 insertions, 12 deletions
@@ -132,6 +132,22 @@ struct ast_app { struct ast_app *next; }; +/* An extension state notify */ +struct ast_notify_cb { + int id; + void *data; + ast_notify_cb_type callback; + struct ast_notify_cb *next; +}; + +struct ast_notify { + struct ast_exten *exten; + int laststate; + struct ast_notify_cb *callbacks; + struct ast_notify *next; +}; + + static int pbx_builtin_prefix(struct ast_channel *, void *); static int pbx_builtin_stripmsd(struct ast_channel *, void *); static int pbx_builtin_answer(struct ast_channel *, void *); @@ -294,6 +310,11 @@ static struct ast_app *apps = NULL; static pthread_mutex_t switchlock = AST_MUTEX_INITIALIZER; struct ast_switch *switches = NULL; +/* Lock for extension state notifys */ +static pthread_mutex_t notifylock = AST_MUTEX_INITIALIZER; +static int notifycnt = 0; +struct ast_notify *notifys = NULL; + int pbx_exec(struct ast_channel *c, /* Channel */ struct ast_app *app, void *data, /* Data for execution */ @@ -676,20 +697,19 @@ static struct ast_exten *pbx_find_extension(struct ast_channel *chan, char *cont return NULL; } -static void pbx_substitute_variables_temp(struct ast_channel *c,char *cp3,char **cp4) +static void pbx_substitute_variables_temp(struct ast_channel *c,char *cp3,char **cp4, char *workspace, int workspacelen) { char *first,*second; int offset,offset2; struct ast_var_t *variables; char *name, *num; /* for callerid name + num variables */ struct varshead *headp; - char pri[80]; headp=&c->varshead; *cp4=NULL; /* Now we have the variable name on cp3 */ if ((first=strchr(cp3,':'))) { *first='\0'; - pbx_substitute_variables_temp(c,cp3,cp4); + pbx_substitute_variables_temp(c,cp3,cp4,workspace,workspacelen); if (!(*cp4)) return; offset=atoi(first+1); if ((second=strchr(first+1,':'))) { @@ -711,20 +731,18 @@ static void pbx_substitute_variables_temp(struct ast_channel *c,char *cp3,char * *cp4+=strlen(*cp4)+offset; (*cp4)[offset2] = '\0'; } else if (!strcmp(cp3, "CALLERIDNUM")) { - char cid[256] = ""; if (c->callerid) - strncpy(cid, c->callerid, sizeof(cid) - 1); - ast_callerid_parse(cid, &name, &num); + strncpy(workspace, c->callerid, workspacelen - 1); + ast_callerid_parse(workspace, &name, &num); if (num) { ast_shrink_phone_number(num); *cp4 = num; } else *cp4 = ""; } else if (!strcmp(cp3, "CALLERIDNAME")) { - char cid[256] = ""; if (c->callerid) - strncpy(cid, c->callerid, sizeof(cid) - 1); - ast_callerid_parse(cid, &name, &num); + strncpy(workspace, c->callerid, workspacelen - 1); + ast_callerid_parse(workspace, &name, &num); if (name) *cp4 = name; else @@ -733,6 +751,11 @@ static void pbx_substitute_variables_temp(struct ast_channel *c,char *cp3,char * *cp4 = c->callerid; if (!(*cp4)) *cp4 = ""; + } else if (!strcmp(cp3, "HINT")) { + if (!ast_get_hint(workspace, workspacelen - 1, c, c->context, c->exten)) + *cp4 = ""; + else + *cp4 = workspace; } else if (!strcmp(cp3, "EXTEN")) { *cp4 = c->exten; } else if (!strncmp(cp3, "EXTEN-", strlen("EXTEN-")) && @@ -760,8 +783,10 @@ static void pbx_substitute_variables_temp(struct ast_channel *c,char *cp3,char * } else if (!strcmp(cp3, "CONTEXT")) { *cp4 = c->context; } else if (!strcmp(cp3, "PRIORITY")) { - snprintf(pri, sizeof(pri), "%d", c->priority); - *cp4 = pri; + snprintf(workspace, workspacelen, "%d", c->priority); + *cp4 = workspace; + } else if (!strcmp(cp3, "CHANNEL")) { + *cp4 = c->name; } else { AST_LIST_TRAVERSE(headp,variables,entries) { #if 0 @@ -796,6 +821,7 @@ static void pbx_substitute_variables_helper(struct ast_channel *c,char *cp1,char char *cp4,*cp2; char *tmp,*wherearewe,*finish=NULL,*ltmp,*lval,*nextvar; int length,variables=0; + char workspace[256]; wherearewe=tmp=cp1; cp2=*ecp2; @@ -854,7 +880,7 @@ static void pbx_substitute_variables_helper(struct ast_channel *c,char *cp1,char cp1=cp2; } if (count) { - pbx_substitute_variables_temp(c,cp1,&cp4); + pbx_substitute_variables_temp(c,cp1,&cp4, workspace, sizeof(workspace)); if (cp4) { /* reset output variable so we could store the result */ *cp2='\0'; @@ -1080,6 +1106,300 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte } +static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten) +{ + struct ast_exten *e; + struct ast_switch *sw; + char *data; + int status = 0; + char *incstack[AST_PBX_MAX_STACK]; + int stacklen = 0; + + if (ast_pthread_mutex_lock(&conlock)) { + ast_log(LOG_WARNING, "Unable to obtain lock\n"); + return NULL; + } + e = pbx_find_extension(c, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data); + ast_pthread_mutex_unlock(&conlock); + return e; +} + +static int ast_extension_state2(struct ast_exten *e) +{ + char hint[AST_MAX_EXTENSION] = ""; + char *cur, *rest; + int res = -1; + int allunavailable = 1, allbusy = 1, allfree = 1; + int busy = 0; + + strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1); + + cur = hint; + do { + rest = strchr(cur, '&'); + if (rest) { + *rest = 0; + rest++; + } + + res = ast_device_state(cur); + switch (res) { + case AST_DEVICE_NOT_INUSE: + allunavailable = 0; + allbusy = 0; + break; + case AST_DEVICE_INUSE: + return AST_EXTENSION_INUSE; + case AST_DEVICE_BUSY: + allunavailable = 0; + allfree = 0; + busy = 1; + break; + case AST_DEVICE_UNAVAILABLE: + case AST_DEVICE_INVALID: + allbusy = 0; + allfree = 0; + break; + default: + allunavailable = 0; + allbusy = 0; + allfree = 0; + } + cur = rest; + } while (cur); + + if (allfree) + return AST_EXTENSION_NOT_INUSE; + if (allbusy) + return AST_EXTENSION_BUSY; + if (allunavailable) + return AST_EXTENSION_UNAVAILABLE; + if (busy) + return AST_EXTENSION_INUSE; + + return AST_EXTENSION_NOT_INUSE; +} + + +int ast_extension_state(struct ast_channel *c, char *context, char *exten) +{ + struct ast_exten *e; + + e = ast_hint_extension(c, context, exten); + if (!e) + return -1; + + return ast_extension_state2(e); +} + +int ast_device_state_changed(char *device) +{ + struct ast_notify *list; + struct ast_notify_cb *cblist; + char hint[AST_MAX_EXTENSION]; + char *cur, *rest; + int state; + + pthread_mutex_lock(¬ifylock); + + list = notifys; + + while (list) { + + strcpy(hint, ast_get_extension_app(list->exten)); + cur = hint; + do { + rest = strchr(cur, '&'); + if (rest) { + *rest = 0; + rest++; + } + + if (!strncmp(cur, device, strlen(cur))) { + // Found extension execute callbacks + state = ast_extension_state2(list->exten); + if ((state != -1) && (state != list->laststate)) { + cblist = list->callbacks; + while (cblist) { + cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data); + cblist = cblist->next; + } + list->laststate = state; + } + break; + } + cur = rest; + } while (cur); + + list = list->next; + } + + pthread_mutex_unlock(¬ifylock); + return 1; +} + +int ast_extension_state_add(char *context, char *exten, + ast_notify_cb_type callback, void *data) +{ + struct ast_notify *list; + struct ast_notify_cb *cblist; + struct ast_exten *e; + + pthread_mutex_lock(¬ifylock); + list = notifys; + + while (list) { + if (!strcmp(list->exten->parent->name, context) && + !strcmp(list->exten->exten, exten)) + break; + list = list->next; + } + + if (!list) { + e = ast_hint_extension(NULL, context, exten); + if (!e) { + pthread_mutex_unlock(¬ifylock); + return -1; + } + list = malloc(sizeof(struct ast_notify)); + if (!list) { + pthread_mutex_unlock(¬ifylock); + return -1; + } + /* Initialize and insert new item */ + memset(list, 0, sizeof(struct ast_notify)); + list->exten = e; + list->laststate = -1; + list->next = notifys; + notifys = list; + } + + /* Now inserts the callback */ + cblist = malloc(sizeof(struct ast_notify_cb)); + if (!cblist) { + pthread_mutex_unlock(¬ifylock); + return -1; + } + memset(cblist, 0, sizeof(struct ast_notify_cb)); + cblist->id = notifycnt++; + cblist->callback = callback; + cblist->data = data; + + cblist->next = list->callbacks; + list->callbacks = cblist; + + pthread_mutex_unlock(¬ifylock); + return cblist->id; +} + +static int ast_extension_state_clean(struct ast_exten *e) +{ + /* Cleanup the Notifys if hint is removed */ + struct ast_notify *list, *prev = NULL; + struct ast_notify_cb *cblist, *cbprev; + + pthread_mutex_lock(¬ifylock); + + list = notifys; + while(list) { + if (list->exten==e) { + cbprev = NULL; + cblist = list->callbacks; + while (cblist) { + cbprev = cblist; + cblist = cblist->next; + cblist->callback(list->exten->parent->name, list->exten->exten, -1, cblist->data); + free(cbprev); + } + list->callbacks = NULL; + + if (!prev) { + notifys = list->next; + free(list); + list = notifys; + } else { + prev->next = list->next; + free(list); + list = prev->next; + } + } else { + prev = list; + list = list->next; + } + } + + pthread_mutex_unlock(¬ifylock); + return 1; +} + +int ast_extension_state_del(int id) +{ + struct ast_notify *list, *prev = NULL; + struct ast_notify_cb *cblist, *cbprev; + + pthread_mutex_lock(¬ifylock); + + list = notifys; + while (list) { + cblist = list->callbacks; + cbprev = NULL; + while (cblist) { + if (cblist->id==id) { + if (!cbprev) { + list->callbacks = cblist->next; + free(cblist); + cblist = list->callbacks; + } else { + cbprev->next = cblist->next; + free(cblist); + cblist = cbprev->next; + } + + if (!list->callbacks) { + if (!prev) { + notifys = list->next; + free(list); + list = notifys; + } else { + prev->next = list->next; + free(list); + list = prev->next; + } + } + break; + } else { + cbprev = cblist; + cblist = cblist->next; + } + } + + // we can have only one item + if (cblist) + break; + + prev = list; + list = list->next; + } + + pthread_mutex_unlock(¬ifylock); + if (list) + return 0; + else + return -1; + +} + +int ast_get_hint(char *hint, int maxlen, struct ast_channel *c, char *context, char *exten) +{ + struct ast_exten *e; + e = ast_hint_extension(c, context, exten); + if (e) { + strncpy(hint, ast_get_extension_app(e), maxlen); + return -1; + } + return 0; +} + int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid) { return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS); @@ -1544,6 +1864,9 @@ int ast_context_remove_extension2(struct ast_context *con, char *extension, int peer = exten; while (peer) { exten = peer->peer; + + if (!peer->priority==PRIORITY_HINT) + ast_extension_state_clean(peer); peer->datad(peer->data); free(peer); @@ -1589,6 +1912,8 @@ int ast_context_remove_extension2(struct ast_context *con, char *extension, int } /* now, free whole priority extension */ + if (peer->priority==PRIORITY_HINT) + ast_extension_state_clean(peer); peer->datad(peer->data); free(peer); @@ -2956,6 +3281,7 @@ int ast_add_extension2(struct ast_context *con, tmp->matchcid = 0; } strncpy(tmp->app, application, sizeof(tmp->app)-1); + tmp->parent = con; tmp->data = data; tmp->datad = datad; tmp->registrar = registrar; |