This mod via bug 7531
[asterisk/asterisk.git] / main / channel.c
index 66649bc..ace4a41 100644 (file)
@@ -29,6 +29,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #include <string.h>
 #include <sys/time.h>
 #include <signal.h>
@@ -84,6 +85,7 @@ struct ast_channel_whisper_buffer {
        ast_mutex_t lock;
        struct ast_slinfactory sf;
        unsigned int original_format;
+       struct ast_trans_pvt *path;
 };
 
 /* uncomment if you have problems with 'monitoring' synchronized files */
@@ -99,9 +101,12 @@ static int uniqueint = 0;
 
 unsigned long global_fin = 0, global_fout = 0;
 
-AST_THREADSTORAGE(state2str_threadbuf, state2str_threadbuf_init);
+AST_THREADSTORAGE(state2str_threadbuf);
 #define STATE2STR_BUFSIZE   32
 
+/* XXX 100ms ... this won't work with wideband support */
+#define AST_DEFAULT_EMULATE_DTMF_SAMPLES 800
+
 struct chanlist {
        const struct ast_channel_tech *tech;
        AST_LIST_ENTRY(chanlist) list;
@@ -240,7 +245,8 @@ static int show_channeltype(int fd, int argc, char *argv[])
                "    Indication: %s\n"
                "     Transfer : %s\n"
                "  Capabilities: %d\n"
-               "    Send Digit: %s\n"
+               "   Digit Begin: %s\n"
+               "     Digit End: %s\n"
                "    Send HTML : %s\n"
                " Image Support: %s\n"
                "  Text Support: %s\n",
@@ -249,7 +255,8 @@ static int show_channeltype(int fd, int argc, char *argv[])
                (cl->tech->indicate) ? "yes" : "no",
                (cl->tech->transfer) ? "yes" : "no",
                (cl->tech->capabilities) ? cl->tech->capabilities : -1,
-               (cl->tech->send_digit) ? "yes" : "no",
+               (cl->tech->send_digit_begin) ? "yes" : "no",
+               (cl->tech->send_digit_end) ? "yes" : "no",
                (cl->tech->send_html) ? "yes" : "no",
                (cl->tech->send_image) ? "yes" : "no",
                (cl->tech->send_text) ? "yes" : "no"
@@ -283,18 +290,22 @@ 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: core show channeltypes\n"
+"       Lists available channel types registered in your Asterisk server.\n";
 
 static char show_channeltype_usage[] =
-"Usage: show channeltype <name>\n"
+"Usage: core show channeltype <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_channel[] = {
+       { { "core", "show", "channeltypes", NULL },
+       show_channeltypes, "List available channel types",
+       show_channeltypes_usage },
 
-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 };
+       { { "core", "show", "channeltype", NULL },
+       show_channeltype, "Give more details on that channel type",
+       show_channeltype_usage, complete_channeltypes },
+};
 
 /*! \brief Checks to see if a channel is needing hang up */
 int ast_check_hangup(struct ast_channel *chan)
@@ -320,6 +331,21 @@ static int ast_check_hangup_locked(struct ast_channel *chan)
        return res;
 }
 
+/*! \brief printf the string into a correctly sized mallocd buffer, and return the buffer */
+char *ast_safe_string_alloc(const char *fmt, ...)
+{
+       char *b2,buf[1];
+       int len;
+
+       va_list args;
+       va_start(args, fmt);
+       len = vsnprintf(buf, 1, fmt, args);
+       b2 = ast_malloc(len+1);
+       vsnprintf(b2, len+1,  fmt, args);
+       va_end(args);
+       return b2;
+}
+
 /*! \brief Initiate system shutdown */
 void ast_begin_shutdown(int hangup)
 {
@@ -598,12 +624,13 @@ static const struct ast_channel_tech null_tech = {
 };
 
 /*! \brief Create a new channel structure */
-struct ast_channel *ast_channel_alloc(int needqueue)
+struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_num, const char *cid_name, const char *name_fmt, ...)
 {
        struct ast_channel *tmp;
        int x;
        int flags;
        struct varshead *headp;
+       va_list ap1, ap2;
 
        /* If shutting down, don't allocate any new channels */
        if (shutting_down) {
@@ -644,7 +671,7 @@ struct ast_channel *ast_channel_alloc(int needqueue)
        if (needqueue) {
                if (pipe(tmp->alertpipe)) {
                        ast_log(LOG_WARNING, "Channel allocation failed: Can't create alert pipe!\n");
-                       ast_string_field_free_all(tmp);
+                       ast_string_field_free_pools(tmp);
                        free(tmp);
                        return NULL;
                } else {
@@ -661,10 +688,10 @@ struct ast_channel *ast_channel_alloc(int needqueue)
        /* And timing pipe */
        tmp->fds[AST_TIMING_FD] = tmp->timingfd;
        ast_string_field_set(tmp, name, "**Unknown**");
-       
+
        /* Initial state */
-       tmp->_state = AST_STATE_DOWN;
-       
+       tmp->_state = state;
+
        tmp->streamid = -1;
        
        tmp->fin = global_fin;
@@ -678,6 +705,37 @@ struct ast_channel *ast_channel_alloc(int needqueue)
                        (long) time(NULL), ast_atomic_fetchadd_int(&uniqueint, 1));
        }
 
+       if (!ast_strlen_zero(name_fmt)) {
+               /* Almost every channel is calling this function, and setting the name via the ast_string_field_build() call.
+                * And they all use slightly different formats for their name string.
+                * This means, to set the name here, we have to accept variable args, and call the string_field_build from here.
+                * This means, that the stringfields must have a routine that takes the va_lists directly, and 
+                * uses them to build the string, instead of forming the va_lists internally from the vararg ... list.
+                * This new function was written so this can be accomplished.
+                */
+               va_start(ap1, name_fmt);
+               va_start(ap2, name_fmt);
+               ast_string_field_build_va(tmp, name, name_fmt, ap1, ap2);
+               va_end(ap1);
+               va_end(ap2);
+
+               /* and now, since the channel structure is built, and has its name, let's call the
+                * manager event generator with this Newchannel event. This is the proper and correct
+                * place to make this call, but you sure do have to pass a lot of data into this func
+                * to do it here!
+                */
+               manager_event(EVENT_FLAG_CALL, "Newchannel",
+                             "Channel: %s\r\n"
+                             "State: %s\r\n"
+                             "CallerIDNum: %s\r\n"
+                             "CallerIDName: %s\r\n"
+                             "Uniqueid: %s\r\n",
+                             tmp->name, ast_state2str(state),
+                             S_OR(cid_num, "<unknown>"),
+                             S_OR(cid_name, "<unknown>"),
+                             tmp->uniqueid);
+       }
+       
        headp = &tmp->varshead;
        AST_LIST_HEAD_INIT_NOLOCK(headp);
        
@@ -706,7 +764,7 @@ struct ast_channel *ast_channel_alloc(int needqueue)
 int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin)
 {
        struct ast_frame *f;
-       struct ast_frame *prev, *cur;
+       struct ast_frame *cur;
        int blah = 1;
        int qlen = 0;
 
@@ -716,33 +774,33 @@ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin)
                return -1;
        }
        ast_channel_lock(chan);
