preserve hint watchers and laststate across 'extensions reload' (issue #2522)
authorKevin P. Fleming <kpfleming@digium.com>
Sat, 27 Aug 2005 23:55:14 +0000 (23:55 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Sat, 27 Aug 2005 23:55:14 +0000 (23:55 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6431 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c
include/asterisk/pbx.h
pbx.c

index f56f2fe..3170111 100755 (executable)
@@ -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 */
index b0ca14c..d54d3ef 100755 (executable)
@@ -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 fbce712..75c94ab 100755 (executable)
--- 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; 
 }