SS7 marked the start of an open season for trunk again but here's something minor...
[asterisk/asterisk.git] / main / channel.c
index 248cf15..3df9191 100644 (file)
@@ -288,18 +288,32 @@ static char *complete_channeltypes(const char *line, const char *word, int pos,
 }
 
 static char show_channeltypes_usage[] =
-"Usage: show channeltypes\n"
-"       Shows available channel types registered in your Asterisk server.\n";
+"Usage: channeltype list\n"
+"       Lists available channel types registered in your Asterisk server.\n";
 
 static char show_channeltype_usage[] =
-"Usage: show channeltype <name>\n"
+"Usage: channeltype show <name>\n"
 "      Show details about the specified channel type, <name>.\n";
 
-static struct ast_cli_entry cli_show_channeltypes =
-       { { "show", "channeltypes", NULL }, show_channeltypes, "Show available channel types", show_channeltypes_usage };
+static struct ast_cli_entry cli_show_channeltypes_deprecated = {
+       { "show", "channeltypes", NULL },
+       show_channeltypes, NULL,
+       NULL };
 
-static struct ast_cli_entry cli_show_channeltype =
-       { { "show", "channeltype", NULL }, show_channeltype, "Give more details on that channel type", show_channeltype_usage, complete_channeltypes };
+static struct ast_cli_entry cli_show_channeltype_deprecated = {
+       { "show", "channeltype", NULL },
+       show_channeltype, NULL,
+       NULL, complete_channeltypes };
+
+static struct ast_cli_entry cli_channel[] = {
+       { { "channeltype", "list", NULL },
+       show_channeltypes, "List available channel types",
+       show_channeltypes_usage, NULL, &cli_show_channeltypes_deprecated },
+
+       { { "channeltype", "show", NULL },
+       show_channeltype, "Give more details on that channel type",
+       show_channeltype_usage, complete_channeltypes, &cli_show_channeltype_deprecated },
+};
 
 /*! \brief Checks to see if a channel is needing hang up */
 int ast_check_hangup(struct ast_channel *chan)
@@ -1203,22 +1217,61 @@ int ast_channel_spy_add(struct ast_channel *chan, struct ast_channel_spy *spy)
        return 0;
 }
 
+/* Clean up a channel's spy information */
+static void spy_cleanup(struct ast_channel *chan)
+{
+       if (!AST_LIST_EMPTY(&chan->spies->list))
+               return;
+       if (chan->spies->read_translator.path)
+               ast_translator_free_path(chan->spies->read_translator.path);
+       if (chan->spies->write_translator.path)
+               ast_translator_free_path(chan->spies->write_translator.path);
+       free(chan->spies);
+       chan->spies = NULL;
+       return;
+}
+
+/* Detach a spy from it's channel */
+static void spy_detach(struct ast_channel_spy *spy, struct ast_channel *chan)
+{
+       ast_mutex_lock(&spy->lock);
+
+       /* We only need to poke them if they aren't already done */
+       if (spy->status != CHANSPY_DONE) {
+               /* Indicate to the spy to stop */
+               spy->status = CHANSPY_STOP;
+               spy->chan = NULL;
+               /* Poke the spy if needed */
+               if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE)
+                       ast_cond_signal(&spy->trigger);
+       }
+
+       /* Print it out while we still have a lock so the structure can't go away (if signalled above) */
+       ast_log(LOG_DEBUG, "Spy %s removed from channel %s\n", spy->type, chan->name);
+
+       ast_mutex_unlock(&spy->lock);
+
+       return;
+}
+
 void ast_channel_spy_stop_by_type(struct ast_channel *chan, const char *type)
 {
-       struct ast_channel_spy *spy;
+       struct ast_channel_spy *spy = NULL;
        
        if (!chan->spies)
                return;
 
-       AST_LIST_TRAVERSE(&chan->spies->list, spy, list) {
+       AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->spies->list, spy, list) {
                ast_mutex_lock(&spy->lock);
                if ((spy->type == type) && (spy->status == CHANSPY_RUNNING)) {
-                       spy->status = CHANSPY_STOP;
-                       if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE)
-                               ast_cond_signal(&spy->trigger);
-               }
-               ast_mutex_unlock(&spy->lock);
+                       ast_mutex_unlock(&spy->lock);
+                       AST_LIST_REMOVE_CURRENT(&chan->spies->list, list);
+                       spy_detach(spy, chan);
+               } else
+                       ast_mutex_unlock(&spy->lock);
        }