-       prev = NULL;
-       for (cur = chan->readq; cur; cur = cur->next) {
-               if ((cur->frametype == AST_FRAME_CONTROL) && (cur->subclass == AST_CONTROL_HANGUP)) {
-                       /* Don't bother actually queueing anything after a hangup */
-                       ast_frfree(f);
-                       ast_channel_unlock(chan);
-                       return 0;
-               }
-               prev = cur;
+
+       /* See if the last frame on the queue is a hangup, if so don't queue anything */
+       if ((cur = AST_LIST_LAST(&chan->readq)) && (cur->frametype == AST_FRAME_CONTROL) && (cur->subclass == AST_CONTROL_HANGUP)) {
+               ast_frfree(f);
+               ast_channel_unlock(chan);
+               return 0;
+       }
+
+       /* Count how many frames exist on the queue */
+       AST_LIST_TRAVERSE(&chan->readq, cur, frame_list) {
                qlen++;
        }
+
        /* Allow up to 96 voice frames outstanding, and up to 128 total frames */
        if (((fin->frametype == AST_FRAME_VOICE) && (qlen > 96)) || (qlen  > 128)) {
                if (fin->frametype != AST_FRAME_VOICE) {
                        ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
                        CRASH;
                } else {
-                       ast_log(LOG_DEBUG, "Dropping voice to exceptionally long queue on %s\n", chan->name);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Dropping voice to exceptionally long queue on %s\n", chan->name);
                        ast_frfree(f);
                        ast_channel_unlock(chan);
                        return 0;
                }
        }
-       if (prev)
-               prev->next = f;
-       else
-               chan->readq = f;
+       AST_LIST_INSERT_TAIL(&chan->readq, f, frame_list);
        if (chan->alertpipe[1] > -1) {
                if (write(chan->alertpipe[1], &blah, sizeof(blah)) != sizeof(blah))
                        ast_log(LOG_WARNING, "Unable to write to alert pipe on %s, frametype/subclass %d/%d (qlen = %d): %s!\n",
@@ -872,8 +930,10 @@ static struct ast_channel *channel_find_locked(const struct ast_channel *prev,
                /* exit if chan not found or mutex acquired successfully */
                /* this is slightly unsafe, as we _should_ hold the lock to access c->name */
                done = c == NULL || ast_channel_trylock(c) == 0;
-               if (!done)
-                       ast_log(LOG_DEBUG, "Avoiding %s for channel '%p'\n", msg, c);
+               if (!done) {
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Avoiding %s for channel '%p'\n", msg, c);
+               }
                AST_LIST_UNLOCK(&channels);
                if (done)
                        return c;
@@ -883,8 +943,9 @@ static struct ast_channel *channel_find_locked(const struct ast_channel *prev,
         * c is surely not null, but we don't have the lock so cannot
         * access c->name
         */
-       ast_log(LOG_DEBUG, "Failure, could not lock '%p' after %d retries!\n",
-               c, retries);
+       if (option_debug)
+               ast_log(LOG_DEBUG, "Failure, could not lock '%p' after %d retries!\n",
+                       c, retries);
 
        return NULL;
 }
@@ -973,7 +1034,7 @@ void ast_channel_free(struct ast_channel *chan)
 {
        int fd;
        struct ast_var_t *vardata;
-       struct ast_frame *f, *fp;
+       struct ast_frame *f;
        struct varshead *headp;
        struct ast_datastore *datastore = NULL;
        char name[AST_CHANNEL_NAME];
@@ -1024,13 +1085,8 @@ void ast_channel_free(struct ast_channel *chan)
                close(fd);
        if ((fd = chan->timingfd) > -1)
                close(fd);
-       f = chan->readq;
-       chan->readq = NULL;
-       while(f) {
-               fp = f;
-               f = f->next;
-               ast_frfree(fp);
-       }
+       while ((f = AST_LIST_REMOVE_HEAD(&chan->readq, frame_list)))
+               ast_frfree(f);
        
        /* Get rid of each of the data stores on the channel */
        while ((datastore = AST_LIST_REMOVE_HEAD(&chan->datastores, entry)))
@@ -1047,7 +1103,7 @@ void ast_channel_free(struct ast_channel *chan)
        /* Destroy the jitterbuffer */
        ast_jb_destroy(chan);
 
-       ast_string_field_free_all(chan);
+       ast_string_field_free_pools(chan);
        free(chan);
        AST_LIST_UNLOCK(&channels);
 
@@ -1198,28 +1254,69 @@ int ast_channel_spy_add(struct ast_channel *chan, struct ast_channel_spy *spy)
                ast_clear_flag(spy, CHANSPY_TRIGGER_WRITE);
        }
 
-       ast_log(LOG_DEBUG, "Spy %s added to channel %s\n",
-               spy->type, chan->name);
+       if (option_debug)
+               ast_log(LOG_DEBUG, "Spy %s added to channel %s\n",
+                       spy->type, chan->name);
 
        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) */
+       if (option_debug)
+               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)
@@ -1236,65 +1333,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;
 
-       spy->chan = NULL;
+       if (spy->status == CHANSPY_DONE)
+               return;
+
+       /* Switch status to done in case we get called twice */
+       spy->status = CHANSPY_DONE;
 
-       for (f = spy->read_queue.head; f; f = spy->read_queue.head) {
-               spy->read_queue.head = f->next;
+       /* Drop any frames in the queue */
+       while ((f = AST_LIST_REMOVE_HEAD(&spy->write_queue.list, frame_list)))
                ast_frfree(f);
-       }
-       for (f = spy->write_queue.head; f; f = spy->write_queue.head) {
-               spy->write_queue.head = f->next;
+       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 */
@@ -1337,9 +1423,8 @@ static void queue_frame_to_spies(struct ast_channel *chan, struct ast_frame *f,
        trans = (dir == SPY_READ) ? &chan->spies->read_translator : &chan->spies->write_translator;
 
        AST_LIST_TRAVERSE(&chan->spies->list, spy, list) {
-               struct ast_frame *last;
-               struct ast_frame *f1;   /* the frame to append */
                struct ast_channel_spy_queue *queue;
+               struct ast_frame *duped_fr;
 
                ast_mutex_lock(&spy->lock);
 
@@ -1352,8 +1437,9 @@ static void queue_frame_to_spies(struct ast_channel *chan, struct ast_frame *f,
                                        trans->path = NULL;
                                }
                                if (!trans->path) {
-                                       ast_log(LOG_DEBUG, "Building translator from %s to SLINEAR for spies on channel %s\n",
-                                               ast_getformatname(f->subclass), chan->name);
+                                       if (option_debug)
+                                               ast_log(LOG_DEBUG, "Building translator from %s to SLINEAR for spies on channel %s\n",
+                                                       ast_getformatname(f->subclass), chan->name);
                                        if ((trans->path = ast_translator_build_path(AST_FORMAT_SLINEAR, f->subclass)) == NULL) {
                                                ast_log(LOG_WARNING, "Cannot build a path from %s to %s\n",
                                                        ast_getformatname(f->subclass), ast_getformatname(AST_FORMAT_SLINEAR));
@@ -1370,26 +1456,17 @@ static void queue_frame_to_spies(struct ast_channel *chan, struct ast_frame *f,
                                        break;
                                }
                        }
-                       f1 = 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;
-                       }
-                       f1 = f;
-               }
-               /* duplicate and append f1 to the tail */
-               f1 = ast_frdup(f1);
+                       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
+                       duped_fr = ast_frdup(f);
 
-               for (last = queue->head; last && last->next; last = last->next)
-                       ;
-               if (last)
-                       last->next = f1;
-               else
-                       queue->head = f1;
+               AST_LIST_INSERT_TAIL(&queue->list, duped_fr, frame_list);
 
                queue->samples += f->samples;
 
@@ -1425,10 +1502,8 @@ static void queue_frame_to_spies(struct ast_channel *chan, struct ast_frame *f,
                                        ast_log(LOG_DEBUG, "Spy '%s' on channel '%s' %s queue too long, dropping frames\n",
                                                spy->type, chan->name, (dir == SPY_READ) ? "read" : "write");
                                while (queue->samples > SPY_QUEUE_SAMPLE_LIMIT) {
-                                       struct ast_frame *drop = queue->head;
-                                       
+                                       struct ast_frame *drop = AST_LIST_REMOVE_HEAD(&queue->list, frame_list);
                                        queue->samples -= drop->samples;
-                                       queue->head = drop->next;
                                        ast_frfree(drop);
                                }
                        }
@@ -1608,7 +1683,8 @@ static int generator_force(void *data)
        res = generate(chan, tmp, 0, 160);
        chan->generatordata = tmp;
        if (res) {
-               ast_log(LOG_DEBUG, "Auto-deactivating generator\n");
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "Auto-deactivating generator\n");
                ast_deactivate_generator(chan);
        }
        return 0;
@@ -1705,7 +1781,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;
        }
@@ -1827,7 +1903,8 @@ int ast_settimeout(struct ast_channel *c, int samples, int (*func)(void *data),
                        samples = 0;
                        data = 0;
                }
-               ast_log(LOG_DEBUG, "Scheduling timer at %d sample intervals\n", samples);
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "Scheduling timer at %d sample intervals\n", samples);
                res = ioctl(c->timingfd, ZT_TIMERCONFIG, &samples);
                c->timingfunc = func;
                c->timingdata = data;
@@ -1879,13 +1956,17 @@ int ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int cmdfd)
                                        break;
                                default:
                                        ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", f->subclass);
