summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin P. Fleming <kpfleming@digium.com>2005-08-27 23:55:14 +0000
committerKevin P. Fleming <kpfleming@digium.com>2005-08-27 23:55:14 +0000
commit99929b21e47fb46df9be68cd3c3bf743e4c1aa83 (patch)
tree605762c7fa3a5ee1b627f5d611d12690568e9271
parent601e4bb78a5859c58279a3fcb97cd381c59cceb0 (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-xchannels/chan_sip.c20
-rwxr-xr-xinclude/asterisk/pbx.h24
-rwxr-xr-xpbx.c89
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 {
diff --git a/pbx.c b/pbx.c
index fbce71238..75c94ab76 100755
--- a/pbx.c
+++ b/pbx.c
@@ -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;
}