+       AST_LIST_TRAVERSE_SAFE_END
+       spy_cleanup(chan);
 }
 
 void ast_channel_spy_trigger_wait(struct ast_channel_spy *spy)
@@ -1235,62 +1288,54 @@ void ast_channel_spy_trigger_wait(struct ast_channel_spy *spy)
 
 void ast_channel_spy_remove(struct ast_channel *chan, struct ast_channel_spy *spy)
 {
-       struct ast_frame *f;
-
        if (!chan->spies)
                return;
 
        AST_LIST_REMOVE(&chan->spies->list, spy, list);
+       spy_detach(spy, chan);
+       spy_cleanup(chan);
+}
 
-       ast_mutex_lock(&spy->lock);
+void ast_channel_spy_free(struct ast_channel_spy *spy)
+{
+       struct ast_frame *f = NULL;
+
+       if (spy->status == CHANSPY_DONE)
+               return;
 
-       spy->chan = NULL;
+       /* Switch status to done in case we get called twice */
+       spy->status = CHANSPY_DONE;
 
-       while ((f = AST_LIST_REMOVE_HEAD(&spy->read_queue.list, frame_list)))
-               ast_frfree(f);
-       
+       /* Drop any frames in the queue */
        while ((f = AST_LIST_REMOVE_HEAD(&spy->write_queue.list, frame_list)))
                ast_frfree(f);
+       while ((f = AST_LIST_REMOVE_HEAD(&spy->read_queue.list, frame_list)))
+               ast_frfree(f);
 
+       /* Destroy the condition if in use */
        if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE)
                ast_cond_destroy(&spy->trigger);
 
-       ast_mutex_unlock(&spy->lock);
-
-       ast_log(LOG_DEBUG, "Spy %s removed from channel %s\n",
-               spy->type, chan->name);
+       /* Destroy our mutex since it is no longer in use */
+       ast_mutex_destroy(&spy->lock);
 
-       if (AST_LIST_EMPTY(&chan->spies->list)) {
-               if (chan->spies->read_translator.path)
-                       ast_translator_free_path(chan->spies->read_translator.path);
-               if (chan->spies->write_translator.path)
-                       ast_translator_free_path(chan->spies->write_translator.path);
-               free(chan->spies);
-               chan->spies = NULL;
-       }
+       return;
 }
 
 static void detach_spies(struct ast_channel *chan)
 {
-       struct ast_channel_spy *spy;
+       struct ast_channel_spy *spy = NULL;
 
        if (!chan->spies)
                return;
 
-       /* Marking the spies as done is sufficient.  Chanspy or spy users will get the picture. */
-       AST_LIST_TRAVERSE(&chan->spies->list, spy, list) {
-               ast_mutex_lock(&spy->lock);
-               spy->chan = NULL;
-               if (spy->status == CHANSPY_RUNNING)
-                       spy->status = CHANSPY_DONE;
-               if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE)
-                       ast_cond_signal(&spy->trigger);
-               ast_mutex_unlock(&spy->lock);
+       AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->spies->list, spy, list) {
+               AST_LIST_REMOVE_CURRENT(&chan->spies->list, list);
+               spy_detach(spy, chan);
        }
+       AST_LIST_TRAVERSE_SAFE_END
 
-       AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->spies->list, spy, list)
-               ast_channel_spy_remove(chan, spy);
-       AST_LIST_TRAVERSE_SAFE_END;
+       spy_cleanup(chan);
 }
 
 /*! \brief Softly hangup a channel, don't lock */
@@ -1366,16 +1411,14 @@ static void queue_frame_to_spies(struct ast_channel *chan, struct ast_frame *f,
                                }
                        }
                        duped_fr = ast_frdup(translated_frame);