+                                       break;
                                }
+                               break;
                        case AST_FRAME_VOICE:
                                /* Write audio if appropriate */
                                if (audiofd > -1)
                                        write(audiofd, f->data, f->datalen);
+                       default:
+                               /* Ignore */
+                               break;
                        }
-                       /* Ignore */
                        ast_frfree(f);
                }
        }
@@ -1903,11 +1984,10 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
         */
        ast_channel_lock(chan);
        if (chan->masq) {
-               if (ast_do_masquerade(chan)) {
+               if (ast_do_masquerade(chan))
                        ast_log(LOG_WARNING, "Failed to perform masquerade\n");
-               } else {
+               else
                        f =  &ast_null_frame;
-               }
                goto done;
        }
 
@@ -1919,13 +1999,17 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
        }
        prestate = chan->_state;
 
-       if (!ast_test_flag(chan, AST_FLAG_DEFER_DTMF) && !ast_strlen_zero(chan->dtmfq)) {
+       if (!ast_test_flag(chan, AST_FLAG_DEFER_DTMF | AST_FLAG_EMULATE_DTMF | AST_FLAG_IN_DTMF) && 
+           !ast_strlen_zero(chan->dtmfq)) {
                /* We have DTMF that has been deferred.  Return it now */
-               chan->dtmff.frametype = AST_FRAME_DTMF;
+               chan->dtmff.frametype = AST_FRAME_DTMF_BEGIN;
                chan->dtmff.subclass = chan->dtmfq[0];
                /* Drop first digit from the buffer */
                memmove(chan->dtmfq, chan->dtmfq + 1, sizeof(chan->dtmfq) - 1);
                f = &chan->dtmff;
+               ast_set_flag(chan, AST_FLAG_EMULATE_DTMF);
+               chan->emulate_dtmf_digit = f->subclass;
+               chan->emulate_dtmf_samples = AST_DEFAULT_EMULATE_DTMF_SAMPLES;
                goto done;
        }
        
@@ -1946,7 +2030,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                        blah = ZT_EVENT_TIMER_EXPIRED;
 
                if (blah == ZT_EVENT_TIMER_PING) {
-                       if (!chan->readq || !chan->readq->next) {
+                       if (AST_LIST_EMPTY(&chan->readq) || !AST_LIST_NEXT(AST_LIST_FIRST(&chan->readq), frame_list)) {
                                /* Acknowledge PONG unless we need it again */
                                if (ioctl(chan->timingfd, ZT_TIMERPONG, &blah)) {
                                        ast_log(LOG_WARNING, "Failed to pong timer on '%s': %s\n", chan->name, strerror(errno));
@@ -1985,10 +2069,8 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
        }
 
        /* Check for pending read queue */
-       if (chan->readq) {
-               f = chan->readq;
-               chan->readq = f->next;
-               f->next = NULL;
+       if (!AST_LIST_EMPTY(&chan->readq)) {
+               f = AST_LIST_REMOVE_HEAD(&chan->readq, frame_list);
                /* Interpret hangup and return NULL */
                /* XXX why not the same for frames from the channel ? */
                if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP) {
@@ -2014,22 +2096,26 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
 
        if (f) {
                /* if the channel driver returned more than one frame, stuff the excess
-                  into the readq for the next ast_read call
+                  into the readq for the next ast_read call (note that we can safely assume
+                  that the readq is empty, because otherwise we would not have called into
+                  the channel driver and f would be only a single frame)
                */
-               if (f->next) {
-                       chan->readq = f->next;
-                       f->next = NULL;
+               if (AST_LIST_NEXT(f, frame_list)) {
+                       AST_LIST_HEAD_SET_NOLOCK(&chan->readq, AST_LIST_NEXT(f, frame_list));
+                       AST_LIST_NEXT(f, frame_list) = NULL;
                }
 
                switch (f->frametype) {
                case AST_FRAME_CONTROL:
                        if (f->subclass == AST_CONTROL_ANSWER) {
                                if (!ast_test_flag(chan, AST_FLAG_OUTGOING)) {
-                                       ast_log(LOG_DEBUG, "Ignoring answer on an inbound call!\n");
+                                       if (option_debug)
+                                               ast_log(LOG_DEBUG, "Ignoring answer on an inbound call!\n");
                                        ast_frfree(f);
                                        f = &ast_null_frame;
                                } else if (prestate == AST_STATE_UP) {
-                                       ast_log(LOG_DEBUG, "Dropping duplicate answer!\n");
+                                       if (option_debug)
+                                               ast_log(LOG_DEBUG, "Dropping duplicate answer!\n");
                                        ast_frfree(f);
                                        f = &ast_null_frame;
                                } else {
@@ -2039,27 +2125,57 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                                }
                        }
                        break;
-               case AST_FRAME_DTMF:
-                       ast_log(LOG_DTMF, "DTMF '%c' received on %s\n", f->subclass, chan->name);
-                       if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF)) {
+               case AST_FRAME_DTMF_END:
+                       ast_log(LOG_DTMF, "DTMF end '%c' received on %s\n", f->subclass, chan->name);
+                       if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF | AST_FLAG_EMULATE_DTMF)) {
                                if (strlen(chan->dtmfq) < sizeof(chan->dtmfq) - 2)
                                        chan->dtmfq[strlen(chan->dtmfq)] = f->subclass;
                                else
                                        ast_log(LOG_WARNING, "Dropping deferred DTMF digits on %s\n", chan->name);
                                ast_frfree(f);
                                f = &ast_null_frame;
-                       }
+                       } else if (!ast_test_flag(chan, AST_FLAG_IN_DTMF)) {
+                               f->frametype = AST_FRAME_DTMF_BEGIN;
+                               ast_set_flag(chan, AST_FLAG_EMULATE_DTMF);
+                               chan->emulate_dtmf_digit = f->subclass;
+                               if (f->samples)
+                                       chan->emulate_dtmf_samples = f->samples;
+                               else
+                                       chan->emulate_dtmf_samples = AST_DEFAULT_EMULATE_DTMF_SAMPLES;
+                       } else 
+                               ast_clear_flag(chan, AST_FLAG_IN_DTMF);
                        break;
                case AST_FRAME_DTMF_BEGIN:
                        ast_log(LOG_DTMF, "DTMF begin '%c' received on %s\n", f->subclass, chan->name);
-                       break;
-               case AST_FRAME_DTMF_END:
-                       ast_log(LOG_DTMF, "DTMF end '%c' received on %s\n", f->subclass, chan->name);
+                       if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF)) {
+                               ast_frfree(f);
+                               f = &ast_null_frame;
+                       } else 
+                               ast_set_flag(chan, AST_FLAG_IN_DTMF);
                        break;
                case AST_FRAME_VOICE:
-                       if (dropaudio) {
+                       /* The EMULATE_DTMF flag must be cleared here as opposed to when the samples
+                        * first get to zero, because we want to make sure we pass at least one
+                        * voice frame through before starting the next digit, to ensure a gap
+                        * between DTMF digits. */
+                       if (ast_test_flag(chan, AST_FLAG_EMULATE_DTMF) && !chan->emulate_dtmf_samples) {
+                               ast_clear_flag(chan, AST_FLAG_EMULATE_DTMF);
+                               chan->emulate_dtmf_digit = 0;
+                       }
+
+                       if (dropaudio || ast_test_flag(chan, AST_FLAG_IN_DTMF)) {
                                ast_frfree(f);
                                f = &ast_null_frame;
+                       } else if (ast_test_flag(chan, AST_FLAG_EMULATE_DTMF)) {
+                               if (f->samples >= chan->emulate_dtmf_samples) {
+                                       chan->emulate_dtmf_samples = 0;
+                                       f->frametype = AST_FRAME_DTMF_END;
+                                       f->subclass = chan->emulate_dtmf_digit;
+                               } else {
+                                       chan->emulate_dtmf_samples -= f->samples;
+                                       ast_frfree(f);
+                                       f = &ast_null_frame;
+                               }
                        } else if (!(f->subclass & chan->nativeformats)) {
                                /* This frame can't be from the current native formats -- drop it on the
                                   floor */
@@ -2128,6 +2244,9 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                                        }
                                }
                        }
+               default:
+                       /* Just pass it on! */
+                       break;
                }
        } else {
                /* Make sure we always return NULL in the future */
@@ -2206,7 +2325,8 @@ int ast_indicate_data(struct ast_channel *chan, int condition, const void *data,
                                break;
                        }
                        if (ts && ts->data[0]) {
-                               ast_log(LOG_DEBUG, "Driver for channel '%s' does not support indication %d, emulating it\n", chan->name, condition);
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Driver for channel '%s' does not support indication %d, emulating it\n", chan->name, condition);
                                ast_playtones_start(chan,0,ts->data, 1);
                                res = 0;
                        } else if (condition == AST_CONTROL_PROGRESS) {
@@ -2280,12 +2400,13 @@ int ast_sendtext(struct ast_channel *chan, const char *text)
        return res;
 }
 
-static int do_senddigit(struct ast_channel *chan, char digit)
+int ast_senddigit_begin(struct ast_channel *chan, char digit)
 {
        int res = -1;
 
-       if (chan->tech->send_digit)
-               res = chan->tech->send_digit(chan, digit);
+       if (chan->tech->send_digit_begin)
+               res = chan->tech->send_digit_begin(chan, digit);
+
        if (res) {
                /*
                 * Device does not support DTMF tones, lets fake
@@ -2318,15 +2439,34 @@ static int do_senddigit(struct ast_channel *chan, char digit)
                        ast_playtones_start(chan, 0, dtmf_tones[15], 0);
                else {
                        /* not handled */
-                       ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, chan->name);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, chan->name);
                }
        }
