diff options
author | Kevin P. Fleming <kpfleming@digium.com> | 2005-08-27 23:55:14 +0000 |
---|---|---|
committer | Kevin P. Fleming <kpfleming@digium.com> | 2005-08-27 23:55:14 +0000 |
commit | 99929b21e47fb46df9be68cd3c3bf743e4c1aa83 (patch) | |
tree | 605762c7fa3a5ee1b627f5d611d12690568e9271 | |
parent | 601e4bb78a5859c58279a3fcb97cd381c59cceb0 (diff) |
preserve hint watchers and laststate across 'extensions reload' (issue #2522)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6431 65c4cc65-6c06-0410-ace0-fbb531ad65f3
-rwxr-xr-x | channels/chan_sip.c | 20 | ||||
-rwxr-xr-x | include/asterisk/pbx.h | 24 | ||||
-rwxr-xr-x | pbx.c | 89 |
3 files changed, 113 insertions, 20 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index f56f2fe88..317011140 100755 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -5733,20 +5733,24 @@ static int check_auth(struct sip_pvt *p, struct sip_request *req, char *randdata } /*--- cb_extensionstate: Part of thte SUBSCRIBE support subsystem ---*/ -static int cb_extensionstate(char *context, char* exten, int state, void *data) +static int cb_extensionstate(char *context, char* exten, enum ast_extension_states state, void *data) { struct sip_pvt *p = data; - if (state == -1) { + + switch (state) { + case AST_EXTENSION_DEACTIVATED: + case AST_EXTENSION_REMOVED: + transmit_state_notify(p, state, 1); sip_scheddestroy(p, 15000); p->stateid = -1; return 0; + default: + transmit_state_notify(p, state, 1); + + if (option_debug > 1) + ast_verbose(VERBOSE_PREFIX_1 "Extension Changed %s new state %d for Notify User %s\n", exten, state, p->username); + return 0; } - - transmit_state_notify(p, state, 1); - - if (option_debug > 1) - ast_verbose(VERBOSE_PREFIX_1 "Extension Changed %s new state %d for Notify User %s\n", exten, state, p->username); - return 0; } /*--- register_verify: Verify registration of user */ diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index b0ca14cc0..d54d3ef8e 100755 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -34,14 +34,20 @@ extern "C" { #define PRIORITY_HINT -1 /*! Extension states */ -/*! No device INUSE or BUSY */ -#define AST_EXTENSION_NOT_INUSE 0 -/*! One or more devices INUSE */ -#define AST_EXTENSION_INUSE 1 -/*! All devices BUSY */ -#define AST_EXTENSION_BUSY 2 -/*! All devices UNAVAILABLE/UNREGISTERED */ -#define AST_EXTENSION_UNAVAILABLE 3 +enum ast_extension_states { + /*! Extension removed */ + AST_EXTENSION_REMOVED = -2, + /*! Extension hint removed */ + AST_EXTENSION_DEACTIVATED = -1, + /*! No device INUSE or BUSY */ + AST_EXTENSION_NOT_INUSE = 0, + /*! One or more devices INUSE */ + AST_EXTENSION_INUSE = 1, + /*! All devices BUSY */ + AST_EXTENSION_BUSY = 2, + /*! All devices UNAVAILABLE/UNREGISTERED */ + AST_EXTENSION_UNAVAILABLE = 3, +}; struct ast_context; struct ast_exten; @@ -49,7 +55,7 @@ struct ast_include; struct ast_ignorepat; struct ast_sw; -typedef int (*ast_state_cb_type)(char *context, char* id, int state, void *data); +typedef int (*ast_state_cb_type)(char *context, char* id, enum ast_extension_states state, void *data); /*! Data structure associated with a custom function */ struct ast_custom_function { @@ -2077,7 +2077,7 @@ static int ast_remove_hint(struct ast_exten *e) /* Notify with -1 and remove all callbacks */ cbprev = cblist; cblist = cblist->next; - cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data); + cbprev->callback(list->exten->parent->name, list->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data); free(cbprev); } list->callbacks = NULL; @@ -3014,6 +3014,8 @@ static int handle_show_hints(int fd, int argc, char *argv[]) { struct ast_hint *hint; int num = 0; + int watchers; + struct ast_state_cb *watcher; if (!hints) { ast_cli(fd, "There are no registered dialplan hints\n"); @@ -3027,7 +3029,12 @@ static int handle_show_hints(int fd, int argc, char *argv[]) } hint = hints; while (hint) { - ast_cli(fd, " %-20.20s: %-20.20s State %2d\n", ast_get_extension_name(hint->exten), ast_get_extension_app(hint->exten), hint->laststate ); + watchers = 0; + for (watcher = hint->callbacks; watcher; watcher = watcher->next) + watchers++; + ast_cli(fd, " %-20.20s: %-20.20s State %2d Watchers %2d\n", + ast_get_extension_name(hint->exten), ast_get_extension_app(hint->exten), + hint->laststate, watchers); num++; hint = hint->next; } @@ -3542,8 +3549,50 @@ struct ast_context *ast_context_create(struct ast_context **extcontexts, const c void __ast_context_destroy(struct ast_context *con, const char *registrar); -void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar) { +struct store_hint { + char *context; + char *exten; + struct ast_state_cb *callbacks; + int laststate; + AST_LIST_ENTRY(store_hint) list; + char data[1]; +}; + +AST_LIST_HEAD(store_hints, store_hint); + +void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar) +{ struct ast_context *tmp, *lasttmp = NULL; + struct store_hints store; + struct store_hint *this; + struct ast_hint *hint; + struct ast_exten *exten; + int length; + struct ast_state_cb *thiscb, *prevcb; + + /* preserve all watchers for hints associated with this registrar */ + AST_LIST_HEAD_INIT(&store); + ast_mutex_lock(&hintlock); + for (hint = hints; hint; hint = hint->next) { + if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) { + length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this); + this = calloc(1, length); + if (!this) { + ast_log(LOG_WARNING, "Could not allocate memory to preserve hint\n"); + continue; + } + this->callbacks = hint->callbacks; + hint->callbacks = NULL; + this->laststate = hint->laststate; + this->context = this->data; + strcpy(this->data, hint->exten->parent->name); + this->exten = this->data + strlen(this->context) + 1; + strcpy(this->exten, hint->exten->exten); + AST_LIST_INSERT_HEAD(&store, this, list); + } + } + ast_mutex_unlock(&hintlock); + tmp = *extcontexts; ast_mutex_lock(&conlock); if (registrar) { @@ -3566,6 +3615,40 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char } else ast_log(LOG_WARNING, "Requested contexts didn't get merged\n"); ast_mutex_unlock(&conlock); + + /* restore the watchers for hints that can be found; notify those that + cannot be restored + */ + while ((this = AST_LIST_REMOVE_HEAD(&store, list))) { + exten = ast_hint_extension(NULL, this->context, this->exten); + /* Find the hint in the list of hints */ + ast_mutex_lock(&hintlock); + for (hint = hints; hint; hint = hint->next) { + if (hint->exten == exten) + break; + } + if (!exten || !hint) { + /* this hint has been removed, notify the watchers */ + prevcb = NULL; + thiscb = this->callbacks; + while (thiscb) { + prevcb = thiscb; + thiscb = thiscb->next; + prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data); + free(prevcb); + } + } else { + thiscb = this->callbacks; + while (thiscb->next) + thiscb = thiscb->next; + thiscb->next = hint->callbacks; + hint->callbacks = this->callbacks; + hint->laststate = this->laststate; + } + ast_mutex_unlock(&hintlock); + free(this); + } + return; } |