-               } else {
-                       if (f->subclass != queue->format) {
-                               ast_log(LOG_WARNING, "Spy '%s' on channel '%s' wants format '%s', but frame is '%s', dropping\n",
-                                       spy->type, chan->name,
-                                       ast_getformatname(queue->format), ast_getformatname(f->subclass));
-                               ast_mutex_unlock(&spy->lock);
-                               continue;
-                       }
+               } else if (f->subclass != queue->format) {
+                       ast_log(LOG_WARNING, "Spy '%s' on channel '%s' wants format '%s', but frame is '%s', dropping\n",
+                               spy->type, chan->name,
+                               ast_getformatname(queue->format), ast_getformatname(f->subclass));
+                       ast_mutex_unlock(&spy->lock);
+                       continue;
+               } else
                        duped_fr = ast_frdup(f);
-               }
 
                AST_LIST_INSERT_TAIL(&queue->list, duped_fr, frame_list);
 
@@ -1691,7 +1734,7 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
        /* Wait full interval */
        rms = *ms;
        if (whentohangup) {
-               rms = (whentohangup - now) * 1000;      /* timeout in milliseconds */
+               rms = whentohangup * 1000;              /* timeout in milliseconds */
                if (*ms >= 0 && *ms < rms)              /* original *ms still smaller */
                        rms =  *ms;
        }
@@ -2585,7 +2628,7 @@ static int set_format(struct ast_channel *chan, int fmt, int *rawformat, int *fo
        /* Now we have a good choice for both. */
        ast_channel_lock(chan);
 
-       if ((*rawformat == native) && (*format == fmt)) {
+       if ((*rawformat == native) && (*format == fmt) && ((*rawformat == *format) || (*trans))) {
                /* the channel is already in these formats, so nothing to do */
                ast_channel_unlock(chan);
                return 0;
@@ -3125,6 +3168,8 @@ int ast_do_masquerade(struct ast_channel *original)
        void *t_pvt;
        struct ast_callerid tmpcid;
        struct ast_channel *clone = original->masq;
+       struct ast_channel_spy_list *spy_list = NULL;
+       struct ast_channel_spy *spy = NULL;
        int rformat = original->readformat;
        int wformat = original->writeformat;
        char newn[100];
@@ -3203,6 +3248,27 @@ int ast_do_masquerade(struct ast_channel *original)
        original->rawwriteformat = clone->rawwriteformat;
        clone->rawwriteformat = x;
 
+       /* Swap the spies */
+       spy_list = original->spies;
+       original->spies = clone->spies;
+       clone->spies = spy_list;
+
+       /* Update channel on respective spy lists if present */
+       if (original->spies) {
+               AST_LIST_TRAVERSE(&original->spies->list, spy, list) {
+                       ast_mutex_lock(&spy->lock);
+                       spy->chan = original;
+                       ast_mutex_unlock(&spy->lock);
+               }
+       }
+       if (clone->spies) {
+               AST_LIST_TRAVERSE(&clone->spies->list, spy, list) {
+                       ast_mutex_lock(&spy->lock);
+                       spy->chan = clone;
+                       ast_mutex_unlock(&spy->lock);
+               }
+       }
+
        /* Save any pending frames on both sides.  Start by counting
         * how many we're going to need... */
        x = 0;
@@ -3609,6 +3675,16 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
        return res;
 }
 
+/*! \brief Bridge two channels together (early) */
+int ast_channel_early_bridge(struct ast_channel *c0, struct ast_channel *c1)
+{
+       /* Make sure we can early bridge, if not error out */
+       if (!c0->tech->early_bridge || (c1 && (!c1->tech->early_bridge || c0->tech->early_bridge != c1->tech->early_bridge)))
+               return -1;
+
+       return c0->tech->early_bridge(c0, c1);
+}
+
 /*! \brief Bridge two channels together */
 enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1,
                                          struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc)
@@ -4097,8 +4173,7 @@ void ast_moh_cleanup(struct ast_channel *chan)
 
 void ast_channels_init(void)
 {
-       ast_cli_register(&cli_show_channeltypes);
-       ast_cli_register(&cli_show_channeltype);
+       ast_cli_register_multiple(cli_channel, sizeof(cli_channel) / sizeof(struct ast_cli_entry));
 }
 
 /*! \brief Print call group and pickup group ---*/