+
+       return 0;
+}
+
+int ast_senddigit_end(struct ast_channel *chan, char digit)
+{
+       int res = -1;
+
+       if (chan->tech->send_digit_end)
+               res = chan->tech->send_digit_end(chan, digit);
+
+       if (res && chan->generator)
+               ast_playtones_stop(chan);
+       
        return 0;
 }
 
 int ast_senddigit(struct ast_channel *chan, char digit)
 {
-       return do_senddigit(chan, digit);
+       ast_senddigit_begin(chan, digit);
+       
+       ast_safe_sleep(chan, 100); /* XXX 100ms ... probably should be configurable */
+       
+       return ast_senddigit_end(chan, digit);
 }
 
 int ast_prod(struct ast_channel *chan)
@@ -2336,7 +2476,8 @@ int ast_prod(struct ast_channel *chan)
 
        /* Send an empty audio frame to get things moving */
        if (chan->_state != AST_STATE_UP) {
-               ast_log(LOG_DEBUG, "Prodding channel '%s'\n", chan->name);
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "Prodding channel '%s'\n", chan->name);
                a.subclass = chan->rawwriteformat;
                a.data = nothing + AST_FRIENDLY_OFFSET;
                a.src = "ast_prod";
@@ -2394,17 +2535,16 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
                        chan->tech->indicate(chan, fr->subclass, fr->data, fr->datalen);
                break;
        case AST_FRAME_DTMF_BEGIN:
-               res = (chan->tech->send_digit_begin == NULL) ? 0 :
-                       chan->tech->send_digit_begin(chan, fr->subclass);
+               ast_clear_flag(chan, AST_FLAG_BLOCKING);
+               ast_channel_unlock(chan);
+               res = ast_senddigit_begin(chan, fr->subclass);
+               ast_channel_lock(chan);
+               CHECK_BLOCKING(chan);
                break;
        case AST_FRAME_DTMF_END:
-               res = (chan->tech->send_digit_end == NULL) ? 0 :
-                       chan->tech->send_digit_end(chan);
-               break;
-       case AST_FRAME_DTMF:
                ast_clear_flag(chan, AST_FLAG_BLOCKING);
                ast_channel_unlock(chan);
-               res = do_senddigit(chan,fr->subclass);
+               res = ast_senddigit_end(chan, fr->subclass);
                ast_channel_lock(chan);
                CHECK_BLOCKING(chan);
                break;
@@ -2429,67 +2569,105 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
                if (chan->tech->write == NULL)
                        break;  /*! \todo XXX should return 0 maybe ? */
 
-               /* Bypass translator if we're writing format in the raw write format.  This
-                  allows mixing of native / non-native formats */
-               if (fr->subclass == chan->rawwriteformat)
-                       f = fr;
-               else
-                       f = (chan->writetrans) ? ast_translate(chan->writetrans, fr, 0) : fr;
+               /* If someone is whispering on this channel then we must ensure that we are always getting signed linear frames */
+               if (ast_test_flag(chan, AST_FLAG_WHISPER)) {
+                       if (fr->subclass == AST_FORMAT_SLINEAR)
+                               f = fr;
+                       else {
+                               ast_mutex_lock(&chan->whisper->lock);
+                               if (chan->writeformat != AST_FORMAT_SLINEAR) {
+                                       /* Rebuild the translation path and set our write format back to signed linear */
+                                       chan->whisper->original_format = chan->writeformat;
+                                       ast_set_write_format(chan, AST_FORMAT_SLINEAR);
+                                       if (chan->whisper->path)
+                                               ast_translator_free_path(chan->whisper->path);
+                                       chan->whisper->path = ast_translator_build_path(AST_FORMAT_SLINEAR, chan->whisper->original_format);
+                               }
+                               /* Translate frame using the above translation path */
+                               f = (chan->whisper->path) ? ast_translate(chan->whisper->path, fr, 0) : fr;
+                               ast_mutex_unlock(&chan->whisper->lock);
+                       }
+               } else {
+                       /* If the frame is in the raw write format, then it's easy... just use the frame - otherwise we will have to translate */
+                       if (fr->subclass == chan->rawwriteformat)
+                               f = fr;
+                       else
+                               f = (chan->writetrans) ? ast_translate(chan->writetrans, fr, 0) : fr;
+               }
+
+               /* If we have no frame of audio, then we have to bail out */
                if (f == NULL) {
                        res = 0;
-               } else {
-                       if (chan->spies)
-                               queue_frame_to_spies(chan, f, SPY_WRITE);
+                       break;
+               }
+
+               /* If spies are on the channel then queue the frame out to them */
+               if (chan->spies)
+                       queue_frame_to_spies(chan, f, SPY_WRITE);
 
-                       if (chan->monitor && chan->monitor->write_stream) {
-                               /* XXX must explain this code */
+               /* If Monitor is running on this channel, then we have to write frames out there too */
+               if (chan->monitor && chan->monitor->write_stream) {
+                       /* XXX must explain this code */
 #ifndef MONITOR_CONSTANT_DELAY
-                               int jump = chan->insmpl - chan->outsmpl - 4 * f->samples;
-                               if (jump >= 0) {
-                                       if (ast_seekstream(chan->monitor->write_stream, jump + f->samples, SEEK_FORCECUR) == -1)
-                                               ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
-                                       chan->outsmpl += jump + 4 * f->samples;
-                               } else
-                                       chan->outsmpl += f->samples;
+                       int jump = chan->insmpl - chan->outsmpl - 4 * f->samples;
+                       if (jump >= 0) {
+                               if (ast_seekstream(chan->monitor->write_stream, jump + f->samples, SEEK_FORCECUR) == -1)
+                                       ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
+                               chan->outsmpl += jump + 4 * f->samples;
+                       } else
+                               chan->outsmpl += f->samples;
 #else
-                               int jump = chan->insmpl - chan->outsmpl;
-                               if (jump - MONITOR_DELAY >= 0) {
-                                       if (ast_seekstream(chan->monitor->write_stream, jump - f->samples, SEEK_FORCECUR) == -1)
-                                               ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
-                                       chan->outsmpl += jump;
-                               } else
-                                       chan->outsmpl += f->samples;
+                       int jump = chan->insmpl - chan->outsmpl;
+                       if (jump - MONITOR_DELAY >= 0) {
+                               if (ast_seekstream(chan->monitor->write_stream, jump - f->samples, SEEK_FORCECUR) == -1)
+                                       ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
+                               chan->outsmpl += jump;
+                       } else
+                               chan->outsmpl += f->samples;
 #endif
-                               if (chan->monitor->state == AST_MONITOR_RUNNING) {
-                                       if (ast_writestream(chan->monitor->write_stream, f) < 0)
-                                               ast_log(LOG_WARNING, "Failed to write data to channel monitor write stream\n");
-                               }
+                       if (chan->monitor->state == AST_MONITOR_RUNNING) {
+                               if (ast_writestream(chan->monitor->write_stream, f) < 0)
+                                       ast_log(LOG_WARNING, "Failed to write data to channel monitor write stream\n");
                        }
+               }
 
-                       if (ast_test_flag(chan, AST_FLAG_WHISPER)) {
-                               /* frame is assumed to be in SLINEAR, since that is
-                                  required for whisper mode */
-                               ast_frame_adjust_volume(f, -2);
-                               if (ast_slinfactory_available(&chan->whisper->sf) >= f->samples) {
-                                       short buf[f->samples];
-                                       struct ast_frame whisper = {
-                                               .frametype = AST_FRAME_VOICE,
-                                               .subclass = AST_FORMAT_SLINEAR,
-                                               .data = buf,
-                                               .datalen = sizeof(buf),
-                                               .samples = f->samples,
-                                       };
-
-                                       ast_mutex_lock(&chan->whisper->lock);
-                                       if (ast_slinfactory_read(&chan->whisper->sf, buf, f->samples))
-                                               ast_frame_slinear_sum(f, &whisper);
-                                       ast_mutex_unlock(&chan->whisper->lock);
-                               }
+               /* Finally the good part! Write this out to the channel */
+               if (ast_test_flag(chan, AST_FLAG_WHISPER)) {
+                       /* frame is assumed to be in SLINEAR, since that is
+                          required for whisper mode */
+                       ast_frame_adjust_volume(f, -2);
+                       if (ast_slinfactory_available(&chan->whisper->sf) >= f->samples) {
+                               short buf[f->samples];
+                               struct ast_frame whisper = {
+                                       .frametype = AST_FRAME_VOICE,
+                                       .subclass = AST_FORMAT_SLINEAR,
+                                       .data = buf,
+                                       .datalen = sizeof(buf),
+                                       .samples = f->samples,
+                               };
+                               
+                               ast_mutex_lock(&chan->whisper->lock);
+                               if (ast_slinfactory_read(&chan->whisper->sf, buf, f->samples))
+                                       ast_frame_slinear_sum(f, &whisper);
+                               ast_mutex_unlock(&chan->whisper->lock);
                        }
-
-                       res = chan->tech->write(chan, f);
+                       /* and now put it through the regular translator */
+                       f = (chan->writetrans) ? ast_translate(chan->writetrans, f, 0) : f;
                }
-               break;  
+               
+               res = chan->tech->write(chan, f);
+               break;
+       case AST_FRAME_NULL:
+       case AST_FRAME_IAX:
+               /* Ignore these */
+               res = 0;
+               break;
+       default:
+               /* At this point, fr is the incoming frame and f is NULL.  Channels do
+                * not expect to get NULL as a frame pointer and will segfault.  Hence,
+                * we output the original frame passed in. */
+               res = chan->tech->write(chan, fr);
+               break;
        }
 
        if (f && f != fr)
@@ -2533,7 +2711,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;
@@ -2728,19 +2906,8 @@ struct ast_channel *ast_request(const char *type, int format, void *data, int *c
                
                if (!(c = chan->tech->requester(type, capabilities | videoformat, data, cause)))
                        return NULL;
-
-               if (c->_state == AST_STATE_DOWN) {
-                       manager_event(EVENT_FLAG_CALL, "Newchannel",
-                                     "Channel: %s\r\n"
-                                     "State: %s\r\n"
-                                     "CallerID: %s\r\n"
-                                     "CallerIDName: %s\r\n"
-                                     "Uniqueid: %s\r\n",
-                                     c->name, ast_state2str(c->_state),
-                                     S_OR(c->cid.cid_num, "<unknown>"),
-                                     S_OR(c->cid.cid_name, "<unknown>"),
-                                     c->uniqueid);
-               }
+               
+               /* no need to generate a Newchannel event here; it is done in the channel_alloc call */
                return c;
        }
 
@@ -2953,8 +3120,9 @@ int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clo
                return -1;
        }
 
-       ast_log(LOG_DEBUG, "Planning to masquerade channel %s into the structure of %s\n",
-               clone->name, original->name);
+       if (option_debug)
+               ast_log(LOG_DEBUG, "Planning to masquerade channel %s into the structure of %s\n",
+                       clone->name, original->name);
        if (original->masq) {
                ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n",
                        original->masq->name, original->name);
@@ -2966,7 +3134,8 @@ int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clo
                clone->masqr = original;
                ast_queue_frame(original, &ast_null_frame);
                ast_queue_frame(clone, &ast_null_frame);
-               ast_log(LOG_DEBUG, "Done planning to masquerade channel %s into the structure of %s\n", clone->name, original->name);
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "Done planning to masquerade channel %s into the structure of %s\n", clone->name, original->name);
                res = 0;
        }
 
@@ -3046,7 +3215,7 @@ static void clone_variables(struct ast_channel *original, struct ast_channel *cl
 
        AST_LIST_TRAVERSE_SAFE_BEGIN(&original->varshead, varptr, entries) {
                if (!strncmp(ast_var_name(varptr), GROUP_CATEGORY_PREFIX, strlen(GROUP_CATEGORY_PREFIX))) {
-                       AST_LIST_REMOVE(&original->varshead, varptr, entries);
+                       AST_LIST_REMOVE_CURRENT(&original->varshead, entries);
                        ast_var_delete(varptr);
                }
        }
@@ -3055,7 +3224,7 @@ static void clone_variables(struct ast_channel *original, struct ast_channel *cl
        /* Append variables from clone channel into original channel */
        /* XXX Is this always correct?  We have to in order to keep MACROS working XXX */
        if (AST_LIST_FIRST(&clone->varshead))
-               AST_LIST_INSERT_TAIL(&original->varshead, AST_LIST_FIRST(&clone->varshead), entries);
+               AST_LIST_APPEND_LIST(&original->varshead, &clone->varshead, entries);
 }
 
 /*!
@@ -3068,11 +3237,13 @@ int ast_do_masquerade(struct ast_channel *original)
        int x,i;
        int res=0;
        int origstate;
-       struct ast_frame *cur, *prev;
+       struct ast_frame *cur;
        const struct ast_channel_tech *t;
        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];
@@ -3084,6 +3255,9 @@ int ast_do_masquerade(struct ast_channel *original)
                ast_log(LOG_DEBUG, "Actually Masquerading %s(%d) into the structure of %s(%d)\n",
                        clone->name, clone->_state, original->name, original->_state);
 
+       manager_event(EVENT_FLAG_CALL, "Masquerade", "Clone: %s\r\nCloneState: %s\r\nOriginal: %s\r\nOriginalState: %s\r\n",
+                     clone->name, ast_state2str(clone->_state), original->name, ast_state2str(original->_state));
+
        /* XXX This is a seriously wacked out operation.  We're essentially putting the guts of
           the clone channel into the original channel.  Start by killing off the original
           channel's backend.   I'm not sure we're going to keep this function, because
@@ -3132,9 +3306,9 @@ int ast_do_masquerade(struct ast_channel *original)
        clone->tech_pvt = t_pvt;
 
        /* Swap the readq's */
-       cur = original->readq;
-       original->readq = clone->readq;
-       clone->readq = cur;
+       cur = AST_LIST_FIRST(&original->readq);
+       AST_LIST_HEAD_SET_NOLOCK(&original->readq, AST_LIST_FIRST(&clone->readq));
+       AST_LIST_HEAD_SET_NOLOCK(&clone->readq, cur);
 
        /* Swap the alertpipes */
        for (i = 0; i < 2; i++) {
@@ -3151,25 +3325,45 @@ 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... */
-       prev = NULL;
        x = 0;
-       for (cur = clone->readq; cur; cur = cur->next) {
-               x++;
-               prev = cur;
+       if (original->alertpipe[1] > -1) {
+               AST_LIST_TRAVERSE(&clone->readq, cur, frame_list)
+                       x++;
        }
-       /* If we had any, prepend them to the ones already in the queue, and
+
+       /* If we had any, prepend them to the ones already in the queue, and 
         * load up the alertpipe */
-       if (prev) {
-               prev->next = original->readq;
-               original->readq = clone->readq;
-               clone->readq = NULL;
-               if (original->alertpipe[1] > -1) {
-                       for (i = 0; i < x; i++)
-                               write(original->alertpipe[1], &x, sizeof(x));
-               }
+       if (AST_LIST_FIRST(&clone->readq)) {
+               AST_LIST_INSERT_TAIL(&clone->readq, AST_LIST_FIRST(&original->readq), frame_list);
+               AST_LIST_HEAD_SET_NOLOCK(&original->readq, AST_LIST_FIRST(&clone->readq));
+               AST_LIST_HEAD_SET_NOLOCK(&clone->readq, NULL);
+               for (i = 0; i < x; i++)
+                       write(original->alertpipe[1], &x, sizeof(x));
        }
+       
        clone->_softhangup = AST_SOFTHANGUP_DEV;
 
 
@@ -3303,7 +3497,8 @@ int ast_do_masquerade(struct ast_channel *original)
                        );
                ast_channel_free(clone);
        } else {
-               ast_log(LOG_DEBUG, "Released clone lock on '%s'\n", clone->name);
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "Released clone lock on '%s'\n", clone->name);
                ast_set_flag(clone, AST_FLAG_ZOMBIE);
                ast_queue_frame(clone, &ast_null_frame);
                ast_channel_unlock(clone);
@@ -3338,7 +3533,7 @@ void ast_set_callerid(struct ast_channel *chan, const char *callerid, const char
                ast_cdr_setcid(chan->cdr, chan);
        manager_event(EVENT_FLAG_CALL, "Newcallerid",
                                "Channel: %s\r\n"
-                               "CallerID: %s\r\n"
+                               "CallerIDNum: %s\r\n"
                                "CallerIDName: %s\r\n"
                                "Uniqueid: %s\r\n"
                                "CID-CallingPres: %d (%s)\r\n",
@@ -3360,11 +3555,12 @@ int ast_setstate(struct ast_channel *chan, enum ast_channel_state state)
 
        chan->_state = state;
        ast_device_state_changed_literal(chan->name);
+       /* setstate used to conditionally report Newchannel; this is no more */
        manager_event(EVENT_FLAG_CALL,
-                     (oldstate == AST_STATE_DOWN) ? "Newchannel" : "Newstate",
+                     "Newstate",
                      "Channel: %s\r\n"
                      "State: %s\r\n"
-                     "CallerID: %s\r\n"
+                     "CallerIDNum: %s\r\n"
                      "CallerIDName: %s\r\n"
                      "Uniqueid: %s\r\n",
                      chan->name, ast_state2str(chan->_state),
@@ -3462,7 +3658,7 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
                if (bridge_end.tv_sec) {
                        to = ast_tvdiff_ms(bridge_end, ast_tvnow());
                        if (to <= 0) {
-                               res = AST_BRIDGE_RETRY;
+                               res = AST_BRIDGE_COMPLETE;
                                break;
                        }
                } else
@@ -3490,7 +3686,8 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
                if (!f) {
                        *fo = NULL;
                        *rc = who;
-                       ast_log(LOG_DEBUG, "Didn't get a frame from channel: %s\n",who->name);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Didn't get a frame from channel: %s\n",who->name);
                        break;
                }
 
@@ -3512,13 +3709,15 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
                                *fo = f;
                                *rc = who;
                                bridge_exit = 1;
-                               ast_log(LOG_DEBUG, "Got a FRAME_CONTROL (%d) frame on channel %s\n", f->subclass, who->name);
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Got a FRAME_CONTROL (%d) frame on channel %s\n", f->subclass, who->name);
                                break;
                        }
                        if (bridge_exit)
                                break;
                }
                if ((f->frametype == AST_FRAME_VOICE) ||
+                   (f->frametype == AST_FRAME_DTMF_BEGIN) ||
                    (f->frametype == AST_FRAME_DTMF) ||
                    (f->frametype == AST_FRAME_VIDEO) ||
                    (f->frametype == AST_FRAME_IMAGE) ||
@@ -3528,10 +3727,15 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
                        /* monitored dtmf causes exit from bridge */
                        int monitored_source = (who == c0) ? watch_c0_dtmf : watch_c1_dtmf;
 
-                       if (f->frametype == AST_FRAME_DTMF && monitored_source) {
+                       if (monitored_source && 
+                               (f->frametype == AST_FRAME_DTMF_END || 
+                               f->frametype == AST_FRAME_DTMF_BEGIN)) {
                                *fo = f;
                                *rc = who;
-                               ast_log(LOG_DEBUG, "Got DTMF on channel (%s)\n", who->name);
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Got DTMF %s on channel (%s)\n", 
+                                               f->frametype == AST_FRAME_DTMF_END ? "end" : "begin",
+                                               who->name);
                                break;
                        }
                        /* Write immediately frames, not passed through jb */
@@ -3553,6 +3757,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)
@@ -3636,8 +3850,10 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                if (!ast_tvzero(nexteventts)) {
                        now = ast_tvnow();
                        to = ast_tvdiff_ms(nexteventts, now);
-                       if (to < 0)
-                               to = 0;
+                       if (to <= 0) {
+                               res = AST_BRIDGE_COMPLETE;
+                               break;
+                       }
                }
 
                if (config->timelimit) {
@@ -3666,7 +3882,11 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                                                bridge_playfile(c1, c0, config->warning_sound, t);
                                }
                                if (config->warning_freq) {
-                                       nexteventts = ast_tvadd(nexteventts, ast_samp2tv(config->warning_freq, 1000));
+
+                                       if (time_left_ms > (config->warning_freq + 5000)) {
+                                               nexteventts = ast_tvadd(nexteventts, ast_samp2tv(config->warning_freq, 1000));
+                                       }
+                                                               
                                } else
                                        nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
                        }
@@ -3679,7 +3899,8 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                                c1->_softhangup = 0;
                        c0->_bridge = c1;
                        c1->_bridge = c0;
-                       ast_log(LOG_DEBUG, "Unbridge signal received. Ending native bridge.\n");
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Unbridge signal received. Ending native bridge.\n");
                        continue;
                }
                
@@ -3690,12 +3911,13 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                        if (who)
                                *rc = who;
                        res = 0;
-                       ast_log(LOG_DEBUG, "Bridge stops because we're zombie or need a soft hangup: c0=%s, c1=%s, flags: %s,%s,%s,%s\n",
-                               c0->name, c1->name,
-                               ast_test_flag(c0, AST_FLAG_ZOMBIE) ? "Yes" : "No",
-                               ast_check_hangup(c0) ? "Yes" : "No",
-                               ast_test_flag(c1, AST_FLAG_ZOMBIE) ? "Yes" : "No",
-                               ast_check_hangup(c1) ? "Yes" : "No");
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Bridge stops because we're zombie or need a soft hangup: c0=%s, c1=%s, flags: %s,%s,%s,%s\n",
+                                       c0->name, c1->name,
+                                       ast_test_flag(c0, AST_FLAG_ZOMBIE) ? "Yes" : "No",
+                                       ast_check_hangup(c0) ? "Yes" : "No",
+                                       ast_test_flag(c1, AST_FLAG_ZOMBIE) ? "Yes" : "No",
+                                       ast_check_hangup(c1) ? "Yes" : "No");
                        break;
                }
 
@@ -3718,7 +3940,8 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                                              "CallerID1: %s\r\n"
                                              "CallerID2: %s\r\n",
                                              c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num);
-                               ast_log(LOG_DEBUG, "Returning from native bridge, channels: %s, %s\n", c0->name, c1->name);
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Returning from native bridge, channels: %s, %s\n", c0->name, c1->name);
 
                                ast_clear_flag(c0, AST_FLAG_NBRIDGE);
                                ast_clear_flag(c1, AST_FLAG_NBRIDGE);
@@ -3784,7 +4007,8 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                      "CallerID1: %s\r\n"
                      "CallerID2: %s\r\n",
                      c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num);
-       ast_log(LOG_DEBUG, "Bridge stops bridging channels %s and %s\n", c0->name, c1->name);
+       if (option_debug)
+               ast_log(LOG_DEBUG, "Bridge stops bridging channels %s and %s\n", c0->name, c1->name);
 
        return res;
 }
@@ -4041,8 +4265,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 ---*/
@@ -4086,9 +4309,7 @@ static void copy_data_from_queue(struct ast_channel_spy_queue *queue, short *buf
        int bytestocopy;
 
        while (samples) {
-               f = queue->head;
-
-               if (!f) {
+               if (!(f = AST_LIST_FIRST(&queue->list))) {
                        ast_log(LOG_ERROR, "Ran out of frames before buffer filled!\n");
                        break;
                }
@@ -4103,10 +4324,9 @@ static void copy_data_from_queue(struct ast_channel_spy_queue *queue, short *buf
                f->datalen -= bytestocopy;
                f->offset += bytestocopy;
                queue->samples -= tocopy;
-               if (!f->samples) {
-                       queue->head = f->next;
-                       ast_frfree(f);
-               }
+
+               if (!f->samples)
+                       ast_frfree(AST_LIST_REMOVE_HEAD(&queue->list, frame_list));
        }
 }
 
@@ -4136,19 +4356,19 @@ struct ast_frame *ast_channel_spy_read_frame(struct ast_channel_spy *spy, unsign
        if (ast_test_flag(spy, CHANSPY_TRIGGER_FLUSH)) {
                if (spy->read_queue.samples > spy->write_queue.samples) {
                        if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST)) {
-                               for (result = spy->read_queue.head; result; result = result->next)
+                               AST_LIST_TRAVERSE(&spy->read_queue.list, result, frame_list)
                                        ast_frame_adjust_volume(result, spy->read_vol_adjustment);
                        }
-                       result = spy->read_queue.head;
-                       spy->read_queue.head = NULL;
+                       result = AST_LIST_FIRST(&spy->read_queue.list);
+                       AST_LIST_HEAD_SET_NOLOCK(&spy->read_queue.list, NULL);
                        spy->read_queue.samples = 0;
                } else {
                        if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST)) {
-                               for (result = spy->write_queue.head; result; result = result->next)
+                               AST_LIST_TRAVERSE(&spy->write_queue.list, result, frame_list)
                                        ast_frame_adjust_volume(result, spy->write_vol_adjustment);
                        }
-                       result = spy->write_queue.head;
-                       spy->write_queue.head = NULL;
+                       result = AST_LIST_FIRST(&spy->write_queue.list);
+                       AST_LIST_HEAD_SET_NOLOCK(&spy->write_queue.list, NULL);
                        spy->write_queue.samples = 0;
                }
                ast_clear_flag(spy, CHANSPY_TRIGGER_FLUSH);
@@ -4159,15 +4379,10 @@ struct ast_frame *ast_channel_spy_read_frame(struct ast_channel_spy *spy, unsign
                return NULL;
 
        /* short-circuit if both head frames have exactly what we want */
-       if ((spy->read_queue.head->samples == samples) &&
-           (spy->write_queue.head->samples == samples)) {
-               read_frame = spy->read_queue.head;
-               spy->read_queue.head = read_frame->next;
-               read_frame->next = NULL;
-
-               write_frame = spy->write_queue.head;
-               spy->write_queue.head = write_frame->next;
-               write_frame->next = NULL;
+       if ((AST_LIST_FIRST(&spy->read_queue.list)->samples == samples) &&
+           (AST_LIST_FIRST(&spy->write_queue.list)->samples == samples)) {
+               read_frame = AST_LIST_REMOVE_HEAD(&spy->read_queue.list, frame_list);
+               write_frame = AST_LIST_REMOVE_HEAD(&spy->write_queue.list, frame_list);
 
                spy->read_queue.samples -= samples;
                spy->write_queue.samples -= samples;
@@ -4200,10 +4415,10 @@ struct ast_frame *ast_channel_spy_read_frame(struct ast_channel_spy *spy, unsign
        } else {
                if (need_dup) {
                        result = ast_frdup(read_frame);
-                       result->next = ast_frdup(write_frame);
+                       AST_LIST_NEXT(result, frame_list) = ast_frdup(write_frame);
                } else {
                        result = read_frame;
-                       result->next = write_frame;
+                       AST_LIST_NEXT(result, frame_list) = write_frame;
                }
        }
 
@@ -4318,30 +4533,26 @@ int ast_channel_unlock(struct ast_channel *chan)
                ast_log(LOG_DEBUG, "::::==== Unlocking AST channel %s\n", chan->name);
        
        if (!chan) {
-               ast_log(LOG_DEBUG, "::::==== Unlocking non-existing channel \n");
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "::::==== Unlocking non-existing channel \n");
                return 0;
        }
 
        res = ast_mutex_unlock(&chan->lock);
 
        if (option_debug > 2) {
-               /* Try to find counter if possible on your platform 
-                       I've only found out how to do this on Linux
-                       DEBUG_THREADS changes the lock structure
-               */
-#ifdef __linux__
-               int count = 0;
 #ifdef DEBUG_THREADS
-               if ((count = chan->lock.mutex.__m_count))
-#else
-               if ((count = chan->lock.__m_count))
-#endif
-                       ast_log(LOG_DEBUG, ":::=== Still have %d locks (recursive)\n", count);
+               int count = 0;
+               if ((count = chan->lock.reentrancy))
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, ":::=== Still have %d locks (recursive)\n", count);
 #endif
                if (!res)
-                       ast_log(LOG_DEBUG, "::::==== Channel %s was unlocked\n", chan->name);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "::::==== Channel %s was unlocked\n", chan->name);
                        if (res == EINVAL) {
-                               ast_log(LOG_DEBUG, "::::==== Channel %s had no lock by this thread. Failed unlocking\n", chan->name);
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "::::==== Channel %s had no lock by this thread. Failed unlocking\n", chan->name);
                        }
                }
                if (res == EPERM) {
@@ -4365,17 +4576,15 @@ int ast_channel_lock(struct ast_channel *chan)
        res = ast_mutex_lock(&chan->lock);
 
        if (option_debug > 3) {
-#ifdef __linux__
-               int count = 0;
 #ifdef DEBUG_THREADS
-               if ((count = chan->lock.mutex.__m_count))
-#else
-               if ((count = chan->lock.__m_count))
-#endif
-                       ast_log(LOG_DEBUG, ":::=== Now have %d locks (recursive)\n", count);
+               int count = 0;
+               if ((count = chan->lock.reentrancy))
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, ":::=== Now have %d locks (recursive)\n", count);
 #endif
                if (!res)
-                       ast_log(LOG_DEBUG, "::::==== Channel %s was locked\n", chan->name);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "::::==== Channel %s was locked\n", chan->name);
                if (res == EDEADLK) {
                /* We had no lock, so okey any way */
                if (option_debug > 3)
@@ -4401,17 +4610,15 @@ int ast_channel_trylock(struct ast_channel *chan)
        res = ast_mutex_trylock(&chan->lock);
 
        if (option_debug > 2) {
-#ifdef __linux__
-               int count = 0;
 #ifdef DEBUG_THREADS
-               if ((count = chan->lock.mutex.__m_count))
-#else
-               if ((count = chan->lock.__m_count))
-#endif
-                       ast_log(LOG_DEBUG, ":::=== Now have %d locks (recursive)\n", count);
+               int count = 0;
+               if ((count = chan->lock.reentrancy))
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, ":::=== Now have %d locks (recursive)\n", count);
 #endif
                if (!res)
-                       ast_log(LOG_DEBUG, "::::==== Channel %s was locked\n", chan->name);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "::::==== Channel %s was locked\n", chan->name);
                if (res == EBUSY) {
                        /* We failed to lock */
                        if (option_debug > 2)
@@ -4493,7 +4700,6 @@ int ast_channel_whisper_start(struct ast_channel *chan)
 
        ast_mutex_init(&chan->whisper->lock);
        ast_slinfactory_init(&chan->whisper->sf);
-       chan->whisper->original_format = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
        ast_set_flag(chan, AST_FLAG_WHISPER);
 
        return 0;
@@ -4517,7 +4723,10 @@ void ast_channel_whisper_stop(struct ast_channel *chan)
                return;
 
        ast_clear_flag(chan, AST_FLAG_WHISPER);
-       ast_set_write_format(chan, chan->whisper->original_format);
+       if (chan->whisper->path)
+               ast_translator_free_path(chan->whisper->path);
+       if (chan->whisper->original_format && chan->writeformat == AST_FORMAT_SLINEAR)
+               ast_set_write_format(chan, chan->whisper->original_format);
        ast_slinfactory_destroy(&chan->whisper->sf);
        ast_mutex_destroy(&chan->whisper->lock);
        free(chan->whisper);