Merge in ast_strftime branch, which changes timestamps to be accurate to the microsec...
[asterisk/asterisk.git] / channels / chan_zap.c
index 75dccf3..0e52a7b 100644 (file)
@@ -38,6 +38,8 @@
  */
 
 /*** MODULEINFO
+       <depend>res_smdi</depend>
+       <depend>zaptel_vldtmf</depend>
        <depend>zaptel</depend>
        <depend>tonezone</depend>
        <use>pri</use>
@@ -65,8 +67,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <sys/ioctl.h>
 #include <math.h>
 #include <ctype.h>
-#include <zaptel/zaptel.h>
-#include <zaptel/tonezone.h>
+#include "asterisk/zapata.h"
 
 #ifdef HAVE_PRI
 #include <libpri.h>
@@ -106,6 +107,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/abstract_jb.h"
 #include "asterisk/smdi.h"
 #include "asterisk/astobj.h"
+#include "asterisk/event.h"
+
 #define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
 
 /*! Global jitterbuffer configuration - by default, jb is disabled */
@@ -163,7 +166,7 @@ static const char tdesc[] = "Zapata Telephony Driver"
 #ifdef HAVE_PRI
                " w/PRI"
 #endif
-#ifdef HAVEL_LIBSS7
+#ifdef HAVEL_SS7
               "w/SS7"
 #endif
 ;
@@ -208,117 +211,23 @@ static const char config[] = "zapata.conf";
 
 #define DCHAN_AVAILABLE        (DCHAN_PROVISIONED | DCHAN_NOTINALARM | DCHAN_UP)
 
-static char context[AST_MAX_CONTEXT] = "default";
-static char cid_num[256] = "";
-static char cid_name[256] = "";
+/* Overlap dialing option types */
+#define ZAP_OVERLAPDIAL_NONE 0
+#define ZAP_OVERLAPDIAL_OUTGOING 1
+#define ZAP_OVERLAPDIAL_INCOMING 2
+#define ZAP_OVERLAPDIAL_BOTH (ZAP_OVERLAPDIAL_INCOMING|ZAP_OVERLAPDIAL_OUTGOING)
+
 static char defaultcic[64] = "";
 static char defaultozz[64] = "";
 
-static char language[MAX_LANGUAGE] = "";
-static char mohinterpret[MAX_MUSICCLASS] = "default";
-static char mohsuggest[MAX_MUSICCLASS] = "";
 static char progzone[10] = "";
 
 static int usedistinctiveringdetection = 0;
 static int distinctiveringaftercid = 0;
 
-static int transfertobusy = 1;
-
-static int use_callerid = 1;
-static int cid_signalling = CID_SIG_BELL;
-static int cid_start = CID_START_RING;
-static int zaptrcallerid = 0;
-static int cur_radio = 0;
-static int cur_signalling = -1;
-static int cur_outsignalling = -1;
-
-static ast_group_t cur_group = 0;
-static ast_group_t cur_callergroup = 0;
-static ast_group_t cur_pickupgroup = 0;
-static int relaxdtmf = 0;
-
-static int immediate = 0;
-
-static int stripmsd = 0;
-
-static int callwaiting = 0;
-
-static int callwaitingcallerid = 0;
-
-static int hidecallerid = 0;
-
-static int restrictcid = 0;
-
-static int use_callingpres = 0;
-
-static int callreturn = 0;
-
-static int threewaycalling = 0;
-
-static int transfer = 0;
-
-static int canpark = 0;
-
-static int cancallforward = 0;
-
-static float rxgain = 0.0;
-
-static float txgain = 0.0;
-
-static int tonezone = -1;
-
-static int echocancel;
-
-static int echotraining;
-
-static int pulse;
-
-static int echocanbridged = 0;
-
-static int busydetect = 0;
-
-static int busycount = 3;
-static int busy_tonelength = 0;
-static int busy_quietlength = 0;
-
-static int callprogress = 0;
-
-static char accountcode[AST_MAX_ACCOUNT_CODE] = "";
-
-static char mailbox[AST_MAX_EXTENSION];
-
-static int amaflags = 0;
-
-static int adsi = 0;
-static int use_smdi = 0;
-static char smdi_port[SMDI_MAX_FILENAME_LEN] = "/dev/ttyS0";
 static int numbufs = 4;
 
-static int cur_prewink = -1;
-static int cur_preflash = -1;
-static int cur_wink = -1;
-static int cur_flash = -1;
-static int cur_start = -1;
-static int cur_rxwink = -1;
-static int cur_rxflash = -1;
-static int cur_debounce = -1;
-static int cur_priexclusive = 0;
-
-static int priindication_oob = 0;
-
 #ifdef HAVE_PRI
-static int minunused = 2;
-static int minidle = 0;
-static char idleext[AST_MAX_EXTENSION];
-static char idledial[AST_MAX_EXTENSION];
-static int overlapdial = 0;
-static int facilityenable = 0;
-static char internationalprefix[10] = "";
-static char nationalprefix[10] = "";
-static char localprefix[20] = "";
-static char privateprefix[20] = "";
-static char unknownprefix[20] = "";
-static long resetinterval = 3600;      /*!< How often (in seconds) to reset unused channels. Default 1 hour. */
 static struct ast_channel inuse;
 #ifdef PRI_GETSET_TIMERS
 static int pritimers[PRI_MAX_TIMERS];
@@ -336,8 +245,6 @@ static int gendigittimeout = 8000;
 /*! \brief How long to wait for an extra digit, if there is an ambiguous match */
 static int matchdigittimeout = 3000;
 
-static int usecnt = 0;
-
 /*! \brief Protect the interface list (of zt_pvt's) */
 AST_MUTEX_DEFINE_STATIC(iflock);
 
@@ -348,18 +255,6 @@ static int ifcount = 0;
 AST_MUTEX_DEFINE_STATIC(pridebugfdlock);
 #endif
 
-/*! \brief Whether we answer on a Polarity Switch event */
-static int answeronpolarityswitch = 0;
-
-/*! \brief Whether we hang up on a Polarity Switch event */
-static int hanguponpolarityswitch = 0;
-
-/*! \brief How long (ms) to ignore Polarity Switch events after we answer a call */
-static int polarityonanswerdelay = 600;
-
-/*! \brief When to send the CallerID signals (rings) */
-static int sendcalleridafter = DEFAULT_CIDRINGS;
-
 /*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
    when it's doing something critical. */
 AST_MUTEX_DEFINE_STATIC(monlock);
@@ -374,6 +269,14 @@ static enum ast_bridge_result zt_bridge(struct ast_channel *c0, struct ast_chann
 
 static int zt_sendtext(struct ast_channel *c, const char *text);
 
+static void mwi_event_cb(const struct ast_event *event, void *userdata)
+{
+       /* This module does not handle MWI in an event-based manner.  However, it
+        * subscribes to MWI for each mailbox that is configured so that the core
+        * knows that we care about it.  Then, chan_zap will get the MWI from the
+        * event cache instead of checking the mailbox directly. */
+}
+
 /*! \brief Avoid the silly zt_getevent which ignores a bunch of events */
 static inline int zt_get_event(int fd)
 {
@@ -418,6 +321,8 @@ static int ringt_base = DEFAULT_RINGT;
 #define LINKSTATE_UP           (1 << 2)
 #define LINKSTATE_DOWN         (1 << 3)
 
+#define SS7_NAI_DYNAMIC                -1
+
 struct zt_ss7 {
        pthread_t master;                                               /*!< Thread of master */
        ast_mutex_t lock;
@@ -426,6 +331,16 @@ struct zt_ss7 {
        int linkstate[NUM_DCHANS];
        int numchans;
        int type;
+       enum {
+               LINKSET_STATE_DOWN = 0,
+               LINKSET_STATE_UP
+       } state;
+       char called_nai;                                                /*!< Called Nature of Address Indicator */
+       char calling_nai;                                               /*!< Calling Nature of Address Indicator */
+       char internationalprefix[10];                                   /*!< country access code ('00' for european dialplans) */
+       char nationalprefix[10];                                        /*!< area access code ('0' for european dialplans) */
+       char subscriberprefix[20];                                      /*!< area access code + area code ('0'+area code for european dialplans) */
+       char unknownprefix[20];                                         /*!< for unknown dialplans */
        struct ss7 *ss7;
        struct zt_pvt *pvts[MAX_CHANNELS];                              /*!< Member channel pvt structs */
 };
@@ -492,8 +407,6 @@ struct zt_pri {
 
 static struct zt_pri pris[NUM_SPANS];
 
-static int pritype = PRI_CPE;
-
 #if 0
 #define DEFAULT_PRI_DEBUG (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE)
 #else
@@ -505,11 +418,6 @@ static inline void pri_rel(struct zt_pri *pri)
        ast_mutex_unlock(&pri->lock);
 }
 
-static int switchtype = PRI_SWITCH_NI2;
-static int nsf = PRI_NSF_NONE;
-static int dialplan = PRI_NATIONAL_ISDN + 1;
-static int localdialplan = PRI_NATIONAL_ISDN + 1;
-
 #else
 /*! Shut up the compiler */
 struct zt_pri;
@@ -528,6 +436,7 @@ static struct zt_distRings drings;
 
 struct distRingData {
        int ring[3];
+       int range;
 };
 struct ringContextData {
        char contextData[AST_MAX_CONTEXT];
@@ -585,6 +494,7 @@ static struct zt_pvt {
        int outsigmod;                                  /*!< Outbound Signalling style (modifier) */
        int oprmode;                                    /*!< "Operator Services" mode */
        struct zt_pvt *oprpeer;                         /*!< "Operator Services" peer tech_pvt ptr */
+       float cid_rxgain;                                       /*!< "Gain to apply during caller id */
        float rxgain;
        float txgain;
        int tonezone;                                   /*!< tone zone for this chan, or -1 for default */
@@ -614,13 +524,14 @@ static struct zt_pvt {
        unsigned int firstradio:1;
        unsigned int hanguponpolarityswitch:1;
        unsigned int hardwaredtmf:1;
-       unsigned int hidecallerid;
+       unsigned int hidecallerid:1;
+       unsigned int hidecalleridname:1;      /*!< Hide just the name not the number for legacy PBX use */
        unsigned int ignoredtmf:1;
        unsigned int immediate:1;                       /*!< Answer before getting digits? */
        unsigned int inalarm:1;
        unsigned int mate:1;                            /*!< flag to say its in MATE mode */
        unsigned int outgoing:1;
-       unsigned int overlapdial:1;
+       /* unsigned int overlapdial:1;                  unused and potentially confusing */
        unsigned int permcallwaiting:1;
        unsigned int permhidecallerid:1;                /*!< Whether to hide our outgoing caller ID or not */
        unsigned int priindication_oob:1;
@@ -673,7 +584,7 @@ static struct zt_pvt {
        char callwait_name[AST_MAX_EXTENSION];
        char rdnis[AST_MAX_EXTENSION];
        char dnid[AST_MAX_EXTENSION];
-       unsigned int group;
+       ast_group_t group;
        int law;
        int confno;                                     /*!< Our conference */
        int confusers;                                  /*!< Who is using our conference */
@@ -714,6 +625,7 @@ static struct zt_pvt {
        struct tdd_state *tdd;                          /*!< TDD flag */
        char call_forward[AST_MAX_EXTENSION];
        char mailbox[AST_MAX_EXTENSION];
+       struct ast_event_sub *mwi_event_sub;
        char dialdest[256];
        int onhooktime;
        int msgstate;
@@ -739,13 +651,123 @@ static struct zt_pvt {
        struct isup_call *ss7call;
        int transcap;
        int cic;                                                        /*!< CIC associated with channel */
+       unsigned int dpc;                                               /*!< CIC's DPC */
 #endif
        char begindigit;
 } *iflist = NULL, *ifend = NULL;
 
+/*! \brief Channel configuration from zapata.conf .
+ * This struct is used for parsing the [channels] section of zapata.conf.
+ * Generally there is a field here for every possible configuration item.
+ *
+ * The state of fields is saved along the parsing and whenever a 'channel'
+ * statement is reached, the current zt_chan_conf is used to configure the 
+ * channel (struct zt_pvt)
+ *
+ * \see zt_chan_init for the default values.
+ */
+struct zt_chan_conf {
+       struct zt_pvt chan;
+#ifdef HAVE_PRI
+       struct zt_pri pri;
+#endif
+
+#ifdef HAVE_SS7
+       struct zt_ss7 ss7;
+#endif
+       ZT_PARAMS timing;
+
+       char smdi_port[SMDI_MAX_FILENAME_LEN];
+};
+
+/** returns a new zt_chan_conf with default values (by-value) */
+static struct zt_chan_conf zt_chan_conf_default(void) {
+       /* recall that if a field is not included here it is initialized
+        * to 0 or equivalent
+        */
+       struct zt_chan_conf conf = {
+#ifdef HAVE_PRI
+               .pri = {
+                       .nsf = PRI_NSF_NONE,
+                       .switchtype = PRI_SWITCH_NI2,
+                       .dialplan = PRI_NATIONAL_ISDN + 1,
+                       .localdialplan = PRI_NATIONAL_ISDN + 1,
+                       .nodetype = PRI_CPE,
+
+                       .minunused = 2,
+                       .idleext = "",
+                       .idledial = "",
+                       .internationalprefix = "",
+                       .nationalprefix = "",
+                       .localprefix = "",
+                       .privateprefix = "",
+                       .unknownprefix = "",
+
+                       .resetinterval = 3600
+               },
+#endif
+#ifdef HAVE_SS7
+               .ss7 = {
+                       .called_nai = SS7_NAI_NATIONAL,
+                       .calling_nai = SS7_NAI_NATIONAL,
+                       .internationalprefix = "",
+                       .nationalprefix = "",
+                       .subscriberprefix = "",
+                       .unknownprefix = ""
+               },
+#endif
+               .chan = {
+                       .context = "default",
+                       .cid_num = "",
+                       .cid_name = "",
+                       .mohinterpret = "default",
+                       .mohsuggest = "",
+                       .transfertobusy = 1,
+
+                       .cid_signalling = CID_SIG_BELL,
+                       .cid_start = CID_START_RING,
+                       .zaptrcallerid = 0,
+                       .use_callerid = 1,
+                       .sig = -1,
+                       .outsigmod = -1,
+
+                       .cid_rxgain = +5.0,
+
+                       .tonezone = -1,
+
+                       .echocancel = 1,
+
+                       .busycount = 3,
+
+                       .accountcode = "",
+
+                       .mailbox = "",
+
+
+                       .polarityonanswerdelay = 600,
+
+                       .sendcalleridafter = DEFAULT_CIDRINGS
+               },
+               .timing = {
+                       .prewinktime = -1,
+                       .preflashtime = -1,
+                       .winktime = -1,
+                       .flashtime = -1,
+                       .starttime = -1,
+                       .rxwinktime = -1,
+                       .rxflashtime = -1,
+                       .debouncetime = -1
+               },
+               .smdi_port = "/dev/ttyS0",
+       };
+
+       return conf;
+}
+
+
 static struct ast_channel *zt_request(const char *type, int format, void *data, int *cause);
 static int zt_digit_begin(struct ast_channel *ast, char digit);
-static int zt_digit_end(struct ast_channel *ast, char digit);
+static int zt_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int zt_sendtext(struct ast_channel *c, const char *text);
 static int zt_call(struct ast_channel *ast, char *rdest, int timeout);
 static int zt_hangup(struct ast_channel *ast);
@@ -756,7 +778,7 @@ static struct ast_frame *zt_exception(struct ast_channel *ast);
 static int zt_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);
 static int zt_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 static int zt_setoption(struct ast_channel *chan, int option, void *data, int datalen);
-static int zt_func_read(struct ast_channel *chan, char *function, char *data, char *buf, size_t len); 
+static int zt_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len);
 
 static const struct ast_channel_tech zap_tech = {
        .type = "Zap",
@@ -976,8 +998,7 @@ static void swap_subs(struct zt_pvt *p, int a, int b)
        int tinthreeway;
        struct ast_channel *towner;
 
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Swapping %d and %d\n", a, b);
+       ast_debug(1, "Swapping %d and %d\n", a, b);
 
        tchan = p->subs[a].chan;
        towner = p->subs[a].owner;
@@ -1080,8 +1101,7 @@ static int alloc_sub(struct zt_pvt *p, int x)
                                p->subs[x].zfd = -1;
                                return -1;
                        }
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Allocated %s subchannel on FD %d channel %d\n", subnames[x], p->subs[x].zfd, p->subs[x].chan);
+                       ast_debug(1, "Allocated %s subchannel on FD %d channel %d\n", subnames[x], p->subs[x].zfd, p->subs[x].chan);
                        return 0;
                } else
                        ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
@@ -1097,8 +1117,7 @@ static int unalloc_sub(struct zt_pvt *p, int x)
                ast_log(LOG_WARNING, "Trying to unalloc the real channel %d?!?\n", p->channel);
                return -1;
        }
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Released sub %d of channel %d\n", x, p->channel);
+       ast_debug(1, "Released sub %d of channel %d\n", x, p->channel);
        if (p->subs[x].zfd > -1) {
                zt_close(p->subs[x].zfd);
        }
@@ -1153,8 +1172,7 @@ static int zt_digit_begin(struct ast_channel *chan, char digit)
                                ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", pvt->span);
                } else if (strlen(pvt->dialdest) < sizeof(pvt->dialdest) - 1) {
                        int res;
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Queueing digit '%c' since setup_ack not yet received\n", digit);
+                       ast_debug(1, "Queueing digit '%c' since setup_ack not yet received\n", digit);
                        res = strlen(pvt->dialdest);
                        pvt->dialdest[res++] = digit;
                        pvt->dialdest[res] = '\0';
@@ -1169,17 +1187,17 @@ static int zt_digit_begin(struct ast_channel *chan, char digit)
                int res;
                ZT_DIAL_OPERATION zo = {
                        .op = ZT_DIAL_OP_APPEND,
-                       .dialstr[0] = 'T',
-                       .dialstr[1] = digit,
-                       .dialstr[2] = 0,
                };
+
+               zo.dialstr[0] = 'T';
+               zo.dialstr[1] = digit;
+               zo.dialstr[2] = '\0';
                if ((res = ioctl(pvt->subs[SUB_REAL].zfd, ZT_DIAL, &zo)))
                        ast_log(LOG_WARNING, "Couldn't dial digit %c\n", digit);
                else
                        pvt->dialing = 1;
        } else {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Started VLDTMF digit '%c'\n", digit);
+               ast_debug(1, "Started VLDTMF digit '%c'\n", digit);
                pvt->dialing = 1;
                pvt->begindigit = digit;
        }
@@ -1187,10 +1205,10 @@ static int zt_digit_begin(struct ast_channel *chan, char digit)
 out:
        ast_mutex_unlock(&pvt->lock);
 
-       return 0; /* Tell Asterisk not to generate inband indications */
+       return 0;
 }
 
-static int zt_digit_end(struct ast_channel *chan, char digit)
+static int zt_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
 {
        struct zt_pvt *pvt;
        int res = 0;
@@ -1214,8 +1232,7 @@ static int zt_digit_end(struct ast_channel *chan, char digit)
 
        if (pvt->begindigit) {
                x = -1;
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Ending VLDTMF digit '%c'\n", digit);
+               ast_debug(1, "Ending VLDTMF digit '%c'\n", digit);
                res = ioctl(pvt->subs[SUB_REAL].zfd, ZT_SENDTONE, &x);
                pvt->dialing = 0;
                pvt->begindigit = 0;
@@ -1284,7 +1301,7 @@ static char *event2str(int event)
 #ifdef HAVE_PRI
 static char *dialplan2str(int dialplan)
 {
-       if (dialplan == -1) {
+       if (dialplan == -1 || dialplan == -2) {
                return("Dynamically set dialplan in ISDN");
        }
        return (pri_plan2str(dialplan));
@@ -1389,8 +1406,7 @@ static int conf_add(struct zt_pvt *p, struct zt_subchannel *c, int index, int sl
                p->confno = zi.confno;
        }
        memcpy(&c->curconf, &zi, sizeof(c->curconf));
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Added %d to conference %d/%d\n", c->zfd, c->curconf.confmode, c->curconf.confno);
+       ast_debug(1, "Added %d to conference %d/%d\n", c->zfd, c->curconf.confmode, c->curconf.confno);
        return 0;
 }
 
@@ -1422,8 +1438,7 @@ static int conf_del(struct zt_pvt *p, struct zt_subchannel *c, int index)
                ast_log(LOG_WARNING, "Failed to drop %d from conference %d/%d\n", c->zfd, c->curconf.confmode, c->curconf.confno);
                return -1;
        }
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Removed %d from conference %d/%d\n", c->zfd, c->curconf.confmode, c->curconf.confno);
+       ast_debug(1, "Removed %d from conference %d/%d\n", c->zfd, c->curconf.confmode, c->curconf.confno);
        memcpy(&c->curconf, &zi, sizeof(c->curconf));
        return 0;
 }
@@ -1537,8 +1552,7 @@ static int update_conf(struct zt_pvt *p)
                   Kill it. */
                p->confno = -1;
        }
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
+       ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
        return 0;
 }
 
@@ -1549,13 +1563,11 @@ static void zt_enable_ec(struct zt_pvt *p)
        if (!p)
                return;
        if (p->echocanon) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Echo cancellation already on\n");
+               ast_debug(1, "Echo cancellation already on\n");
                return;
        }
        if (p->digital) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Echo cancellation isn't required on digital connection\n");
+               ast_debug(1, "Echo cancellation isn't required on digital connection\n");
                return;
        }
        if (p->echocancel) {
@@ -1571,13 +1583,10 @@ static void zt_enable_ec(struct zt_pvt *p)
                        ast_log(LOG_WARNING, "Unable to enable echo cancellation on channel %d\n", p->channel);
                else {
                        p->echocanon = 1;
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Enabled echo cancellation on channel %d\n", p->channel);
+                       ast_debug(1, "Enabled echo cancellation on channel %d\n", p->channel);
                }
-       } else {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "No echo cancellation requested\n");
-       }
+       } else
+               ast_debug(1, "No echo cancellation requested\n");
 }
 
 static void zt_train_ec(struct zt_pvt *p)
@@ -1589,14 +1598,10 @@ static void zt_train_ec(struct zt_pvt *p)
                res = ioctl(p->subs[SUB_REAL].zfd, ZT_ECHOTRAIN, &x);
                if (res)
                        ast_log(LOG_WARNING, "Unable to request echo training on channel %d\n", p->channel);
-               else {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Engaged echo training on channel %d\n", p->channel);
-               }
-       } else {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "No echo training requested\n");
-       }
+               else
+                       ast_debug(1, "Engaged echo training on channel %d\n", p->channel);
+       } else
+               ast_debug(1, "No echo training requested\n");
 }
 
 static void zt_disable_ec(struct zt_pvt *p)
@@ -1608,10 +1613,8 @@ static void zt_disable_ec(struct zt_pvt *p)
                res = ioctl(p->subs[SUB_REAL].zfd, ZT_ECHOCANCEL, &x);
                if (res)
                        ast_log(LOG_WARNING, "Unable to disable echo cancellation on channel %d\n", p->channel);
-               else {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "disabled echo cancellation on channel %d\n", p->channel);
-               }
+               else
+                       ast_debug(1, "disabled echo cancellation on channel %d\n", p->channel);
        }
        p->echocanon = 0;
 }
@@ -1693,8 +1696,7 @@ static int set_actual_txgain(int fd, int chan, float gain, int law)
        g.chan = chan;
        res = ioctl(fd, ZT_GETGAINS, &g);
        if (res) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Failed to read gains: %s\n", strerror(errno));
+               ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
                return res;
        }
 
@@ -1712,8 +1714,7 @@ static int set_actual_rxgain(int fd, int chan, float gain, int law)
        g.chan = chan;
        res = ioctl(fd, ZT_GETGAINS, &g);
        if (res) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Failed to read gains: %s\n", strerror(errno));
+               ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
                return res;
        }
 
@@ -1731,8 +1732,8 @@ static int bump_gains(struct zt_pvt *p)
 {
        int res;
 
-       /* Bump receive gain by 5.0db */
-       res = set_actual_gain(p->subs[SUB_REAL].zfd, 0, p->rxgain + 5.0, p->txgain, p->law);
+       /* Bump receive gain by value stored in cid_rxgain */
+       res = set_actual_gain(p->subs[SUB_REAL].zfd, 0, p->rxgain + p->cid_rxgain, p->txgain, p->law);
        if (res) {
                ast_log(LOG_WARNING, "Unable to bump gain: %s\n", strerror(errno));
                return -1;
@@ -1756,14 +1757,23 @@ static int restore_gains(struct zt_pvt *p)
 
 static inline int zt_set_hook(int fd, int hs)
 {
-       int x, res;
+       int x, res, count = 0;
+
        x = hs;
        res = ioctl(fd, ZT_HOOK, &x);
-       if (res < 0) 
-       {
+
+       while (res < 0 && count < 20) {
+               usleep(100000); /* 1/10 sec. */
+               x = hs;
+               res = ioctl(fd, ZT_HOOK, &x);
+               count++;
+       }
+
+       if (res < 0) {
                if (errno == EINPROGRESS) return 0;
                ast_log(LOG_WARNING, "zt hook failed: %s\n", strerror(errno));
        }
+
        return res;
 }
 
@@ -1806,8 +1816,7 @@ static int save_conference(struct zt_pvt *p)
                ast_log(LOG_WARNING, "Unable to set conference info: %s\n", strerror(errno));
                return -1;
        }
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Disabled conferencing\n");
+       ast_debug(1, "Disabled conferencing\n");
        return 0;
 }
 
@@ -1822,8 +1831,7 @@ static int restore_conference(struct zt_pvt *p)
                        return -1;
                }
        }
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Restored conferencing\n");
+       ast_debug(1, "Restored conferencing\n");
        return 0;
 }
 
@@ -1847,8 +1855,21 @@ static int send_cwcidspill(struct zt_pvt *p)
 
 static int has_voicemail(struct zt_pvt *p)
 {
+       int new_msgs;
+       struct ast_event *event;
+
+       event = ast_event_get_cached(AST_EVENT_MWI,
+               AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, p->mailbox,
+               AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
+               AST_EVENT_IE_END);
+
+       if (event) {
+               new_msgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
+               ast_event_destroy(event);
+       } else
+               new_msgs = ast_app_has_voicemail(p->mailbox, NULL);
 
-       return ast_app_has_voicemail(p->mailbox, NULL);
+       return new_msgs;
 }
 
 static int send_callerid(struct zt_pvt *p)
@@ -1874,7 +1895,7 @@ static int send_callerid(struct zt_pvt *p)
                        return 0;
                p->cidpos += res;
        }
-       free(p->cidspill);
+       ast_free(p->cidspill);
        p->cidspill = NULL;
        if (p->callwaitcas) {
                /* Wait for CID/CW to expire */
@@ -1890,7 +1911,7 @@ static int zt_callwait(struct ast_channel *ast)
        p->callwaitingrepeat = CALLWAITING_REPEAT_SAMPLES;
        if (p->cidspill) {
                ast_log(LOG_WARNING, "Spill already exists?!?\n");
-               free(p->cidspill);
+               ast_free(p->cidspill);
        }
        if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
                return -1;
@@ -1912,6 +1933,18 @@ static int zt_callwait(struct ast_channel *ast)
        return 0;
 }
 
+#ifdef HAVE_SS7
+static unsigned char cid_pres2ss7pres(int cid_pres)
+{
+        return (cid_pres >> 5) & 0x03;
+}
+
+static unsigned char cid_pres2ss7screen(int cid_pres)
+{
+       return cid_pres & 0x03;
+}
+#endif
+
 static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
 {
        struct zt_pvt *p = ast->tech_pvt;
@@ -1967,7 +2000,7 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
                                /* Generate the Caller-ID spill if desired */
                                if (p->cidspill) {
                                        ast_log(LOG_WARNING, "cidspill already exists??\n");
-                                       free(p->cidspill);
+                                       ast_free(p->cidspill);
                                }
                                p->callwaitcas = 0;
                                if ((p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) {
@@ -1998,8 +2031,7 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
                        if (c) {
                                p->dop.op = ZT_DIAL_OP_REPLACE;
                                snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "Tw%s", c);
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "FXO: setup deferred dialstring: %s\n", c);
+                               ast_debug(1, "FXO: setup deferred dialstring: %s\n", c);
                        } else {
                                p->dop.dialstr[0] = '\0';
                        }
@@ -2091,8 +2123,7 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
 #ifdef HAVE_PRI
                }
 #endif
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Dialing '%s'\n", c);
+               ast_debug(1, "Dialing '%s'\n", c);
                p->dop.op = ZT_DIAL_OP_REPLACE;
 
                c += p->stripmsd;
@@ -2167,10 +2198,9 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
                                ast_mutex_unlock(&p->lock);
                                return -1;
                        }
-               } else {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Deferring dialing...\n");
-               }
+               } else
+                       ast_debug(1, "Deferring dialing...\n");
+
                p->dialing = 1;
                if (ast_strlen_zero(c))
                        p->dialednone = 1;
@@ -2186,13 +2216,17 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
                p->dialdest[0] = '\0';
                break;
        default:
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "not yet implemented\n");
+               ast_debug(1, "not yet implemented\n");
                ast_mutex_unlock(&p->lock);
                return -1;
        }
 #ifdef HAVE_SS7
        if (p->ss7) {
+               char ss7_called_nai;
+               int called_nai_strip;
+               char ss7_calling_nai;
+               int calling_nai_strip;
+
                c = strchr(dest, '/');
                if (c)
                        c++;
@@ -2205,7 +2239,11 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
                        l = NULL;
                }
 
-               ss7_grab(p, p->ss7);
+               if (ss7_grab(p, p->ss7)) {
+                       ast_log(LOG_WARNING, "Failed to grab SS7!\n");
+                       ast_mutex_unlock(&p->lock);
+                       return -1;
+               }
                p->digital = IS_DIGITAL(ast->transfercapability);
                p->ss7call = isup_new_call(p->ss7->ss7);
 
@@ -2216,9 +2254,42 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
                        return -1;
                }
 
-               isup_init_call(p->ss7->ss7, p->ss7call, p->cic, c + p->stripmsd, l);
+               called_nai_strip = 0;
+               ss7_called_nai = p->ss7->called_nai;
+               if (ss7_called_nai == SS7_NAI_DYNAMIC) { /* compute dynamically */
+                       if (strncmp(c + p->stripmsd, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
+                               called_nai_strip = strlen(p->ss7->internationalprefix);
+                               ss7_called_nai = SS7_NAI_INTERNATIONAL;
+                       } else if (strncmp(c + p->stripmsd, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
+                               called_nai_strip = strlen(p->ss7->nationalprefix);
+                               ss7_called_nai = SS7_NAI_NATIONAL;
+                       } else {
+                               ss7_called_nai = SS7_NAI_SUBSCRIBER;
+                       }
+               }
+               isup_set_called(p->ss7call, c + p->stripmsd + called_nai_strip, ss7_called_nai, p->ss7->ss7);
+
+               calling_nai_strip = 0;
+               ss7_calling_nai = p->ss7->calling_nai;
+               if ((l != NULL) && (ss7_calling_nai == SS7_NAI_DYNAMIC)) { /* compute dynamically */
+                       if (strncmp(l, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
+                               calling_nai_strip = strlen(p->ss7->internationalprefix);
+                               ss7_calling_nai = SS7_NAI_INTERNATIONAL;
+                       } else if (strncmp(l, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
+                               calling_nai_strip = strlen(p->ss7->nationalprefix);
+                               ss7_calling_nai = SS7_NAI_NATIONAL;
+                       } else {
+                               ss7_calling_nai = SS7_NAI_SUBSCRIBER;
+                       }
+               }
+               isup_set_calling(p->ss7call, l ? (l + calling_nai_strip) : NULL, ss7_calling_nai,
+                       p->use_callingpres ? cid_pres2ss7pres(ast->cid.cid_pres) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED),
+                       p->use_callingpres ? cid_pres2ss7screen(ast->cid.cid_pres) : SS7_SCREENING_USER_PROVIDED );
+
+               isup_init_call(p->ss7->ss7, p->ss7call, p->cic, p->dpc);
 
                isup_iam(p->ss7->ss7, p->ss7call);
+               ast_setstate(ast, AST_STATE_DIALING);
                ss7_rel(p->ss7);
        }
 #endif /* HAVE_SS7 */
@@ -2241,6 +2312,10 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
                        c++;
                else
                        c = dest;
+               if (!p->hidecalleridname)
+                       n = ast->cid.cid_name;
+               else
+                       n = NULL;
                if (!p->hidecallerid) {
                        l = ast->cid.cid_num;
                        n = ast->cid.cid_name;
@@ -2284,13 +2359,11 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
                }
                if (p->bearer || (mysig == SIG_FXSKS)) {
                        if (p->bearer) {
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Oooh, I have a bearer on %d (%d:%d)\n", PVT_TO_CHANNEL(p->bearer), p->bearer->logicalspan, p->bearer->channel);
+                               ast_debug(1, "Oooh, I have a bearer on %d (%d:%d)\n", PVT_TO_CHANNEL(p->bearer), p->bearer->logicalspan, p->bearer->channel);
                                p->bearer->call = p->call;
-                       } else {
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "I'm being setup with no bearer right now...\n");
-                       }
+                       } else
+                               ast_debug(1, "I'm being setup with no bearer right now...\n");
+
                        pri_set_crv(p->pri->pri, p->call, p->channel, 0);
                }
                p->digital = IS_DIGITAL(ast->transfercapability);
@@ -2316,12 +2389,16 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
                        ast_verbose(VERBOSE_PREFIX_3 "Requested transfer capability: 0x%.2x - %s\n", ast->transfercapability, ast_transfercapability2str(ast->transfercapability));
                dp_strip = 0;
                pridialplan = p->pri->dialplan - 1;
-               if (pridialplan == -2) { /* compute dynamically */
+               if (pridialplan == -2 || pridialplan == -3) { /* compute dynamically */
                        if (strncmp(c + p->stripmsd, p->pri->internationalprefix, strlen(p->pri->internationalprefix)) == 0) {
-                               dp_strip = strlen(p->pri->internationalprefix);
+                               if (pridialplan == -2) {
+                                       dp_strip = strlen(p->pri->internationalprefix);
+                               }
                                pridialplan = PRI_INTERNATIONAL_ISDN;
                        } else if (strncmp(c + p->stripmsd, p->pri->nationalprefix, strlen(p->pri->nationalprefix)) == 0) {
-                               dp_strip = strlen(p->pri->nationalprefix);
+                               if (pridialplan == -2) {
+                                       dp_strip = strlen(p->pri->nationalprefix);
+                               }
                                pridialplan = PRI_NATIONAL_ISDN;
                        } else {
                                pridialplan = PRI_LOCAL_ISDN;
@@ -2331,12 +2408,16 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
 
                ldp_strip = 0;
                prilocaldialplan = p->pri->localdialplan - 1;
-               if ((l != NULL) && (prilocaldialplan == -2)) { /* compute dynamically */
+               if ((l != NULL) && (prilocaldialplan == -2 || prilocaldialplan == -3)) { /* compute dynamically */
                        if (strncmp(l, p->pri->internationalprefix, strlen(p->pri->internationalprefix)) == 0) {
-                               ldp_strip = strlen(p->pri->internationalprefix);
+                               if (prilocaldialplan == -2) {
+                                       ldp_strip = strlen(p->pri->internationalprefix);
+                               }
                                prilocaldialplan = PRI_INTERNATIONAL_ISDN;
                        } else if (strncmp(l, p->pri->nationalprefix, strlen(p->pri->nationalprefix)) == 0) {
-                               ldp_strip = strlen(p->pri->nationalprefix);
+                               if (prilocaldialplan == -2) {
+                                       ldp_strip = strlen(p->pri->nationalprefix);
+                               }
                                prilocaldialplan = PRI_NATIONAL_ISDN;
                        } else {
                                prilocaldialplan = PRI_LOCAL_ISDN;
@@ -2394,8 +2475,10 @@ static void destroy_zt_pvt(struct zt_pvt **pvt)
                p->next->prev = p->prev;
        if (p->use_smdi)
                ASTOBJ_UNREF(p->smdi_iface, ast_smdi_interface_destroy);
+       if (p->mwi_event_sub)
+               ast_event_unsubscribe(p->mwi_event_sub);
        ast_mutex_destroy(&p->lock);
-       free(p);
+       ast_free(p);
        *pvt = NULL;
 }
 
@@ -2471,24 +2554,21 @@ static int zap_send_keypad_facility_exec(struct ast_channel *chan, void *data)
        char *digits = (char *) data;
 
        if (ast_strlen_zero(digits)) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "No digit string sent to application!\n");
+               ast_debug(1, "No digit string sent to application!\n");
                return -1;
        }
 
        p = (struct zt_pvt *)chan->tech_pvt;
 
        if (!p) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Unable to find technology private\n");
+               ast_debug(1, "Unable to find technology private\n");
                return -1;
        }
 
        ast_mutex_lock(&p->lock);
 
        if (!p->pri || !p->call) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Unable to find pri or call on channel!\n");
+               ast_debug(1, "Unable to find pri or call on channel!\n");
                ast_mutex_unlock(&p->lock);
                return -1;
        }
@@ -2497,8 +2577,7 @@ static int zap_send_keypad_facility_exec(struct ast_channel *chan, void *data)
                pri_keypad_facility(p->pri->pri, p->call, digits);
                pri_rel(p->pri);
        } else {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Unable to grab pri to send keypad facility!\n");
+               ast_debug(1, "Unable to grab pri to send keypad facility!\n");
                ast_mutex_unlock(&p->lock);
                return -1;
        }
@@ -2597,8 +2676,7 @@ static int zt_hangup(struct ast_channel *ast)
        struct zt_pvt *prev = NULL;
        ZT_PARAMS par;
 
-       if (option_debug)
-               ast_log(LOG_DEBUG, "zt_hangup(%s)\n", ast->name);
+       ast_debug(1, "zt_hangup(%s)\n", ast->name);
        if (!ast->tech_pvt) {
                ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
                return 0;
@@ -2618,12 +2696,12 @@ static int zt_hangup(struct ast_channel *ast)
        restore_gains(p);
        if (p->origcid_num) {
                ast_copy_string(p->cid_num, p->origcid_num, sizeof(p->cid_num));
-               free(p->origcid_num);
+               ast_free(p->origcid_num);
                p->origcid_num = NULL;
        }       
        if (p->origcid_name) {
                ast_copy_string(p->cid_name, p->origcid_name, sizeof(p->cid_name));
-               free(p->origcid_name);
+               ast_free(p->origcid_name);
                p->origcid_name = NULL;
        }       
        if (p->dsp)
@@ -2631,9 +2709,8 @@ static int zt_hangup(struct ast_channel *ast)
        if (p->exten)
                p->exten[0] = '\0';
 
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
-                       p->channel, index, p->subs[SUB_REAL].zfd, p->subs[SUB_CALLWAIT].zfd, p->subs[SUB_THREEWAY].zfd);
+       ast_debug(1, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
+               p->channel, index, p->subs[SUB_REAL].zfd, p->subs[SUB_CALLWAIT].zfd, p->subs[SUB_THREEWAY].zfd);
        p->ignoredtmf = 0;
        
        if (index > -1) {
@@ -2650,32 +2727,27 @@ static int zt_hangup(struct ast_channel *ast)
                zt_setlinear(p->subs[index].zfd, 0);
                if (index == SUB_REAL) {
                        if ((p->subs[SUB_CALLWAIT].zfd > -1) && (p->subs[SUB_THREEWAY].zfd > -1)) {
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Normal call hung up with both three way call and a call waiting call in place?\n");
+                               ast_debug(1, "Normal call hung up with both three way call and a call waiting call in place?\n");
                                if (p->subs[SUB_CALLWAIT].inthreeway) {
                                        /* We had flipped over to answer a callwait and now it's gone */
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "We were flipped over to the callwait, moving back and unowning.\n");
+                                       ast_debug(1, "We were flipped over to the callwait, moving back and unowning.\n");
                                        /* Move to the call-wait, but un-own us until they flip back. */
                                        swap_subs(p, SUB_CALLWAIT, SUB_REAL);
                                        unalloc_sub(p, SUB_CALLWAIT);
                                        p->owner = NULL;
                                } else {
                                        /* The three way hung up, but we still have a call wait */
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "We were in the threeway and have a callwait still.  Ditching the threeway.\n");
+                                       ast_debug(1, "We were in the threeway and have a callwait still.  Ditching the threeway.\n");
                                        swap_subs(p, SUB_THREEWAY, SUB_REAL);
                                        unalloc_sub(p, SUB_THREEWAY);
                                        if (p->subs[SUB_REAL].inthreeway) {
                                                /* This was part of a three way call.  Immediately make way for
                                                   another call */
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "Call was complete, setting owner to former third call\n");
+                                               ast_debug(1, "Call was complete, setting owner to former third call\n");
                                                p->owner = p->subs[SUB_REAL].owner;
                                        } else {
                                                /* This call hasn't been completed yet...  Set owner to NULL */
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "Call was incomplete, setting owner to NULL\n");
+                                               ast_debug(1, "Call was incomplete, setting owner to NULL\n");
                                                p->owner = NULL;
                                        }
                                        p->subs[SUB_REAL].inthreeway = 0;
@@ -2695,13 +2767,11 @@ static int zt_hangup(struct ast_channel *ast)
                                if (p->subs[SUB_REAL].inthreeway) {
                                        /* This was part of a three way call.  Immediately make way for
                                           another call */
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Call was complete, setting owner to former third call\n");
+                                       ast_debug(1, "Call was complete, setting owner to former third call\n");
                                        p->owner = p->subs[SUB_REAL].owner;
                                } else {
                                        /* This call hasn't been completed yet...  Set owner to NULL */
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Call was incomplete, setting owner to NULL\n");
+                                       ast_debug(1, "Call was incomplete, setting owner to NULL\n");
                                        p->owner = NULL;
                                }
                                p->subs[SUB_REAL].inthreeway = 0;
@@ -2775,7 +2845,14 @@ static int zt_hangup(struct ast_channel *ast)
                        if (p->ss7call) {
                                if (!ss7_grab(p, p->ss7)) {
                                        if (!p->alreadyhungup) {
-                                               isup_rel(p->ss7->ss7, p->ss7call, ast->hangupcause ? ast->hangupcause : -1);
+                                               const char *cause = pbx_builtin_getvar_helper(ast,"SS7_CAUSE");
+                                               int icause = ast->hangupcause ? ast->hangupcause : -1;
+
+                                               if (cause) {
+                                                       if (atoi(cause))
+                                                               icause = atoi(cause);
+                                               }
+                                               isup_rel(p->ss7->ss7, p->ss7call, icause);
                                                ss7_rel(p->ss7);
                                                p->alreadyhungup = 1;
                                        } else
@@ -2797,8 +2874,7 @@ static int zt_hangup(struct ast_channel *ast)
                        if (p->call && (!p->bearer || (p->bearer->call == p->call))) {
                                if (!pri_grab(p, p->pri)) {
                                        if (p->alreadyhungup) {
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "Already hungup...  Calling hangup once, and clearing call\n");
+                                               ast_debug(1, "Already hungup...  Calling hangup once, and clearing call\n");
 
 #ifdef SUPPORT_USERUSER
                                                pri_call_set_useruser(p->call, useruser);
@@ -2811,8 +2887,7 @@ static int zt_hangup(struct ast_channel *ast)
                                        } else {
                                                const char *cause = pbx_builtin_getvar_helper(ast,"PRI_CAUSE");
                                                int icause = ast->hangupcause ? ast->hangupcause : -1;
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "Not yet hungup...  Calling hangup once with icause, and clearing call\n");
+                                               ast_debug(1, "Not yet hungup...  Calling hangup once with icause, and clearing call\n");
 
 #ifdef SUPPORT_USERUSER
                                                pri_call_set_useruser(p->call, useruser);
@@ -2836,8 +2911,7 @@ static int zt_hangup(struct ast_channel *ast)
                                }
                        } else {
                                if (p->bearer)
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Bearer call is %p, while ours is still %p\n", p->bearer->call, p->call);
+                                       ast_debug(1, "Bearer call is %p, while ours is still %p\n", p->bearer->call, p->call);
                                p->call = NULL;
                                res = 0;
                        }
@@ -2855,8 +2929,7 @@ static int zt_hangup(struct ast_channel *ast)
                        res = ioctl(p->subs[SUB_REAL].zfd, ZT_GET_PARAMS, &par);
                        if (!res) {
 #if 0
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Hanging up channel %d, offhook = %d\n", p->channel, par.rxisoffhook);
+                               ast_debug(1, "Hanging up channel %d, offhook = %d\n", p->channel, par.rxisoffhook);
 #endif
                                /* If they're off hook, try playing congestion */
                                if ((par.rxisoffhook) && (!(p->radio || (p->oprmode < 0))))
@@ -2879,7 +2952,7 @@ static int zt_hangup(struct ast_channel *ast)
                        tone_zone_play_tone(p->subs[SUB_REAL].zfd, -1);
                }
                if (p->cidspill)
-                       free(p->cidspill);
+                       ast_free(p->cidspill);
                if (p->sig)
                        zt_disable_ec(p);
                x = 0;
@@ -2901,8 +2974,7 @@ static int zt_hangup(struct ast_channel *ast)
                }
 #ifdef HAVE_PRI
                if (p->bearer) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Freeing up bearer channel %d\n", p->bearer->channel);
+                       ast_debug(1, "Freeing up bearer channel %d\n", p->bearer->channel);
                        /* Free up the bearer channel as well, and
                           don't use its file descriptor anymore */
                        update_conf(p->bearer);
@@ -2922,8 +2994,7 @@ static int zt_hangup(struct ast_channel *ast)
        p->oprmode = 0;
        ast->tech_pvt = NULL;
        ast_mutex_unlock(&p->lock);
-       ast_atomic_fetchadd_int(&usecnt, -1);
-       ast_update_use_count();
+       ast_module_unref(ast_module_info->self);
        if (option_verbose > 2) 
                ast_verbose( VERBOSE_PREFIX_3 "Hungup '%s'\n", ast->name);
 
@@ -2986,18 +3057,16 @@ static int zt_answer(struct ast_channel *ast)
        case SIG_FXOGS:
        case SIG_FXOKS:
                /* Pick up the line */
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Took %s off hook\n", ast->name);
+               ast_debug(1, "Took %s off hook\n", ast->name);
                if (p->hanguponpolarityswitch) {
-                       gettimeofday(&p->polaritydelaytv, NULL);
+                       p->polaritydelaytv = ast_tvnow();
                }
                res = zt_set_hook(p->subs[SUB_REAL].zfd, ZT_OFFHOOK);
                tone_zone_play_tone(p->subs[index].zfd, -1);
                p->dialing = 0;
                if ((index == SUB_REAL) && p->subs[SUB_THREEWAY].inthreeway) {
                        if (oldstate == AST_STATE_RINGING) {
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Finally swapping real and threeway\n");
+                               ast_debug(1, "Finally swapping real and threeway\n");
                                tone_zone_play_tone(p->subs[SUB_THREEWAY].zfd, -1);
                                swap_subs(p, SUB_THREEWAY, SUB_REAL);
                                p->owner = p->subs[SUB_REAL].owner;
@@ -3068,8 +3137,7 @@ static int zt_setoption(struct ast_channel *chan, int option, void *data, int da
                        ast_log(LOG_WARNING, "No index in TXGAIN?\n");
                        return -1;
                }
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Setting actual tx gain on %s to %f\n", chan->name, p->txgain + (float) *scp);
+               ast_debug(1, "Setting actual tx gain on %s to %f\n", chan->name, p->txgain + (float) *scp);
                return set_actual_txgain(p->subs[index].zfd, 0, p->txgain + (float) *scp, p->law);
        case AST_OPTION_RXGAIN:
                scp = (signed char *) data;
@@ -3078,8 +3146,7 @@ static int zt_setoption(struct ast_channel *chan, int option, void *data, int da
                        ast_log(LOG_WARNING, "No index in RXGAIN?\n");
                        return -1;
                }
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Setting actual rx gain on %s to %f\n", chan->name, p->rxgain + (float) *scp);
+               ast_debug(1, "Setting actual rx gain on %s to %f\n", chan->name, p->rxgain + (float) *scp);
                return set_actual_rxgain(p->subs[index].zfd, 0, p->rxgain + (float) *scp, p->law);
        case AST_OPTION_TONE_VERIFY:
                if (!p->dsp)
@@ -3087,18 +3154,15 @@ static int zt_setoption(struct ast_channel *chan, int option, void *data, int da
                cp = (char *) data;
                switch (*cp) {
                case 1:
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",chan->name);
+                       ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",chan->name);
                        ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_MUTECONF | p->dtmfrelax);  /* set mute mode if desired */
                        break;
                case 2:
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",chan->name);
+                       ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",chan->name);
                        ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX | p->dtmfrelax);  /* set mute mode if desired */
                        break;
                default:
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: OFF(0) on %s\n",chan->name);
+                       ast_debug(1, "Set option TONE VERIFY, mode: OFF(0) on %s\n",chan->name);
                        ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_DTMF | p->dtmfrelax);  /* set mute mode if desired */
                        break;
                }
@@ -3108,16 +3172,14 @@ static int zt_setoption(struct ast_channel *chan, int option, void *data, int da
                cp = (char *) data;
                p->mate = 0;
                if (!*cp) { /* turn it off */
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Set option TDD MODE, value: OFF(0) on %s\n",chan->name);
+                       ast_debug(1, "Set option TDD MODE, value: OFF(0) on %s\n",chan->name);
                        if (p->tdd)
                                tdd_free(p->tdd);
                        p->tdd = 0;
                        break;
                }
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Set option TDD MODE, value: %s(%d) on %s\n",
-                               (*cp == 2) ? "MATE" : "ON", (int) *cp, chan->name);
+               ast_debug(1, "Set option TDD MODE, value: %s(%d) on %s\n",
+                       (*cp == 2) ? "MATE" : "ON", (int) *cp, chan->name);
                zt_disable_ec(p);
                /* otherwise, turn it on */
                if (!p->didtdd) { /* if havent done it yet */
@@ -3146,23 +3208,20 @@ static int zt_setoption(struct ast_channel *chan, int option, void *data, int da
                                fds[0].revents = 0;
                                res = poll(fds, 1, -1);
                                if (!res) {
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "poll (for write) ret. 0 on channel %d\n", p->channel);
+                                       ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
                                        continue;
                                }
                                /* if got exception */
                                if (fds[0].revents & POLLPRI)
                                        return -1;
                                if (!(fds[0].revents & POLLOUT)) {
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "write fd not ready on channel %d\n", p->channel);
+                                       ast_debug(1, "write fd not ready on channel %d\n", p->channel);
                                        continue;
                                }
                                res = write(fd, buf, size);
                                if (res != size) {
                                        if (res == -1) return -1;
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
+                                       ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
                                        break;
                                }
                                len -= size;
@@ -3185,21 +3244,18 @@ static int zt_setoption(struct ast_channel *chan, int option, void *data, int da
                if (!p->dsp)
                        break;
                cp = (char *) data;
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Set option RELAX DTMF, value: %s(%d) on %s\n",
-                               *cp ? "ON" : "OFF", (int) *cp, chan->name);
+               ast_debug(1, "Set option RELAX DTMF, value: %s(%d) on %s\n",
+                       *cp ? "ON" : "OFF", (int) *cp, chan->name);
                ast_dsp_digitmode(p->dsp, ((*cp) ? DSP_DIGITMODE_RELAXDTMF : DSP_DIGITMODE_DTMF) | p->dtmfrelax);
                break;
        case AST_OPTION_AUDIO_MODE:  /* Set AUDIO mode (or not) */
                cp = (char *) data;
                if (!*cp) {             
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Set option AUDIO MODE, value: OFF(0) on %s\n", chan->name);
+                       ast_debug(1, "Set option AUDIO MODE, value: OFF(0) on %s\n", chan->name);
                        x = 0;
                        zt_disable_ec(p);
                } else {                
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Set option AUDIO MODE, value: ON(1) on %s\n", chan->name);
+                       ast_debug(1, "Set option AUDIO MODE, value: ON(1) on %s\n", chan->name);
                        x = 1;
                }
                if (ioctl(p->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &x) == -1)
@@ -3218,19 +3274,16 @@ static int zt_setoption(struct ast_channel *chan, int option, void *data, int da
                        pp->oprmode = oprmode->mode;
                        p->oprmode = -oprmode->mode;
                }
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Set Operator Services mode, value: %d on %s/%s\n",
-                               oprmode->mode, chan->name,oprmode->peer->name);
+               ast_debug(1, "Set Operator Services mode, value: %d on %s/%s\n",
+                       oprmode->mode, chan->name,oprmode->peer->name);
                break;
        case AST_OPTION_ECHOCAN:
                cp = (char *) data;
                if (*cp) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Enabling echo cancelation on %s\n", chan->name);
+                       ast_debug(1, "Enabling echo cancelation on %s\n", chan->name);
                        zt_enable_ec(p);
                } else {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Disabling echo cancelation on %s\n", chan->name);
+                       ast_debug(1, "Disabling echo cancelation on %s\n", chan->name);
                        zt_disable_ec(p);
                }
                break;
@@ -3240,7 +3293,7 @@ static int zt_setoption(struct ast_channel *chan, int option, void *data, int da
        return 0;
 }
 
-static int zt_func_read(struct ast_channel *chan, char *function, char *data, char *buf, size_t len)
+static int zt_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
 {
        struct zt_pvt *p = chan->tech_pvt;
        
@@ -3281,8 +3334,7 @@ static void zt_unlink(struct zt_pvt *slave, struct zt_pvt *master, int needlock)
                if (master->slaves[x]) {
                        if (!slave || (master->slaves[x] == slave)) {
                                /* Take slave out of the conference */
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Unlinking slave %d from %d\n", master->slaves[x]->channel, master->channel);
+                               ast_debug(1, "Unlinking slave %d from %d\n", master->slaves[x]->channel, master->channel);
                                conf_del(master, &master->slaves[x]->subs[SUB_REAL], SUB_REAL);
                                conf_del(master->slaves[x], &master->subs[SUB_REAL], SUB_REAL);
                                master->slaves[x]->master = NULL;
@@ -3338,8 +3390,7 @@ static void zt_link(struct zt_pvt *slave, struct zt_pvt *master) {
                ast_log(LOG_WARNING, "Replacing master %d with new master, %d\n", slave->master->channel, master->channel);
        slave->master = master;
        
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
+       ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
 }
 
 static void disable_dtmf_detect(struct zt_pvt *p)
@@ -3502,9 +3553,8 @@ static enum ast_bridge_result zt_bridge(struct ast_channel *c0, struct ast_chann
                        nothingok = 0;
                }
        }
-       if (option_debug)
-               ast_log(LOG_DEBUG, "master: %d, slave: %d, nothingok: %d\n",
-                       master ? master->channel : 0, slave ? slave->channel : 0, nothingok);
+       ast_debug(1, "master: %d, slave: %d, nothingok: %d\n",
+               master ? master->channel : 0, slave ? slave->channel : 0, nothingok);
        if (master && slave) {
                /* Stop any tones, or play ringtone as appropriate.  If they're bridged
                   in an active threeway call with a channel that is ringing, we should
@@ -3514,13 +3564,11 @@ static enum ast_bridge_result zt_bridge(struct ast_channel *c0, struct ast_chann
                    p1->subs[SUB_REAL].owner && 
                    p1->subs[SUB_REAL].inthreeway && 
                    (p1->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Playing ringback on %s since %s is in a ringing three-way\n", c0->name, c1->name);
+                       ast_debug(1, "Playing ringback on %s since %s is in a ringing three-way\n", c0->name, c1->name);
                        tone_zone_play_tone(p0->subs[oi0].zfd, ZT_TONE_RINGTONE);
                        os1 = p1->subs[SUB_REAL].owner->_state;
                } else {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Stopping tones on %d/%d talking to %d/%d\n", p0->channel, oi0, p1->channel, oi1);
+                       ast_debug(1, "Stopping tones on %d/%d talking to %d/%d\n", p0->channel, oi0, p1->channel, oi1);
                        tone_zone_play_tone(p0->subs[oi0].zfd, -1);
                }
                if ((oi0 == SUB_THREEWAY) && 
@@ -3528,13 +3576,11 @@ static enum ast_bridge_result zt_bridge(struct ast_channel *c0, struct ast_chann
                    p0->subs[SUB_REAL].owner && 
                    p0->subs[SUB_REAL].inthreeway && 
                    (p0->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Playing ringback on %s since %s is in a ringing three-way\n", c1->name, c0->name);
+                       ast_debug(1, "Playing ringback on %s since %s is in a ringing three-way\n", c1->name, c0->name);
                        tone_zone_play_tone(p1->subs[oi1].zfd, ZT_TONE_RINGTONE);
                        os0 = p0->subs[SUB_REAL].owner->_state;
                } else {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Stopping tones on %d/%d talking to %d/%d\n", p1->channel, oi1, p0->channel, oi0);
+                       ast_debug(1, "Stopping tones on %d/%d talking to %d/%d\n", p1->channel, oi1, p0->channel, oi0);
                        tone_zone_play_tone(p1->subs[oi0].zfd, -1);
                }
                if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
@@ -3607,9 +3653,8 @@ static enum ast_bridge_result zt_bridge(struct ast_channel *c0, struct ast_chann
                    (t1 != p1->subs[SUB_REAL].inthreeway) ||
                    (oi0 != i0) ||
                    (oi1 != i1)) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Something changed out on %d/%d to %d/%d, returning -3 to restart\n",
-                                       op0->channel, oi0, op1->channel, oi1);
+                       ast_debug(1, "Something changed out on %d/%d to %d/%d, returning -3 to restart\n",
+                               op0->channel, oi0, op1->channel, oi1);
                        res = AST_BRIDGE_RETRY;
                        goto return_from_bridge;
                }
@@ -3627,8 +3672,7 @@ static enum ast_bridge_result zt_bridge(struct ast_channel *c0, struct ast_chann
 
                who = ast_waitfor_n(priority ? c0_priority : c1_priority, 2, &timeoutms);
                if (!who) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Ooh, empty read...\n");
+                       ast_debug(1, "Ooh, empty read...\n");
                        continue;
                }
                f = ast_read(who);
@@ -3679,8 +3723,7 @@ static int zt_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
        struct zt_pvt *p = newchan->tech_pvt;
        int x;
        ast_mutex_lock(&p->lock);
-       if (option_debug)
-               ast_log(LOG_DEBUG, "New owner for channel %d is %s\n", p->channel, newchan->name);
+       ast_debug(1, "New owner for channel %d is %s\n", p->channel, newchan->name);
        if (p->owner == oldchan) {
                p->owner = newchan;
        }
@@ -3741,9 +3784,12 @@ static int attempt_transfer(struct zt_pvt *p)
                   stop if now if appropriate */
                if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner))
                        ast_queue_control(p->subs[SUB_THREEWAY].owner, AST_CONTROL_UNHOLD);
-               if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RINGING) {
+               if (p->subs[SUB_REAL].owner->_state == AST_STATE_RINGING) {
                        ast_indicate(ast_bridged_channel(p->subs[SUB_REAL].owner), AST_CONTROL_RINGING);
                }
+               if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RING) {
+                       tone_zone_play_tone(p->subs[SUB_THREEWAY].zfd, ZT_TONE_RINGTONE);
+               }
                if (p->subs[SUB_REAL].owner->cdr) {
                        /* Move CDR from second channel to current one */
                        p->subs[SUB_THREEWAY].owner->cdr =
@@ -3766,8 +3812,12 @@ static int attempt_transfer(struct zt_pvt *p)
                unalloc_sub(p, SUB_THREEWAY);
        } else if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
                ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
-               if (p->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)
+               if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RINGING) {
                        ast_indicate(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), AST_CONTROL_RINGING);
+               }
+               if (p->subs[SUB_REAL].owner->_state == AST_STATE_RING) {
+                       tone_zone_play_tone(p->subs[SUB_REAL].zfd, ZT_TONE_RINGTONE);
+               }
                if (p->subs[SUB_THREEWAY].owner->cdr) {
                        /* Move CDR from second channel to current one */
                        p->subs[SUB_REAL].owner->cdr = 
@@ -3792,9 +3842,8 @@ static int attempt_transfer(struct zt_pvt *p)
                /* Tell the caller not to hangup */
                return 1;
        } else {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Neither %s nor %s are in a bridge, nothing to transfer\n",
-                                               p->subs[SUB_REAL].owner->name, p->subs[SUB_THREEWAY].owner->name);
+               ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
+                       p->subs[SUB_REAL].owner->name, p->subs[SUB_THREEWAY].owner->name);
                p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
                return -1;
        }
@@ -3836,6 +3885,74 @@ static int get_alarms(struct zt_pvt *p)
        }
        return zi.alarms;
 }
+
+static void zt_handle_dtmfup(struct ast_channel *ast, int index, struct ast_frame **dest)
+{
+       struct zt_pvt *p = ast->tech_pvt;
+       struct ast_frame *f = *dest;
+
+       ast_debug(1, "DTMF digit: %c on %s\n", f->subclass, ast->name);
+
+       if (p->confirmanswer) {
+               ast_debug(1, "Confirm answer on %s!\n", ast->name);
+               /* Upon receiving a DTMF digit, consider this an answer confirmation instead
+                  of a DTMF digit */
+               p->subs[index].f.frametype = AST_FRAME_CONTROL;
+               p->subs[index].f.subclass = AST_CONTROL_ANSWER;
+               *dest = &p->subs[index].f;
+               /* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
+               p->confirmanswer = 0;
+       } else if (p->callwaitcas) {
+               if ((f->subclass == 'A') || (f->subclass == 'D')) {
+                       ast_debug(1, "Got some DTMF, but it's for the CAS\n");
+                       if (p->cidspill)
+                               ast_free(p->cidspill);
+                       send_cwcidspill(p);
+               }
+               if ((f->subclass != 'm') && (f->subclass != 'u')) 
+                       p->callwaitcas = 0;
+               p->subs[index].f.frametype = AST_FRAME_NULL;
+               p->subs[index].f.subclass = 0;
+               *dest = &p->subs[index].f;
+       } else if (f->subclass == 'f') {
+               /* Fax tone -- Handle and return NULL */
+               if ((p->callprogress & 0x6) && !p->faxhandled) {
+                       p->faxhandled++;
+                       if (strcmp(ast->exten, "fax")) {
+                               const char *target_context = S_OR(ast->macrocontext, ast->context);
+
+                               if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) {
+                                       if (option_verbose > 2)
+                                               ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", ast->name);
+                                       /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
+                                       pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
+                                       if (ast_async_goto(ast, target_context, "fax", 1))
+                                               ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
+                               } else
+                                       ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
+                       } else
+                               ast_debug(1, "Already in a fax extension, not redirecting\n");
+               } else
+                       ast_debug(1, "Fax already handled\n");
+               zt_confmute(p, 0);
+               p->subs[index].f.frametype = AST_FRAME_NULL;
+               p->subs[index].f.subclass = 0;
+               *dest = &p->subs[index].f;
+       } else if (f->subclass == 'm') {
+               /* Confmute request */
+               zt_confmute(p, 1);
+               p->subs[index].f.frametype = AST_FRAME_NULL;
+               p->subs[index].f.subclass = 0;
+               *dest = &p->subs[index].f;              
+       } else if (f->subclass == 'u') {
+               /* Unmute */
+               zt_confmute(p, 0);
+               p->subs[index].f.frametype = AST_FRAME_NULL;
+               p->subs[index].f.subclass = 0;
+               *dest = &p->subs[index].f;              
+       } else
+               zt_confmute(p, 0);
+}
                        
 static struct ast_frame *zt_handle_event(struct ast_channel *ast)
 {
@@ -3844,11 +3961,8 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
        char *c;
        struct zt_pvt *p = ast->tech_pvt;
        pthread_t threadid;
-       pthread_attr_t attr;
        struct ast_channel *chan;
-
-       pthread_attr_init(&attr);
-       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+       struct ast_frame *f;
 
        index = zt_get_index(ast, p, 0);
        mysig = p->sig;
@@ -3862,6 +3976,8 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
        p->subs[index].f.offset = 0;
        p->subs[index].f.src = "zt_handle_event";
        p->subs[index].f.data = NULL;
+       f = &p->subs[index].f;
+
        if (index < 0)
                return &p->subs[index].f;
        if (p->fake_event) {
@@ -3870,15 +3986,13 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
        } else
                res = zt_get_event(p->subs[index].zfd);
 
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Got event %s(%d) on channel %d (index %d)\n", event2str(res), res, p->channel, index);
+       ast_debug(1, "Got event %s(%d) on channel %d (index %d)\n", event2str(res), res, p->channel, index);
 
        if (res & (ZT_EVENT_PULSEDIGIT | ZT_EVENT_DTMFUP)) {
                p->pulsedial =  (res & ZT_EVENT_PULSEDIGIT) ? 1 : 0;
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff);
+               ast_debug(1, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff);
 #ifdef HAVE_PRI
-               if (!p->proceeding && p->sig == SIG_PRI && p->pri && p->pri->overlapdial) {
+               if (!p->proceeding && p->sig == SIG_PRI && p->pri && (p->pri->overlapdial & ZAP_OVERLAPDIAL_INCOMING)) {
                        /* absorb event */
                } else {
 #endif
@@ -3887,14 +4001,12 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
 #ifdef HAVE_PRI
                }
 #endif
-               /* Unmute conference, return the captured digit */
-               zt_confmute(p, 0);
-               return &p->subs[index].f;
+               zt_handle_dtmfup(ast, index, &f);
+               return f;
        }
 
        if (res & ZT_EVENT_DTMFDOWN) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "DTMF Down '%c'\n", res & 0xff);
+               ast_debug(1, "DTMF Down '%c'\n", res & 0xff);
                /* Mute conference */
                zt_confmute(p, 1);
                p->subs[index].f.frametype = AST_FRAME_DTMF_BEGIN;
@@ -3921,8 +4033,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                        if (p->inalarm) break;
                        if ((p->radio || (p->oprmode < 0))) break;
                        if (ioctl(p->subs[index].zfd,ZT_DIALING,&x) == -1) {
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "ZT_DIALING ioctl failed on %s\n",ast->name);
+                               ast_debug(1, "ZT_DIALING ioctl failed on %s\n",ast->name);
                                return NULL;
                        }
                        if (!x) { /* if not still dialing in driver */
@@ -3949,8 +4060,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                        }
                                        if (ast->_state == AST_STATE_DIALING) {
                                                if ((p->callprogress & 1) && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) {
-                                                       if (option_debug)
-                                                               ast_log(LOG_DEBUG, "Done dialing, but waiting for progress detection before doing more...\n");
+                                                       ast_debug(1, "Done dialing, but waiting for progress detection before doing more...\n");
                                                } else if (p->confirmanswer || (!p->dialednone && ((mysig == SIG_EM) || (mysig == SIG_EM_E1) ||  (mysig == SIG_EMWINK) || (mysig == SIG_FEATD) || (mysig == SIG_FEATDMF_TA) || (mysig == SIG_FEATDMF) || (mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF) || (mysig == SIG_FEATB) || (mysig == SIG_SF) || (mysig == SIG_SFWINK) || (mysig == SIG_SF_FEATD) || (mysig == SIG_SF_FEATDMF) || (mysig == SIG_SF_FEATB)))) {
                                                        ast_setstate(ast, AST_STATE_RINGING);
                                                } else if (!p->answeronpolarityswitch) {
@@ -4068,16 +4178,14 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                                        return NULL;
                                                }
                                                mssinceflash = ast_tvdiff_ms(ast_tvnow(), p->flashtime);
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "Last flash was %d ms ago\n", mssinceflash);
+                                               ast_debug(1, "Last flash was %d ms ago\n", mssinceflash);
                                                if (mssinceflash < MIN_MS_SINCE_FLASH) {
                                                        /* It hasn't been long enough since the last flashook.  This is probably a bounce on 
                                                           hanging up.  Hangup both channels now */
                                                        if (p->subs[SUB_THREEWAY].owner)
                                                                ast_queue_hangup(p->subs[SUB_THREEWAY].owner);
                                                        p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
-                                                       if (option_debug)
-                                                               ast_log(LOG_DEBUG, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
+                                                       ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
                                                        ast_mutex_unlock(&p->subs[SUB_THREEWAY].owner->lock);
                                                } else if ((ast->pbx) || (ast->_state == AST_STATE_UP)) {
                                                        if (p->transfer) {
@@ -4185,11 +4293,10 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                        p->subs[index].f.subclass = AST_CONTROL_ANSWER;
                                        /* Make sure it stops ringing */
                                        zt_set_hook(p->subs[index].zfd, ZT_OFFHOOK);
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "channel %d answered\n", p->channel);
+                                       ast_debug(1, "channel %d answered\n", p->channel);
                                        if (p->cidspill) {
                                                /* Cancel any running CallerID spill */
-                                               free(p->cidspill);
+                                               ast_free(p->cidspill);
                                                p->cidspill = NULL;
                                        }
                                        p->dialing = 0;
@@ -4206,8 +4313,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                                        p->dop.dialstr[0] = '\0';
                                                        return NULL;
                                                } else {
-                                                       if (option_debug)
-                                                               ast_log(LOG_DEBUG, "Sent FXO deferred digit string: %s\n", p->dop.dialstr);
+                                                       ast_debug(1, "Sent FXO deferred digit string: %s\n", p->dop.dialstr);
                                                        p->subs[index].f.frametype = AST_FRAME_NULL;
                                                        p->subs[index].f.subclass = 0;
                                                        p->dialing = 1;
@@ -4222,8 +4328,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                        ast->rings = 1;
                                        p->subs[index].f.frametype = AST_FRAME_CONTROL;
                                        p->subs[index].f.subclass = AST_CONTROL_OFFHOOK;
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "channel %d picked up\n", p->channel);
+                                       ast_debug(1, "channel %d picked up\n", p->channel);
                                        return &p->subs[index].f;
                                case AST_STATE_UP:
                                        /* Make sure it stops ringing */
@@ -4253,10 +4358,9 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
 
                                /* If we get a ring then we cannot be in 
                                 * reversed polarity. So we reset to idle */
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Setting IDLE polarity due "
-                                               "to ring. Old polarity was %d\n", 
-                                               p->polarity);
+                               ast_debug(1, "Setting IDLE polarity due "
+                                       "to ring. Old polarity was %d\n", 
+                                       p->polarity);
                                p->polarity = POLARITY_IDLE;
 
                                /* Fall through */
@@ -4278,13 +4382,11 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                if (ast->_state == AST_STATE_PRERING)
                                        ast_setstate(ast, AST_STATE_RING);
                                if ((ast->_state == AST_STATE_DOWN) || (ast->_state == AST_STATE_RING)) {
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Ring detected\n");
+                                       ast_debug(1, "Ring detected\n");
                                        p->subs[index].f.frametype = AST_FRAME_CONTROL;
                                        p->subs[index].f.subclass = AST_CONTROL_RING;
                                } else if (p->outgoing && ((ast->_state == AST_STATE_RINGING) || (ast->_state == AST_STATE_DIALING))) {
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Line answered\n");
+                                       ast_debug(1, "Line answered\n");
                                        if (p->confirmanswer) {
                                                p->subs[index].f.frametype = AST_FRAME_NULL;
                                                p->subs[index].f.subclass = 0;
@@ -4319,7 +4421,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                        ast->rings++;
                        if ((ast->rings > p->cidrings) && (p->cidspill)) {
                                ast_log(LOG_WARNING, "Didn't finish Caller-ID spill.  Cancelling.\n");
-                               free(p->cidspill);
+                               ast_free(p->cidspill);
                                p->cidspill = NULL;
                                p->callwaitcas = 0;
                        }
@@ -4361,14 +4463,13 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                break;
                        }
                        /* Remember last time we got a flash-hook */
-                       gettimeofday(&p->flashtime, NULL);
+                       p->flashtime = ast_tvnow();
                        switch (mysig) {
                        case SIG_FXOLS:
                        case SIG_FXOGS:
                        case SIG_FXOKS:
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
-                                               index, p->subs[SUB_REAL].zfd, p->subs[SUB_CALLWAIT].zfd, p->subs[SUB_THREEWAY].zfd);
+                               ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
+                                       index, p->subs[SUB_REAL].zfd, p->subs[SUB_CALLWAIT].zfd, p->subs[SUB_THREEWAY].zfd);
                                p->callwaitcas = 0;
 
                                if (index != SUB_REAL) {
@@ -4381,8 +4482,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                        swap_subs(p, SUB_REAL, SUB_CALLWAIT);
                                        tone_zone_play_tone(p->subs[SUB_REAL].zfd, -1);
                                        p->owner = p->subs[SUB_REAL].owner;
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Making %s the new owner\n", p->owner->name);
+                                       ast_debug(1, "Making %s the new owner\n", p->owner->name);
                                        if (p->owner->_state == AST_STATE_RINGING) {
                                                ast_setstate(p->owner, AST_STATE_UP);
                                                p->subs[SUB_REAL].needanswer = 1;
@@ -4422,8 +4522,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                                if (!((ast->pbx) ||
                                                      (ast->_state == AST_STATE_UP) ||
                                                      (ast->_state == AST_STATE_RING))) {
-                                                       if (option_debug)
-                                                               ast_log(LOG_DEBUG, "Flash when call not up or ringing\n");
+                                                       ast_debug(1, "Flash when call not up or ringing\n");
                                                        goto winkflashdone;
                                                }
                                                if (alloc_sub(p, SUB_THREEWAY)) {
@@ -4450,7 +4549,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                                p->owner = chan;
                                                if (!chan) {
                                                        ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", p->channel);
-                                               } else if (ast_pthread_create(&threadid, &attr, ss_thread, chan)) {
+                                               } else if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
                                                        ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
                                                        res = tone_zone_play_tone(p->subs[SUB_REAL].zfd, ZT_TONE_CONGESTION);
                                                        zt_enable_ec(p);
@@ -4465,14 +4564,13 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                                                        !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
                                                        }
                                                        p->subs[SUB_THREEWAY].needhold = 1;
-                                               }               
+                                               }
                                        }
                                } else {
                                        /* Already have a 3 way call */
                                        if (p->subs[SUB_THREEWAY].inthreeway) {
                                                /* Call is already up, drop the last person */
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "Got flash with three way call up, dropping last call on %d\n", p->channel);
+                                               ast_debug(1, "Got flash with three way call up, dropping last call on %d\n", p->channel);
                                                /* If the primary call isn't answered yet, use it */
                                                if ((p->subs[SUB_REAL].owner->_state != AST_STATE_UP) && (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_UP)) {
                                                        /* Swap back -- we're dropping the real 3-way that isn't finished yet*/
@@ -4505,8 +4603,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                                        p->subs[otherindex].needunhold = 1;
                                                        p->owner = p->subs[SUB_REAL].owner;
                                                        if (ast->_state == AST_STATE_RINGING) {
-                                                               if (option_debug)
-                                                                       ast_log(LOG_DEBUG, "Enabling ringtone on real and threeway\n");
+                                                               ast_debug(1, "Enabling ringtone on real and threeway\n");
                                                                res = tone_zone_play_tone(p->subs[SUB_REAL].zfd, ZT_TONE_RINGTONE);
                                                                res = tone_zone_play_tone(p->subs[SUB_THREEWAY].zfd, ZT_TONE_RINGTONE);
                                                        }
@@ -4538,16 +4635,15 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                        case SIG_FXSGS:
                                if (option_debug) {
                                        if (p->dialing)
-                                               ast_log(LOG_DEBUG, "Ignoring wink on channel %d\n", p->channel);
+                                               ast_debug(1, "Ignoring wink on channel %d\n", p->channel);
                                        else
-                                               ast_log(LOG_DEBUG, "Got wink in weird state %d on channel %d\n", ast->_state, p->channel);
+                                               ast_debug(1, "Got wink in weird state %d on channel %d\n", ast->_state, p->channel);
                                }
                                break;
                        case SIG_FEATDMF_TA:
                                switch (p->whichwink) {
                                case 0:
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "ANI2 set to '%d' and ANI is '%s'\n", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
+                                       ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
                                        snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%d%s#", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
                                        break;
                                case 1:
@@ -4573,10 +4669,9 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                        ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d\n", p->channel);
                                        p->dop.dialstr[0] = '\0';
                                        return NULL;
-                               } else {
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Sent deferred digit string: %s\n", p->dop.dialstr);
-                               }
+                               } else
+                                       ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
+
                                p->dop.dialstr[0] = '\0';
                                break;
                        default:
@@ -4603,10 +4698,9 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                        ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d\n", p->channel);
                                        p->dop.dialstr[0] = '\0';
                                        return NULL;
-                               } else {
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Sent deferred digit string: %s\n", p->dop.dialstr);
-                               }
+                               } else
+                                       ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
+
                                p->dop.dialstr[0] = '\0';
                                p->dop.op = ZT_DIAL_OP_REPLACE;
                                break;
@@ -4618,8 +4712,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                        case SIG_FEATB:
                        case SIG_SF_FEATDMF:
                        case SIG_SF_FEATB:
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p->channel);
+                               ast_debug(1, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p->channel);
                                break;
                        default:
                                break;
@@ -4637,16 +4730,14 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                if (p->answeronpolarityswitch &&
                                    ((ast->_state == AST_STATE_DIALING) ||
                                         (ast->_state == AST_STATE_RINGING))) {
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Answering on polarity switch!\n");
+                                       ast_debug(1, "Answering on polarity switch!\n");
                                        ast_setstate(p->owner, AST_STATE_UP);
                                        if (p->hanguponpolarityswitch) {
-                                               gettimeofday(&p->polaritydelaytv, NULL);
+                                               p->polaritydelaytv = ast_tvnow();
                                        }
-                               } else {
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Ignore switch to REVERSED Polarity on channel %d, state %d\n", p->channel, ast->_state);
-                               }
+                               } else
+                                       ast_debug(1, "Ignore switch to REVERSED Polarity on channel %d, state %d\n", p->channel, ast->_state);
+
                        } 
                        /* Removed else statement from here as it was preventing hangups from ever happening*/
                        /* Added AST_STATE_RING in if statement below to deal with calling party hangups that take place when ringing */
@@ -4655,30 +4746,24 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                               (p->polarity == POLARITY_REV) &&
                                ((ast->_state == AST_STATE_UP) || (ast->_state == AST_STATE_RING)) ) {
                                 /* Added log_debug information below to provide a better indication of what is going on */
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Polarity Reversal event occured - DEBUG 1: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %d\n", p->channel, ast->_state, p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) );
+                               ast_debug(1, "Polarity Reversal event occured - DEBUG 1: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %d\n", p->channel, ast->_state, p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) );
                        
                                if (ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) > p->polarityonanswerdelay) {
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Polarity Reversal detected and now Hanging up on channel %d\n", p->channel);
+                                       ast_debug(1, "Polarity Reversal detected and now Hanging up on channel %d\n", p->channel);
                                        ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
                                        p->polarity = POLARITY_IDLE;
-                               } else {
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Polarity Reversal detected but NOT hanging up (too close to answer event) on channel %d, state %d\n", p->channel, ast->_state);
-                               }
+                               } else
+                                       ast_debug(1, "Polarity Reversal detected but NOT hanging up (too close to answer event) on channel %d, state %d\n", p->channel, ast->_state);
+
                        } else {
                                p->polarity = POLARITY_IDLE;
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Ignoring Polarity switch to IDLE on channel %d, state %d\n", p->channel, ast->_state);
+                               ast_debug(1, "Ignoring Polarity switch to IDLE on channel %d, state %d\n", p->channel, ast->_state);
                        }
                        /* Added more log_debug information below to provide a better indication of what is going on */
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Polarity Reversal event occured - DEBUG 2: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %d\n", p->channel, ast->_state, p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) );
+                       ast_debug(1, "Polarity Reversal event occured - DEBUG 2: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %d\n", p->channel, ast->_state, p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) );
                        break;
                default:
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Dunno what to do with event %d on channel %d\n", res, p->channel);
+                       ast_debug(1, "Dunno what to do with event %d on channel %d\n", res, p->channel);
        }
        return &p->subs[index].f;
 }
@@ -4719,8 +4804,7 @@ static struct ast_frame *__zt_exception(struct ast_channel *ast)
                /* Switch to real if there is one and this isn't something really silly... */
                if ((res != ZT_EVENT_RINGEROFF) && (res != ZT_EVENT_RINGERON) &&
                        (res != ZT_EVENT_HOOKCOMPLETE)) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Restoring owner of channel %d on event %d\n", p->channel, res);
+                       ast_debug(1, "Restoring owner of channel %d on event %d\n", p->channel, res);
                        p->owner = p->subs[SUB_REAL].owner;
                        if (p->owner && ast_bridged_channel(p->owner))
                                ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
@@ -4752,7 +4836,7 @@ static struct ast_frame *__zt_exception(struct ast_channel *ast)
                        /* Do nothing */
                        break;
                case ZT_EVENT_WINKFLASH:
-                       gettimeofday(&p->flashtime, NULL);
+                       p->flashtime = ast_tvnow();
                        if (p->owner) {
                                if (option_verbose > 2) 
                                        ast_verbose(VERBOSE_PREFIX_3 "Channel %d flashed to other channel %s\n", p->channel, p->owner->name);
@@ -4779,10 +4863,8 @@ static struct ast_frame *__zt_exception(struct ast_channel *ast)
                f = &p->subs[index].f;
                return f;
        }
-       if (!(p->radio || (p->oprmode < 0))) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Exception on %d, channel %d\n", ast->fds[0],p->channel);
-       }
+       if (!(p->radio || (p->oprmode < 0))) 
+               ast_debug(1, "Exception on %d, channel %d\n", ast->fds[0],p->channel);
        /* If it's not us, return NULL immediately */
        if (ast != p->owner) {
                ast_log(LOG_WARNING, "We're %s, not %s\n", ast->name, p->owner->name);
@@ -4925,8 +5007,7 @@ static struct ast_frame  *zt_read(struct ast_channel *ast)
                p->subs[index].f.frametype = AST_FRAME_CONTROL;
                p->subs[index].f.subclass = AST_CONTROL_HOLD;
                ast_mutex_unlock(&p->lock);
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Sending hold on '%s'\n", ast->name);
+               ast_debug(1, "Sending hold on '%s'\n", ast->name);
                return &p->subs[index].f;
        }       
        
@@ -4936,8 +5017,7 @@ static struct ast_frame  *zt_read(struct ast_channel *ast)
                p->subs[index].f.frametype = AST_FRAME_CONTROL;
                p->subs[index].f.subclass = AST_CONTROL_UNHOLD;
                ast_mutex_unlock(&p->lock);
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Sending unhold on '%s'\n", ast->name);
+               ast_debug(1, "Sending unhold on '%s'\n", ast->name);
                return &p->subs[index].f;
        }       
        
@@ -4982,8 +5062,7 @@ static struct ast_frame  *zt_read(struct ast_channel *ast)
                return f;
        }
        if (res != (p->subs[index].linear ? READ_SIZE * 2 : READ_SIZE)) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Short read (%d/%d), must be an event...\n", res, p->subs[index].linear ? READ_SIZE * 2 : READ_SIZE);
+               ast_debug(1, "Short read (%d/%d), must be an event...\n", res, p->subs[index].linear ? READ_SIZE * 2 : READ_SIZE);
                f = __zt_exception(ast);
                ast_mutex_unlock(&p->lock);
                return f;
@@ -4993,8 +5072,7 @@ static struct ast_frame  *zt_read(struct ast_channel *ast)
 
                c = tdd_feed(p->tdd,readbuf,READ_SIZE);
                if (c < 0) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG,"tdd_feed failed\n");
+                       ast_debug(1,"tdd_feed failed\n");
                        ast_mutex_unlock(&p->lock);
                        return NULL;
                }
@@ -5040,10 +5118,9 @@ static struct ast_frame  *zt_read(struct ast_channel *ast)
        p->subs[index].f.samples = READ_SIZE;
        p->subs[index].f.mallocd = 0;
        p->subs[index].f.offset = AST_FRIENDLY_OFFSET;
-       p->subs[index].f.data = p->subs[index].buffer + AST_FRIENDLY_OFFSET/2;
+       p->subs[index].f.data = p->subs[index].buffer + AST_FRIENDLY_OFFSET / sizeof(p->subs[index].buffer[0]);
 #if 0
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Read %d of voice on %s\n", p->subs[index].f.datalen, ast->name);
+       ast_debug(1, "Read %d of voice on %s\n", p->subs[index].f.datalen, ast->name);
 #endif 
        if (p->dialing || /* Transmitting something */
           (index && (ast->_state != AST_STATE_UP)) || /* Three-way or callwait that isn't up */
@@ -5071,7 +5148,9 @@ static struct ast_frame  *zt_read(struct ast_channel *ast)
                                }
                        } else if (f->frametype == AST_FRAME_DTMF) {
 #ifdef HAVE_PRI
-                               if (!p->proceeding && p->sig==SIG_PRI && p->pri && p->pri->overlapdial) {
+                               if (!p->proceeding && p->sig==SIG_PRI && p->pri && 
+                                   ((!p->outgoing && (p->pri->overlapdial & ZAP_OVERLAPDIAL_INCOMING)) ||
+                                    (p->outgoing && (p->pri->overlapdial & ZAP_OVERLAPDIAL_OUTGOING)))) {
                                        /* Don't accept in-band DTMF when in overlap dial mode */
                                        f->frametype = AST_FRAME_NULL;
                                        f->subclass = 0;
@@ -5083,75 +5162,9 @@ static struct ast_frame  *zt_read(struct ast_channel *ast)
                }
        } else 
                f = &p->subs[index].f; 
-       if (f && (f->frametype == AST_FRAME_DTMF)) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "DTMF digit: %c on %s\n", f->subclass, ast->name);
-               if (p->confirmanswer) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Confirm answer on %s!\n", ast->name);
-                       /* Upon receiving a DTMF digit, consider this an answer confirmation instead
-                          of a DTMF digit */
-                       p->subs[index].f.frametype = AST_FRAME_CONTROL;
-                       p->subs[index].f.subclass = AST_CONTROL_ANSWER;
-                       f = &p->subs[index].f;
-                       /* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
-                       p->confirmanswer = 0;
-               } else if (p->callwaitcas) {
-                       if ((f->subclass == 'A') || (f->subclass == 'D')) {
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Got some DTMF, but it's for the CAS\n");
-                               if (p->cidspill)
-                                       free(p->cidspill);
-                               send_cwcidspill(p);
-                       }
-                       if ((f->subclass != 'm') && (f->subclass != 'u')) 
-                               p->callwaitcas = 0;
-                       p->subs[index].f.frametype = AST_FRAME_NULL;
-                       p->subs[index].f.subclass = 0;
-                       f = &p->subs[index].f;
-               } else if (f->subclass == 'f') {
-                       /* Fax tone -- Handle and return NULL */
-                       if (!p->faxhandled) {
-                               p->faxhandled++;
-                               if (strcmp(ast->exten, "fax")) {
-                                       const char *target_context = S_OR(ast->macrocontext, ast->context);
-
-                                       if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) {
-                                               if (option_verbose > 2)
-                                                       ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", ast->name);
-                                               /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
-                                               pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
-                                               if (ast_async_goto(ast, target_context, "fax", 1))
-                                                       ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
-                                       } else
-                                               ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
-                               } else {
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n");
-                               }
-                       } else {
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Fax already handled\n");
-                       }
-                       zt_confmute(p, 0);
-                       p->subs[index].f.frametype = AST_FRAME_NULL;
-                       p->subs[index].f.subclass = 0;
-                       f = &p->subs[index].f;
-               } else if (f->subclass == 'm') {
-                       /* Confmute request */
-                       zt_confmute(p, 1);
-                       p->subs[index].f.frametype = AST_FRAME_NULL;
-                       p->subs[index].f.subclass = 0;
-                       f = &p->subs[index].f;          
-               } else if (f->subclass == 'u') {
-                       /* Unmute */
-                       zt_confmute(p, 0);
-                       p->subs[index].f.frametype = AST_FRAME_NULL;
-                       p->subs[index].f.subclass = 0;
-                       f = &p->subs[index].f;          
-               } else
-                       zt_confmute(p, 0);
-       }
+
+       if (f && (f->frametype == AST_FRAME_DTMF))
+               zt_handle_dtmfup(ast, index, &f);
 
        /* If we have a fake_event, trigger exception to handle it */
        if (p->fake_event)
@@ -5174,8 +5187,7 @@ static int my_zt_write(struct zt_pvt *p, unsigned char *buf, int len, int index,
                        size = (linear ? READ_SIZE * 2 : READ_SIZE);
                res = write(fd, buf, size);
                if (res != size) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
+                       ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
                        return sent;
                }
                len -= size;
@@ -5225,18 +5237,15 @@ static int zt_write(struct ast_channel *ast, struct ast_frame *frame)
                return -1;
        }
        if (p->dialing) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Dropping frame since I'm still dialing on %s...\n",ast->name);
+               ast_debug(1, "Dropping frame since I'm still dialing on %s...\n",ast->name);
                return 0;
        }
        if (!p->owner) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Dropping frame since there is no active owner on %s...\n",ast->name);
+               ast_debug(1, "Dropping frame since there is no active owner on %s...\n",ast->name);
                return 0;
        }
        if (p->cidspill) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Dropping frame since I've still got a callerid spill\n");
+               ast_debug(1, "Dropping frame since I've still got a callerid spill\n");
                return 0;
        }
        /* Return if it's not valid data */
@@ -5280,8 +5289,7 @@ static int zt_indicate(struct ast_channel *chan, int condition, const void *data
        int func = ZT_FLASH;
        ast_mutex_lock(&p->lock);
        index = zt_get_index(chan, p, 0);
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Requested indication %d on channel %s\n", condition, chan->name);
+       ast_debug(1, "Requested indication %d on channel %s\n", condition, chan->name);
        if (index == SUB_REAL) {
                switch (condition) {
                case AST_CONTROL_BUSY:
@@ -5341,8 +5349,7 @@ static int zt_indicate(struct ast_channel *chan, int condition, const void *data
                        }
                        break;
                case AST_CONTROL_PROCEEDING:
-                       if (option_debug)
-                               ast_log(LOG_DEBUG,"Received AST_CONTROL_PROCEEDING on %s\n",chan->name);
+                       ast_debug(1,"Received AST_CONTROL_PROCEEDING on %s\n",chan->name);
 #ifdef HAVE_PRI
                        if (!p->proceeding && p->sig==SIG_PRI && p->pri && !p->outgoing) {
                                if (p->pri->pri) {              
@@ -5371,8 +5378,7 @@ static int zt_indicate(struct ast_channel *chan, int condition, const void *data
                        res = 0;
                        break;
                case AST_CONTROL_PROGRESS:
-                       if (option_debug)
-                               ast_log(LOG_DEBUG,"Received AST_CONTROL_PROGRESS on %s\n",chan->name);
+                       ast_debug(1,"Received AST_CONTROL_PROGRESS on %s\n",chan->name);
 #ifdef HAVE_PRI
                        p->digital = 0; /* Digital-only calls isn't allows any inband progress messages */
                        if (!p->progress && p->sig==SIG_PRI && p->pri && !p->outgoing) {
@@ -5486,12 +5492,32 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
        int res;
        int x,y;
        int features;
+       struct ast_str *chan_name;
        ZT_PARAMS ps;
        if (i->subs[index].owner) {
                ast_log(LOG_WARNING, "Channel %d already has a %s call\n", i->channel,subnames[index]);
                return NULL;
        }
-       if (!(tmp = ast_channel_alloc(0)))
+       y = 1;
+       chan_name = ast_str_alloca(32);
+       do {
+#ifdef HAVE_PRI
+               if (i->bearer || (i->pri && (i->sig == SIG_FXSKS)))
+                       ast_str_set(&chan_name, 0, "%d:%d-%d", i->pri->trunkgroup, i->channel, y);
+               else
+#endif
+               if (i->channel == CHAN_PSEUDO)
+                       ast_str_set(&chan_name, 0, "pseudo-%ld", ast_random());
+               else    
+                       ast_str_set(&chan_name, 0, "%d-%d", i->channel, y);
+               for (x = 0; x < 3; x++) {
+                       if ((index != x) && i->subs[x].owner && !strcasecmp(chan_name->str, i->subs[x].owner->name))
+                               break;
+               }
+               y++;
+       } while (x < 3);
+       tmp = ast_channel_alloc(0, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "Zap/%s", chan_name->str);
+       if (!tmp)
                return NULL;
        tmp->tech = &zap_tech;
        ps.channo = i->channel;
@@ -5510,23 +5536,6 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
                else
                        deflaw = AST_FORMAT_ULAW;
        }
-       y = 1;
-       do {
-#ifdef HAVE_PRI
-               if (i->bearer || (i->pri && (i->sig == SIG_FXSKS)))
-                       ast_string_field_build(tmp, name, "Zap/%d:%d-%d", i->pri->trunkgroup, i->channel, y);
-               else
-#endif
-               if (i->channel == CHAN_PSEUDO)
-                       ast_string_field_build(tmp, name, "Zap/pseudo-%d", ast_random());
-               else    
-                       ast_string_field_build(tmp, name, "Zap/%d-%d", i->channel, y);
-               for (x = 0; x < 3; x++) {
-                       if ((index != x) && i->subs[x].owner && !strcasecmp(tmp->name, i->subs[x].owner->name))
-                               break;
-               }
-               y++;
-       } while (x < 3);
        tmp->fds[0] = i->subs[index].zfd;
        tmp->nativeformats = AST_FORMAT_SLINEAR | deflaw;
        /* Start out assuming ulaw since it's smaller :) */
@@ -5537,30 +5546,31 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
        i->subs[index].linear = 0;
        zt_setlinear(i->subs[index].zfd, i->subs[index].linear);
        features = 0;
-       if (i->busydetect && CANBUSYDETECT(i))
-               features |= DSP_FEATURE_BUSY_DETECT;
-       if ((i->callprogress & 1) && CANPROGRESSDETECT(i))
-               features |= DSP_FEATURE_CALL_PROGRESS;
-       if ((!i->outgoing && (i->callprogress & 4)) || 
-           (i->outgoing && (i->callprogress & 2))) {
-               features |= DSP_FEATURE_FAX_DETECT;
-       }
+       if (index == SUB_REAL) {
+               if (i->busydetect && CANBUSYDETECT(i))
+                       features |= DSP_FEATURE_BUSY_DETECT;
+               if ((i->callprogress & 1) && CANPROGRESSDETECT(i))
+                       features |= DSP_FEATURE_CALL_PROGRESS;
+               if ((!i->outgoing && (i->callprogress & 4)) || 
+                   (i->outgoing && (i->callprogress & 2))) {
+                       features |= DSP_FEATURE_FAX_DETECT;
+               }
 #ifdef ZT_TONEDETECT
-       x = ZT_TONEDETECT_ON | ZT_TONEDETECT_MUTE;
-       if (ioctl(i->subs[index].zfd, ZT_TONEDETECT, &x)) {
+               x = ZT_TONEDETECT_ON | ZT_TONEDETECT_MUTE;
+               if (ioctl(i->subs[index].zfd, ZT_TONEDETECT, &x)) {
 #endif         
-               i->hardwaredtmf = 0;
-               features |= DSP_FEATURE_DTMF_DETECT;
+                       i->hardwaredtmf = 0;
+                       features |= DSP_FEATURE_DTMF_DETECT;
 #ifdef ZT_TONEDETECT
-       } else if (NEED_MFDETECT(i)) {
-               i->hardwaredtmf = 1;
-               features |= DSP_FEATURE_DTMF_DETECT;
-       }
+               } else if (NEED_MFDETECT(i)) {
+                       i->hardwaredtmf = 1;
+                       features |= DSP_FEATURE_DTMF_DETECT;
+               }
 #endif
+       }
        if (features) {
                if (i->dsp) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Already have a dsp on %s?\n", tmp->name);
+                       ast_debug(1, "Already have a dsp on %s?\n", tmp->name);
                } else {
                        if (i->channel != CHAN_PSEUDO)
                                i->dsp = ast_dsp_new();
@@ -5617,13 +5627,13 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
        if (!ast_strlen_zero(i->dnid))
                tmp->cid.cid_dnid = ast_strdup(i->dnid);
 
-#ifdef PRI_ANI
        /* Don't use ast_set_callerid() here because it will
-        * generate a NewCallerID event before the NewChannel event */
+        * generate a needless NewCallerID event */
+#ifdef PRI_ANI
        tmp->cid.cid_num = ast_strdup(i->cid_num);
        tmp->cid.cid_name = ast_strdup(i->cid_name);
        if (!ast_strlen_zero(i->cid_ani))
-               tmp->cid.cid_ani = ast_strdup(i->cid_num);
+               tmp->cid.cid_ani = ast_strdup(i->cid_ani);
        else    
                tmp->cid.cid_ani = ast_strdup(i->cid_num);
 #else
@@ -5646,7 +5656,6 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
        i->fake_event = 0;
        /* Assure there is no confmute on this channel */
        zt_confmute(i, 0);
-       ast_setstate(tmp, state);
        /* Configure the new channel jb */
        ast_jb_configure(tmp, &global_jbconf);
        if (startpbx) {
@@ -5658,9 +5667,7 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
                }
        }
 
-       ast_atomic_fetchadd_int(&usecnt, 1);
-       ast_update_use_count();
-       
+       ast_module_ref(ast_module_info->self);
        return tmp;
 }
 
@@ -5729,6 +5736,15 @@ static void *ss_thread(void *data)
        int res;
        int index;
 
+       /* in the bizarre case where the channel has become a zombie before we
+          even get started here, abort safely
+       */
+       if (!p) {
+               ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", chan->name);
+               ast_hangup(chan);
+               return NULL;
+       }
+
        if (option_verbose > 2) 
                ast_verbose( VERBOSE_PREFIX_3 "Starting simple switch on '%s'\n", chan->name);
        index = zt_get_index(chan, p, 1);
@@ -5757,8 +5773,7 @@ static void *ss_thread(void *data)
                                timeout = gendigittimeout;
                        res = ast_waitfordigit(chan, timeout);
                        if (res < 0) {
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "waitfordigit returned < 0...\n");
+                               ast_debug(1, "waitfordigit returned < 0...\n");
                                ast_hangup(chan);
                                return NULL;
                        } else if (res) {
@@ -5786,8 +5801,7 @@ static void *ss_thread(void *data)
                                ast_log(LOG_WARNING, "PBX exited non-zero!\n");
                        }
                } else {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "No such possible extension '%s' in context '%s'\n", exten, chan->context);
+                       ast_debug(1, "No such possible extension '%s' in context '%s'\n", exten, chan->context);
                        chan->hangupcause = AST_CAUSE_UNALLOCATED;
                        ast_hangup(chan);
                        p->exten[0] = '\0';
@@ -5906,8 +5920,7 @@ static void *ss_thread(void *data)
                                        }
                                        res = ast_waitfordigit(chan, timeout);
                                        if (res < 0) {
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "waitfordigit returned < 0...\n");
+                                               ast_debug(1, "waitfordigit returned < 0...\n");
                                                ast_hangup(chan);
                                                return NULL;
                                        } else if (res) {
@@ -5925,8 +5938,7 @@ static void *ss_thread(void *data)
                        ast_hangup(chan);
                        return NULL;
                } else if (res < 0) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Got hung up before digits finished\n");
+                       ast_debug(1, "Got hung up before digits finished\n");
                        ast_hangup(chan);
                        return NULL;
                }
@@ -6083,8 +6095,7 @@ static void *ss_thread(void *data)
                                res = ast_waitfordigit(chan, timeout);
                        timeout = 0;
                        if (res < 0) {
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "waitfordigit returned < 0...\n");
+                               ast_debug(1, "waitfordigit returned < 0...\n");
                                res = tone_zone_play_tone(p->subs[index].zfd, -1);
                                ast_hangup(chan);
                                return NULL;
@@ -6141,8 +6152,7 @@ static void *ss_thread(void *data)
                                        timeout = matchdigittimeout;
                                }
                        } else if (res == 0) {
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "not enough digits (and no ambiguous match)...\n");
+                               ast_debug(1, "not enough digits (and no ambiguous match)...\n");
                                res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);
                                zt_wait_event(p->subs[index].zfd);
                                ast_hangup(chan);
@@ -6178,8 +6188,7 @@ static void *ss_thread(void *data)
                                        }
                                        zt_enable_ec(p);
                                        if (ast_pickup_call(chan)) {
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "No call pickup possible...\n");
+                                               ast_debug(1, "No call pickup possible...\n");
                                                res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);
                                                zt_wait_event(p->subs[index].zfd);
                                        }
@@ -6197,10 +6206,10 @@ static void *ss_thread(void *data)
                                /* Disable Caller*ID if enabled */
                                p->hidecallerid = 1;
                                if (chan->cid.cid_num)
-                                       free(chan->cid.cid_num);
+                                       ast_free(chan->cid.cid_num);
                                chan->cid.cid_num = NULL;
                                if (chan->cid.cid_name)
-                                       free(chan->cid.cid_name);
+                                       ast_free(chan->cid.cid_name);
                                chan->cid.cid_name = NULL;
                                res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);
                                if (res) {
@@ -6279,10 +6288,10 @@ static void *ss_thread(void *data)
                                /* Enable Caller*ID if enabled */
                                p->hidecallerid = 0;
                                if (chan->cid.cid_num)
-                                       free(chan->cid.cid_num);
+                                       ast_free(chan->cid.cid_num);
                                chan->cid.cid_num = NULL;
                                if (chan->cid.cid_name)
-                                       free(chan->cid.cid_name);
+                                       ast_free(chan->cid.cid_name);
                                chan->cid.cid_name = NULL;
                                ast_set_callerid(chan, p->cid_num, p->cid_name, NULL);
                                res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);
@@ -6331,8 +6340,7 @@ static void *ss_thread(void *data)
                                }                                       
                        } else if (!ast_canmatch_extension(chan, chan->context, exten, 1, chan->cid.cid_num) &&
                                                        ((exten[0] != '*') || (strlen(exten) > 2))) {
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Can't match %s from '%s' in context %s\n", exten, chan->cid.cid_num ? chan->cid.cid_num : "<Unknown Caller>", chan->context);
+                               ast_debug(1, "Can't match %s from '%s' in context %s\n", exten, chan->cid.cid_num ? chan->cid.cid_num : "<Unknown Caller>", chan->context);
                                break;
                        }
                        if (!timeout)
@@ -6367,8 +6375,7 @@ static void *ss_thread(void *data)
                                                res = 0;
                                        ast_frfree(f);
                                        if (res) {
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "Got ring!\n");
+                                               ast_debug(1, "Got ring!\n");
                                                res = 0;
                                                break;
                                        }
@@ -6388,8 +6395,7 @@ static void *ss_thread(void *data)
                                else if (smdi_msg->type == 'N')
                                        pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "u");
 
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Recieved SMDI message on %s\n", chan->name);
+                               ast_debug(1, "Recieved SMDI message on %s\n", chan->name);
                        } else {
                                ast_log(LOG_WARNING, "SMDI enabled but no SMDI message present\n");
                        }
@@ -6401,14 +6407,13 @@ static void *ss_thread(void *data)
                /* If we want caller id, we're in a prering state due to a polarity reversal
                 * and we're set to use a polarity reversal to trigger the start of caller id,
                 * grab the caller id and wait for ringing to start... */
-               } else if (p->use_callerid && (chan->_state == AST_STATE_PRERING && p->cid_start == CID_START_POLARITY)) {
+               } else if (p->use_callerid && (chan->_state == AST_STATE_PRERING && (p->cid_start == CID_START_POLARITY || p->cid_start == CID_START_POLARITY_IN))) {
                        /* If set to use DTMF CID signalling, listen for DTMF */
                        if (p->cid_signalling == CID_SIG_DTMF) {
                                int i = 0;
                                cs = NULL;
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Receiving DTMF cid on "
-                                               "channel %s\n", chan->name);
+                               ast_debug(1, "Receiving DTMF cid on "
+                                       "channel %s\n", chan->name);
                                zt_setlinear(p->subs[index].zfd, 0);
                                res = 2000;
                                for (;;) {
@@ -6423,8 +6428,7 @@ static void *ss_thread(void *data)
                                        f = ast_read(chan);
                                        if (f->frametype == AST_FRAME_DTMF) {
                                                dtmfbuf[i++] = f->subclass;
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "CID got digit '%c'\n", f->subclass);
+                                               ast_debug(1, "CID got digit '%c'\n", f->subclass);
                                                res = 2000;
                                        }
                                        ast_frfree(f);
@@ -6435,12 +6439,10 @@ static void *ss_thread(void *data)
                                dtmfbuf[i] = '\0';
                                zt_setlinear(p->subs[index].zfd, p->subs[index].linear);
                                /* Got cid and ring. */
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "CID got string '%s'\n", dtmfbuf);
+                               ast_debug(1, "CID got string '%s'\n", dtmfbuf);
                                callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "CID is '%s', flags %d\n", 
-                                               dtmfcid, flags);
+                               ast_debug(1, "CID is '%s', flags %d\n", 
+                                       dtmfcid, flags);
                                /* If first byte is NULL, we have no cid */
                                if (!ast_strlen_zero(dtmfcid)) 
                                        number = dtmfcid;
@@ -6604,17 +6606,26 @@ static void *ss_thread(void *data)
                                                if (option_verbose > 2)
                                                        /* this only shows up if you have n of the dring patterns filled in */
                                                        ast_verbose( VERBOSE_PREFIX_3 "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
-       
                                                for (counter = 0; counter < 3; counter++) {
                                                        /* Check to see if the rings we received match any of the ones in zapata.conf for this
                                                        channel */
                                                        distMatches = 0;
                                                        for (counter1 = 0; counter1 < 3; counter1++) {
-                                                               if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1]+10) && curRingData[counter1] >=
-                                                               (p->drings.ringnum[counter].ring[counter1]-10)) {
+                                                               ast_verbose( VERBOSE_PREFIX_3 "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
+                                                               if (p->drings.ringnum[counter].ring[counter1] == -1) {
+                                                                       ast_verbose( VERBOSE_PREFIX_3 "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
+                                                                       curRingData[counter1]);
+                                                                       distMatches++;
+                                                               }
+                                                               else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
+                                                                   curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
+                                                                       ast_verbose( VERBOSE_PREFIX_3 "Ring pattern matched in range: %d to %d\n",
+                                                                       (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
+                                                                       (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
                                                                        distMatches++;
                                                                }
                                                        }
+
                                                        if (distMatches == 3) {
                                                                /* The ring matches, set the context to whatever is for distinctive ring.. */
                                                                ast_copy_string(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context));
@@ -6642,6 +6653,45 @@ static void *ss_thread(void *data)
                                return NULL;
                        }
                } else if (p->use_callerid && p->cid_start == CID_START_RING) {
+                        if (p->cid_signalling == CID_SIG_DTMF) {
+                                int i = 0;
+                                cs = NULL;
+                                zt_setlinear(p->subs[index].zfd, 0);
+                                res = 2000;
+                                for (;;) {
+                                        struct ast_frame *f;
+                                        res = ast_waitfor(chan, res);
+                                        if (res <= 0) {
+                                                ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
+                                                                "Exiting simple switch\n");
+                                                ast_hangup(chan);
+                                                return NULL;
+                                        }
+                                        f = ast_read(chan);
+                                        if (f->frametype == AST_FRAME_DTMF) {
+                                                dtmfbuf[i++] = f->subclass;
+                                                ast_log(LOG_DEBUG, "CID got digit '%c'\n", f->subclass);
+                                                res = 2000;
+                                        }
+                                        ast_frfree(f);
+
+                                        if (p->ringt_base == p->ringt)
+                                                break;
+
+                                }
+                                dtmfbuf[i] = '\0';
+                                zt_setlinear(p->subs[index].zfd, p->subs[index].linear);
+                                /* Got cid and ring. */
+                                callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
+                                ast_log(LOG_DEBUG, "CID is '%s', flags %d\n",
+                                                dtmfcid, flags);
+                                /* If first byte is NULL, we have no cid */
+                                if (!ast_strlen_zero(dtmfcid))
+                                        number = dtmfcid;
+                                else
+                                        number = NULL;
+                                /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
+                        } else {
                        /* FSK Bell202 callerID */
                        cs = callerid_new(p->cid_signalling);
                        if (cs) {
@@ -6717,8 +6767,7 @@ static void *ss_thread(void *data)
                                }
                                if (res == 1) {
                                        callerid_get(cs, &name, &number, &flags);
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
+                                       ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
                                }
                                if (distinctiveringaftercid == 1) {
                                        /* Clear the current ring data array so we dont have old data in it. */
@@ -6786,8 +6835,17 @@ static void *ss_thread(void *data)
                                                                p->drings.ringnum[counter].ring[2]);
                                                distMatches = 0;
                                                for (counter1 = 0; counter1 < 3; counter1++) {
-                                                       if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1]+10) && curRingData[counter1] >=
-                                                       (p->drings.ringnum[counter].ring[counter1]-10)) {
+                                                       ast_verbose( VERBOSE_PREFIX_3 "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
+                                                       if (p->drings.ringnum[counter].ring[counter1] == -1) {
+                                                               ast_verbose( VERBOSE_PREFIX_3 "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
+                                                               curRingData[counter1]);
+                                                               distMatches++;
+                                                       }
+                                                       else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
+                                                           curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
+                                                               ast_verbose( VERBOSE_PREFIX_3 "Ring pattern matched in range: %d to %d\n",
+                                                               (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
+                                                               (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
                                                                distMatches++;
                                                        }
                                                }
@@ -6812,6 +6870,7 @@ static void *ss_thread(void *data)
                        } else
                                ast_log(LOG_WARNING, "Unable to get caller ID space\n");
                }
+               }
                else
                        cs = NULL;
 
@@ -6847,14 +6906,30 @@ static void *ss_thread(void *data)
        return NULL;
 }
 
+/* destroy a zaptel channel, identified by its number */
+static int zap_destroy_channel_bynum(int channel)
+{
+       struct zt_pvt *tmp = NULL;
+       struct zt_pvt *prev = NULL;
+
+       tmp = iflist;
+       while (tmp) {
+               if (tmp->channel == channel) {
+                       destroy_channel(prev, tmp, 1);
+                       return RESULT_SUCCESS;
+               }
+               prev = tmp;
+               tmp = tmp->next;
+       }
+       return RESULT_FAILURE;
+}
+
 static int handle_init_event(struct zt_pvt *i, int event)
 {
        int res;
        pthread_t threadid;
-       pthread_attr_t attr;
        struct ast_channel *chan;
-       pthread_attr_init(&attr);
-       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
        /* Handle an event on a given channel for the monitor thread. */
        switch (event) {
        case ZT_EVENT_NONE:
@@ -6869,10 +6944,12 @@ static int handle_init_event(struct zt_pvt *i, int event)
                case SIG_FXOLS:
                case SIG_FXOGS:
                case SIG_FXOKS:
-                       zt_set_hook(i->subs[SUB_REAL].zfd, ZT_OFFHOOK);
+                       res = zt_set_hook(i->subs[SUB_REAL].zfd, ZT_OFFHOOK);
+                       if (res && (errno == EBUSY))
+                               break;
                        if (i->cidspill) {
                                /* Cancel VMWI spill */
-                               free(i->cidspill);
+                               ast_free(i->cidspill);
                                i->cidspill = NULL;
                        }
                        if (i->immediate) {
@@ -6896,7 +6973,7 @@ static int handle_init_event(struct zt_pvt *i, int event)
                                                res = tone_zone_play_tone(i->subs[SUB_REAL].zfd, ZT_TONE_DIALTONE);
                                        if (res < 0) 
                                                ast_log(LOG_WARNING, "Unable to play dialtone on channel %d\n", i->channel);
-                                       if (ast_pthread_create(&threadid, &attr, ss_thread, chan)) {
+                                       if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
                                                ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
                                                res = tone_zone_play_tone(i->subs[SUB_REAL].zfd, ZT_TONE_CONGESTION);
                                                if (res < 0)
@@ -6928,8 +7005,12 @@ static int handle_init_event(struct zt_pvt *i, int event)
                case SIG_SF_FEATB:
                case SIG_SF:
                                /* Check for callerid, digits, etc */
-                               chan = zt_new(i, AST_STATE_RING, 0, SUB_REAL, 0, 0);
-                               if (chan && ast_pthread_create(&threadid, &attr, ss_thread, chan)) {
+                               if (i->cid_start == CID_START_POLARITY_IN) {
+                                       chan = zt_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, 0);
+                               } else {
+                                       chan = zt_new(i, AST_STATE_RING, 0, SUB_REAL, 0, 0);
+                               }
+                               if (chan && ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
                                        ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
                                        res = tone_zone_play_tone(i->subs[SUB_REAL].zfd, ZT_TONE_CONGESTION);
                                        if (res < 0)
@@ -7019,13 +7100,13 @@ static int handle_init_event(struct zt_pvt *i, int event)
                case SIG_FXSLS:
                case SIG_FXSKS:
                case SIG_FXSGS:
-                       if (i->cid_start == CID_START_POLARITY) {
+                       if (i->cid_start == CID_START_POLARITY || i->cid_start == CID_START_POLARITY_IN) {
                                i->polarity = POLARITY_REV;
                                ast_verbose(VERBOSE_PREFIX_2 "Starting post polarity "
                                            "CID detection on channel %d\n",
                                            i->channel);
                                chan = zt_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, 0);
-                               if (chan && ast_pthread_create(&threadid, &attr, ss_thread, chan)) {
+                               if (chan && ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
                                        ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
                                }
                        }
@@ -7035,6 +7116,13 @@ static int handle_init_event(struct zt_pvt *i, int event)
                                "polarity reversal on non-FXO (SIG_FXS) "
                                "interface %d\n", i->channel);
                }
+               break;
+       case ZT_EVENT_REMOVED: /* destroy channel */
+               ast_log(LOG_NOTICE, 
+                               "Got ZT_EVENT_REMOVED. Destroying channel %d\n", 
+                               i->channel);
+               zap_destroy_channel_bynum(i->channel);
+               break;
        }
        return 0;
 }
@@ -7057,15 +7145,14 @@ static void *do_monitor(void *data)
                ast_log(LOG_WARNING, "Unable to set cancel type to asynchronous\n");
                return NULL;
        }
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Monitor starting...\n");
+       ast_debug(1, "Monitor starting...\n");
 #endif
        for (;;) {
                /* Lock the interface list */
                ast_mutex_lock(&iflock);
                if (!pfds || (lastalloc != ifcount)) {
                        if (pfds)
-                               free(pfds);
+                               ast_free(pfds);
                        if (ifcount) {
                                if (!(pfds = ast_calloc(1, ifcount * sizeof(*pfds)))) {
                                        ast_mutex_unlock(&iflock);
@@ -7121,11 +7208,10 @@ static void *do_monitor(void *data)
                                        if (last) {
                                                if (!last->cidspill && !last->owner && !ast_strlen_zero(last->mailbox) && (thispass - last->onhooktime > 3) &&
                                                        (last->sig & __ZT_SIG_FXO)) {
-                                                       res = ast_app_has_voicemail(last->mailbox, NULL);
+                                                       res = has_voicemail(last);
                                                        if (last->msgstate != res) {
                                                                int x;
-                                                               if (option_debug)
-                                                                       ast_log(LOG_DEBUG, "Message status for %s changed from %d to %d on %d\n", last->mailbox, last->msgstate, res, last->channel);
+                                                               ast_debug(1, "Message status for %s changed from %d to %d on %d\n", last->mailbox, last->msgstate, res, last->channel);
                                                                x = ZT_FLUSH_BOTH;
                                                                res2 = ioctl(last->subs[SUB_REAL].zfd, ZT_FLUSH, &x);
                                                                if (res2)
@@ -7152,8 +7238,7 @@ static void *do_monitor(void *data)
                                        res = zt_get_event(i->subs[SUB_REAL].zfd);
                                        if (res)
                                        {
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
+                                               ast_debug(1, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
                                                /* Don't hold iflock while handling init events */
                                                ast_mutex_unlock(&iflock);
                                                handle_init_event(i, res);
@@ -7186,7 +7271,7 @@ static void *do_monitor(void *data)
                                                if (res2 > 0) {
                                                        i->cidpos += res2;
                                                        if (i->cidpos >= i->cidlen) {
-                                                               free(i->cidspill);
+                                                               ast_free(i->cidspill);
                                                                i->cidspill = 0;
                                                                i->cidpos = 0;
                                                                i->cidlen = 0;
@@ -7198,8 +7283,7 @@ static void *do_monitor(void *data)
                                        } else {
                                                ast_log(LOG_WARNING, "Read failed with %d: %s\n", res, strerror(errno));
                                        }
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
+                                       ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
                                        /* Don't hold iflock while handling init events -- race with chlock */
                                        ast_mutex_unlock(&iflock);
                                        handle_init_event(i, res);
@@ -7215,8 +7299,7 @@ static void *do_monitor(void *data)
                                                continue;
                                        }
                                        res = zt_get_event(i->subs[SUB_REAL].zfd);
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
+                                       ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
                                        /* Don't hold iflock while handling init events */
                                        ast_mutex_unlock(&iflock);
                                        handle_init_event(i, res);
@@ -7234,9 +7317,6 @@ static void *do_monitor(void *data)
 
 static int restart_monitor(void)
 {
-       pthread_attr_t attr;
-       pthread_attr_init(&attr);
-       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
        /* If we're supposed to be stopped -- stay stopped */
        if (monitor_thread == AST_PTHREADT_STOP)
                return 0;
@@ -7247,17 +7327,11 @@ static int restart_monitor(void)
                return -1;
        }
        if (monitor_thread != AST_PTHREADT_NULL) {
-               /* Just signal it to be sure it wakes up */
-#if 0
-               pthread_cancel(monitor_thread);
-#endif
+               /* Wake up the thread */
                pthread_kill(monitor_thread, SIGURG);
-#if 0
-               pthread_join(monitor_thread, NULL);
-#endif
        } else {
                /* Start a new monitor */
-               if (ast_pthread_create_background(&monitor_thread, &attr, do_monitor, NULL) < 0) {
+               if (ast_pthread_create_detached_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
                        ast_mutex_unlock(&monlock);
                        ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
                        return -1;
@@ -7294,8 +7368,9 @@ static int pri_resolve_span(int *span, int channel, int offset, struct zt_spanin
                } else {
                        if (si->totalchans == 31) { /* if it's an E1 */
                                pris[*span].dchannels[0] = 16 + offset;
-                       } else {
-                               pris[*span].dchannels[0] = 24 + offset;
+                       } else { /* T1 or BRI: D Channel is the last Channel */
+                               pris[*span].dchannels[0] = 
+                                       si->totalchans + offset;
                        }
                        pris[*span].dchanavail[0] |= DCHAN_PROVISIONED;
                        pris[*span].offset = offset;
@@ -7388,7 +7463,7 @@ static unsigned int parse_pointcode(char *pcstring)
        unsigned int code1, code2, code3;
        int numvals;
 
-       numvals = sscanf(pcstring, "%d.%d.%d", &code1, &code2, &code3);
+       numvals = sscanf(pcstring, "%d-%d-%d", &code1, &code2, &code3);
        if (numvals == 1)
                return code1;
        if (numvals == 3)
@@ -7406,7 +7481,7 @@ static struct zt_ss7 * ss7_resolve_linkset(int linkset)
 }
 #endif /* HAVE_SS7 */
 
-static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int radio, struct zt_pri *pri, int reloading)
+static struct zt_pvt *mkintf(int channel, struct zt_chan_conf conf, struct zt_pri *pri, int reloading)
 {
        /* Make a zt_pvt structure for this interface (or CRV if "pri" is specified) */
        struct zt_pvt *tmp = NULL, *tmp2,  *prev = NULL;
@@ -7483,8 +7558,8 @@ static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int
                                        destroy_zt_pvt(&tmp);
                                        return NULL;
                                }
-                               if (p.sigtype != (signalling & 0x3ffff)) {
-                                       ast_log(LOG_ERROR, "Signalling requested on channel %d is %s but line is in %s signalling\n", channel, sig2str(signalling), sig2str(p.sigtype));
+                               if (p.sigtype != (conf.chan.sig & 0x3ffff)) {
+                                       ast_log(LOG_ERROR, "Signalling requested on channel %d is %s but line is in %s signalling\n", channel, sig2str(conf.chan.sig), sig2str(p.sigtype));
                                        destroy_zt_pvt(&tmp);
                                        return NULL;
                                }
@@ -7493,14 +7568,14 @@ static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int
                                span = p.spanno - 1;
                        } else {
                                if (channel == CHAN_PSEUDO)
-                                       signalling = 0;
-                               else if ((signalling != SIG_FXOKS) && (signalling != SIG_FXSKS)) {
+                                       conf.chan.sig = 0;
+                               else if ((conf.chan.sig != SIG_FXOKS) && (conf.chan.sig != SIG_FXSKS)) {
                                        ast_log(LOG_ERROR, "CRV's must use FXO/FXS Kewl Start (fxo_ks/fxs_ks) signalling only.\n");
                                        return NULL;
                                }
                        }
 #ifdef HAVE_SS7
-                       if (signalling == SIG_SS7) {
+                       if (conf.chan.sig == SIG_SS7) {
                                struct zt_ss7 *ss7;
                                int clear = 0;
                                if (ioctl(tmp->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &clear)) {
@@ -7523,19 +7598,30 @@ static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int
 
                                tmp->cic = cur_cicbeginswith++;
 
+                               /* DB: Add CIC's DPC information */
+                               tmp->dpc = cur_defaultdpc;
+
                                tmp->ss7 = ss7;
                                tmp->ss7call = NULL;
                                ss7->pvts[ss7->numchans++] = tmp;
+
+                               ast_copy_string(linksets[span].internationalprefix, conf.ss7.internationalprefix, sizeof(linksets[span].internationalprefix));
+                               ast_copy_string(linksets[span].nationalprefix, conf.ss7.nationalprefix, sizeof(linksets[span].nationalprefix));
+                               ast_copy_string(linksets[span].subscriberprefix, conf.ss7.subscriberprefix, sizeof(linksets[span].subscriberprefix));
+                               ast_copy_string(linksets[span].unknownprefix, conf.ss7.unknownprefix, sizeof(linksets[span].unknownprefix));
+
+                               linksets[span].called_nai = conf.ss7.called_nai;
+                               linksets[span].calling_nai = conf.ss7.calling_nai;
                        }
 #endif
 #ifdef HAVE_PRI
-                       if ((signalling == SIG_PRI) || (signalling == SIG_GR303FXOKS) || (signalling == SIG_GR303FXSKS)) {
+                       if ((conf.chan.sig == SIG_PRI) || (conf.chan.sig == SIG_GR303FXOKS) || (conf.chan.sig == SIG_GR303FXSKS)) {
                                int offset;
                                int myswitchtype;
                                int matchesdchan;
                                int x,y;
                                offset = 0;
-                               if ((signalling == SIG_PRI) && ioctl(tmp->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &offset)) {
+                               if ((conf.chan.sig == SIG_PRI) && ioctl(tmp->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &offset)) {
                                        ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
                                        destroy_zt_pvt(&tmp);
                                        return NULL;
@@ -7559,8 +7645,8 @@ static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int
                                                destroy_zt_pvt(&tmp);
                                                return NULL;
                                        }
-                                       if (signalling == SIG_PRI)
-                                               myswitchtype = switchtype;
+                                       if (conf.chan.sig == SIG_PRI)
+                                               myswitchtype = conf.pri.switchtype;
                                        else
                                                myswitchtype = PRI_SWITCH_GR303_TMC;
                                        /* Make sure this isn't a d-channel */
@@ -7575,7 +7661,7 @@ static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int
                                        }
                                        offset = p.chanpos;
                                        if (!matchesdchan) {
-                                               if (pris[span].nodetype && (pris[span].nodetype != pritype)) {
+                                               if (pris[span].nodetype && (pris[span].nodetype != conf.pri.nodetype)) {
                                                        ast_log(LOG_ERROR, "Span %d is already a %s node\n", span + 1, pri_node2str(pris[span].nodetype));
                                                        destroy_zt_pvt(&tmp);
                                                        return NULL;
@@ -7585,28 +7671,28 @@ static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int
                                                        destroy_zt_pvt(&tmp);
                                                        return NULL;
                                                }
-                                               if ((pris[span].dialplan) && (pris[span].dialplan != dialplan)) {
+                                               if ((pris[span].dialplan) && (pris[span].dialplan != conf.pri.dialplan)) {
                                                        ast_log(LOG_ERROR, "Span %d is already a %s dialing plan\n", span + 1, dialplan2str(pris[span].dialplan));
                                                        destroy_zt_pvt(&tmp);
                                                        return NULL;
                                                }
-                                               if (!ast_strlen_zero(pris[span].idledial) && strcmp(pris[span].idledial, idledial)) {
-                                                       ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, idledial);
+                                               if (!ast_strlen_zero(pris[span].idledial) && strcmp(pris[span].idledial, conf.pri.idledial)) {
+                                                       ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, conf.pri.idledial);
                                                        destroy_zt_pvt(&tmp);
                                                        return NULL;
                                                }
-                                               if (!ast_strlen_zero(pris[span].idleext) && strcmp(pris[span].idleext, idleext)) {
-                                                       ast_log(LOG_ERROR, "Span %d already has idleext '%s'.\n", span + 1, idleext);
+                                               if (!ast_strlen_zero(pris[span].idleext) && strcmp(pris[span].idleext, conf.pri.idleext)) {
+                                                       ast_log(LOG_ERROR, "Span %d already has idleext '%s'.\n", span + 1, conf.pri.idleext);
                                                        destroy_zt_pvt(&tmp);
                                                        return NULL;
                                                }
-                                               if (pris[span].minunused && (pris[span].minunused != minunused)) {
-                                                       ast_log(LOG_ERROR, "Span %d already has minunused of %d.\n", span + 1, minunused);
+                                               if (pris[span].minunused && (pris[span].minunused != conf.pri.minunused)) {
+                                                       ast_log(LOG_ERROR, "Span %d already has minunused of %d.\n", span + 1, conf.pri.minunused);
                                                        destroy_zt_pvt(&tmp);
                                                        return NULL;
                                                }
-                                               if (pris[span].minidle && (pris[span].minidle != minidle)) {
-                                                       ast_log(LOG_ERROR, "Span %d already has minidle of %d.\n", span + 1, minidle);
+                                               if (pris[span].minidle && (pris[span].minidle != conf.pri.minidle)) {
+                                                       ast_log(LOG_ERROR, "Span %d already has minidle of %d.\n", span + 1, conf.pri.minidle);
                                                        destroy_zt_pvt(&tmp);
                                                        return NULL;
                                                }
@@ -7616,24 +7702,24 @@ static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int
                                                        destroy_zt_pvt(&tmp);
                                                        return NULL;
                                                }
-                                               pris[span].nodetype = pritype;
+                                               pris[span].nodetype = conf.pri.nodetype;
                                                pris[span].switchtype = myswitchtype;
-                                               pris[span].nsf = nsf;
-                                               pris[span].dialplan = dialplan;
-                                               pris[span].localdialplan = localdialplan;
+                                               pris[span].nsf = conf.pri.nsf;
+                                               pris[span].dialplan = conf.pri.dialplan;
+                                               pris[span].localdialplan = conf.pri.localdialplan;
                                                pris[span].pvts[pris[span].numchans++] = tmp;
-                                               pris[span].minunused = minunused;
-                                               pris[span].minidle = minidle;
-                                               pris[span].overlapdial = overlapdial;
-                                               pris[span].facilityenable = facilityenable;
-                                               ast_copy_string(pris[span].idledial, idledial, sizeof(pris[span].idledial));
-                                               ast_copy_string(pris[span].idleext, idleext, sizeof(pris[span].idleext));
-                                               ast_copy_string(pris[span].internationalprefix, internationalprefix, sizeof(pris[span].internationalprefix));
-                                               ast_copy_string(pris[span].nationalprefix, nationalprefix, sizeof(pris[span].nationalprefix));
-                                               ast_copy_string(pris[span].localprefix, localprefix, sizeof(pris[span].localprefix));
-                                               ast_copy_string(pris[span].privateprefix, privateprefix, sizeof(pris[span].privateprefix));
-                                               ast_copy_string(pris[span].unknownprefix, unknownprefix, sizeof(pris[span].unknownprefix));
-                                               pris[span].resetinterval = resetinterval;
+                                               pris[span].minunused = conf.pri.minunused;
+                                               pris[span].minidle = conf.pri.minidle;
+                                               pris[span].overlapdial = conf.pri.overlapdial;
+                                               pris[span].facilityenable = conf.pri.facilityenable;
+                                               ast_copy_string(pris[span].idledial, conf.pri.idledial, sizeof(pris[span].idledial));
+                                               ast_copy_string(pris[span].idleext, conf.pri.idleext, sizeof(pris[span].idleext));
+                                               ast_copy_string(pris[span].internationalprefix, conf.pri.internationalprefix, sizeof(pris[span].internationalprefix));
+                                               ast_copy_string(pris[span].nationalprefix, conf.pri.nationalprefix, sizeof(pris[span].nationalprefix));
+                                               ast_copy_string(pris[span].localprefix, conf.pri.localprefix, sizeof(pris[span].localprefix));
+                                               ast_copy_string(pris[span].privateprefix, conf.pri.privateprefix, sizeof(pris[span].privateprefix));
+                                               ast_copy_string(pris[span].unknownprefix, conf.pri.unknownprefix, sizeof(pris[span].unknownprefix));
+                                               pris[span].resetinterval = conf.pri.resetinterval;
                                                
                                                tmp->pri = &pris[span];
                                                tmp->prioffset = offset;
@@ -7649,23 +7735,23 @@ static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int
                        }
 #endif
                } else {
-                       signalling = tmp->sig;
-                       radio = tmp->radio;
+                       conf.chan.sig = tmp->sig;
+                       conf.chan.radio = tmp->radio;
                        memset(&p, 0, sizeof(p));
                        if (tmp->subs[SUB_REAL].zfd > -1)
                                res = ioctl(tmp->subs[SUB_REAL].zfd, ZT_GET_PARAMS, &p);
                }
                /* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
-               if ((signalling == SIG_FXSKS) || (signalling == SIG_FXSLS) ||
-                   (signalling == SIG_EM) || (signalling == SIG_EM_E1) ||  (signalling == SIG_EMWINK) ||
-                       (signalling == SIG_FEATD) || (signalling == SIG_FEATDMF) || (signalling == SIG_FEATDMF_TA) ||
-                         (signalling == SIG_FEATB) || (signalling == SIG_E911) ||
-                   (signalling == SIG_SF) || (signalling == SIG_SFWINK) || (signalling == SIG_FGC_CAMA) || (signalling == SIG_FGC_CAMAMF) ||
-                       (signalling == SIG_SF_FEATD) || (signalling == SIG_SF_FEATDMF) ||
-                         (signalling == SIG_SF_FEATB)) {
+               if ((conf.chan.sig == SIG_FXSKS) || (conf.chan.sig == SIG_FXSLS) ||
+                   (conf.chan.sig == SIG_EM) || (conf.chan.sig == SIG_EM_E1) ||  (conf.chan.sig == SIG_EMWINK) ||
+                       (conf.chan.sig == SIG_FEATD) || (conf.chan.sig == SIG_FEATDMF) || (conf.chan.sig == SIG_FEATDMF_TA) ||
+                         (conf.chan.sig == SIG_FEATB) || (conf.chan.sig == SIG_E911) ||
+                   (conf.chan.sig == SIG_SF) || (conf.chan.sig == SIG_SFWINK) || (conf.chan.sig == SIG_FGC_CAMA) || (conf.chan.sig == SIG_FGC_CAMAMF) ||
+                       (conf.chan.sig == SIG_SF_FEATD) || (conf.chan.sig == SIG_SF_FEATDMF) ||
+                         (conf.chan.sig == SIG_SF_FEATB)) {
                        p.starttime = 250;
                }
-               if (radio) {
+               if (conf.chan.radio) {
                        /* XXX Waiting to hear back from Jim if these should be adjustable XXX */
                        p.channo = channel;
                        p.rxwinktime = 1;
@@ -7673,25 +7759,25 @@ static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int
                        p.starttime = 1;
                        p.debouncetime = 5;
                }
-               if (!radio) {
+               if (!conf.chan.radio) {
                        p.channo = channel;
                        /* Override timing settings based on config file */
-                       if (cur_prewink >= 0)
-                               p.prewinktime = cur_prewink;
-                       if (cur_preflash >= 0)
-                               p.preflashtime = cur_preflash;
-                       if (cur_wink >= 0)
-                               p.winktime = cur_wink;
-                       if (cur_flash >= 0)
-                               p.flashtime = cur_flash;
-                       if (cur_start >= 0)
-                               p.starttime = cur_start;
-                       if (cur_rxwink >= 0)
-                               p.rxwinktime = cur_rxwink;
-                       if (cur_rxflash >= 0)
-                               p.rxflashtime = cur_rxflash;
-                       if (cur_debounce >= 0)
-                               p.debouncetime = cur_debounce;
+                       if (conf.timing.prewinktime >= 0)
+                               p.prewinktime = conf.timing.prewinktime;
+                       if (conf.timing.preflashtime >= 0)
+                               p.preflashtime = conf.timing.preflashtime;
+                       if (conf.timing.winktime >= 0)
+                               p.winktime = conf.timing.winktime;
+                       if (conf.timing.flashtime >= 0)
+                               p.flashtime = conf.timing.flashtime;
+                       if (conf.timing.starttime >= 0)
+                               p.starttime = conf.timing.starttime;
+                       if (conf.timing.rxwinktime >= 0)
+                               p.rxwinktime = conf.timing.rxwinktime;
+                       if (conf.timing.rxflashtime >= 0)
+                               p.rxflashtime = conf.timing.rxflashtime;
+                       if (conf.timing.debouncetime >= 0)
+                               p.debouncetime = conf.timing.debouncetime;
                }
                
                /* dont set parms on a pseudo-channel (or CRV) */
@@ -7720,50 +7806,50 @@ static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int
                                ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d\n", channel);
                }
 #endif
-               tmp->immediate = immediate;
-               tmp->transfertobusy = transfertobusy;
-               tmp->sig = signalling;
-               tmp->outsigmod = outsignalling;
-               tmp->radio = radio;
+               tmp->immediate = conf.chan.immediate;
+               tmp->transfertobusy = conf.chan.transfertobusy;
+               tmp->sig = conf.chan.sig;
+               tmp->outsigmod = conf.chan.outsigmod;
+               tmp->radio = conf.chan.radio;
                tmp->ringt_base = ringt_base;
                tmp->firstradio = 0;
-               if ((signalling == SIG_FXOKS) || (signalling == SIG_FXOLS) || (signalling == SIG_FXOGS))
-                       tmp->permcallwaiting = callwaiting;
+               if ((conf.chan.sig == SIG_FXOKS) || (conf.chan.sig == SIG_FXOLS) || (conf.chan.sig == SIG_FXOGS))
+                       tmp->permcallwaiting = conf.chan.callwaiting;
                else
                        tmp->permcallwaiting = 0;
                /* Flag to destroy the channel must be cleared on new mkif.  Part of changes for reload to work */
                tmp->destroy = 0;
                tmp->drings = drings;
                tmp->usedistinctiveringdetection = usedistinctiveringdetection;
-               tmp->callwaitingcallerid = callwaitingcallerid;
-               tmp->threewaycalling = threewaycalling;
-               tmp->adsi = adsi;
-               tmp->use_smdi = use_smdi;
-               tmp->permhidecallerid = hidecallerid;
-               tmp->callreturn = callreturn;
-               tmp->echocancel = echocancel;
-               tmp->echotraining = echotraining;
-               tmp->pulse = pulse;
-               tmp->echocanbridged = echocanbridged;
-               tmp->busydetect = busydetect;
-               tmp->busycount = busycount;
-               tmp->busy_tonelength = busy_tonelength;
-               tmp->busy_quietlength = busy_quietlength;
-               tmp->callprogress = callprogress;
-               tmp->cancallforward = cancallforward;
-               tmp->dtmfrelax = relaxdtmf;
+               tmp->callwaitingcallerid = conf.chan.callwaitingcallerid;
+               tmp->threewaycalling = conf.chan.threewaycalling;
+               tmp->adsi = conf.chan.adsi;
+               tmp->use_smdi = conf.chan.use_smdi;
+               tmp->permhidecallerid = conf.chan.hidecallerid;
+               tmp->callreturn = conf.chan.callreturn;
+               tmp->echocancel = conf.chan.echocancel;
+               tmp->echotraining = conf.chan.echotraining;
+               tmp->pulse = conf.chan.pulse;
+               tmp->echocanbridged = conf.chan.echocanbridged;
+               tmp->busydetect = conf.chan.busydetect;
+               tmp->busycount = conf.chan.busycount;
+               tmp->busy_tonelength = conf.chan.busy_tonelength;
+               tmp->busy_quietlength = conf.chan.busy_quietlength;
+               tmp->callprogress = conf.chan.callprogress;
+               tmp->cancallforward = conf.chan.cancallforward;
+               tmp->dtmfrelax = conf.chan.dtmfrelax;
                tmp->callwaiting = tmp->permcallwaiting;
                tmp->hidecallerid = tmp->permhidecallerid;
                tmp->channel = channel;
-               tmp->stripmsd = stripmsd;
-               tmp->use_callerid = use_callerid;
-               tmp->cid_signalling = cid_signalling;
-               tmp->cid_start = cid_start;
-               tmp->zaptrcallerid = zaptrcallerid;
-               tmp->restrictcid = restrictcid;
-               tmp->use_callingpres = use_callingpres;
-               tmp->priindication_oob = priindication_oob;
-               tmp->priexclusive = cur_priexclusive;
+               tmp->stripmsd = conf.chan.stripmsd;
+               tmp->use_callerid = conf.chan.use_callerid;
+               tmp->cid_signalling = conf.chan.cid_signalling;
+               tmp->cid_start = conf.chan.cid_start;
+               tmp->zaptrcallerid = conf.chan.zaptrcallerid;
+               tmp->restrictcid = conf.chan.restrictcid;
+               tmp->use_callingpres = conf.chan.use_callingpres;
+               tmp->priindication_oob = conf.chan.priindication_oob;
+               tmp->priexclusive = conf.chan.priexclusive;
                if (tmp->usedistinctiveringdetection) {
                        if (!tmp->use_callerid) {
                                ast_log(LOG_NOTICE, "Distinctive Ring detect requires 'usecallerid' be on\n");
@@ -7778,37 +7864,44 @@ static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int
                        }
                }
                if (tmp->use_smdi) {
-                       tmp->smdi_iface = ast_smdi_interface_find(smdi_port);
+                       tmp->smdi_iface = ast_smdi_interface_find(conf.smdi_port);
                        if (!(tmp->smdi_iface)) {
                                ast_log(LOG_ERROR, "Invalid SMDI port specfied, disabling SMDI support\n");
                                tmp->use_smdi = 0;
                        }
                }
 
-               ast_copy_string(tmp->accountcode, accountcode, sizeof(tmp->accountcode));
-               tmp->amaflags = amaflags;
+               ast_copy_string(tmp->accountcode, conf.chan.accountcode, sizeof(tmp->accountcode));
+               tmp->amaflags = conf.chan.amaflags;
                if (!here) {
                        tmp->confno = -1;
                        tmp->propconfno = -1;
                }
-               tmp->canpark = canpark;
-               tmp->transfer = transfer;
-               ast_copy_string(tmp->defcontext,context,sizeof(tmp->defcontext));
-               ast_copy_string(tmp->language, language, sizeof(tmp->language));
-               ast_copy_string(tmp->mohinterpret, mohinterpret, sizeof(tmp->mohinterpret));
-               ast_copy_string(tmp->mohsuggest, mohsuggest, sizeof(tmp->mohsuggest));
-               ast_copy_string(tmp->context, context, sizeof(tmp->context));
-               ast_copy_string(tmp->cid_num, cid_num, sizeof(tmp->cid_num));
+               tmp->canpark = conf.chan.canpark;
+               tmp->transfer = conf.chan.transfer;
+               ast_copy_string(tmp->defcontext,conf.chan.context,sizeof(tmp->defcontext));
+               ast_copy_string(tmp->language, conf.chan.language, sizeof(tmp->language));
+               ast_copy_string(tmp->mohinterpret, conf.chan.mohinterpret, sizeof(tmp->mohinterpret));
+               ast_copy_string(tmp->mohsuggest, conf.chan.mohsuggest, sizeof(tmp->mohsuggest));
+               ast_copy_string(tmp->context, conf.chan.context, sizeof(tmp->context));
+               ast_copy_string(tmp->cid_num, conf.chan.cid_num, sizeof(tmp->cid_num));
                tmp->cid_ton = 0;
-               ast_copy_string(tmp->cid_name, cid_name, sizeof(tmp->cid_name));
-               ast_copy_string(tmp->mailbox, mailbox, sizeof(tmp->mailbox));
+               ast_copy_string(tmp->cid_name, conf.chan.cid_name, sizeof(tmp->cid_name));
+               ast_copy_string(tmp->mailbox, conf.chan.mailbox, sizeof(tmp->mailbox));
+               if (!ast_strlen_zero(tmp->mailbox)) {
+                       tmp->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, NULL,
+                               AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, tmp->mailbox,
+                               AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
+                               AST_EVENT_IE_END);
+               }
                tmp->msgstate = -1;
-               tmp->group = cur_group;
-               tmp->callgroup=cur_callergroup;
-               tmp->pickupgroup=cur_pickupgroup;
-               tmp->rxgain = rxgain;
-               tmp->txgain = txgain;
-               tmp->tonezone = tonezone;
+               tmp->group = conf.chan.group;
+               tmp->callgroup = conf.chan.callgroup;
+               tmp->pickupgroup= conf.chan.pickupgroup;
+               tmp->cid_rxgain = conf.chan.cid_rxgain;
+               tmp->rxgain = conf.chan.rxgain;
+               tmp->txgain = conf.chan.txgain;
+               tmp->tonezone = conf.chan.tonezone;
                tmp->onhooktime = time(NULL);
                if (tmp->subs[SUB_REAL].zfd > -1) {
                        set_actual_gain(tmp->subs[SUB_REAL].zfd, 0, tmp->rxgain, tmp->txgain, tmp->law);
@@ -7816,7 +7909,7 @@ static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int
                                ast_dsp_digitmode(tmp->dsp, DSP_DIGITMODE_DTMF | tmp->dtmfrelax);
                        update_conf(tmp);
                        if (!here) {
-                               if ((signalling != SIG_PRI) && (signalling != SIG_SS7))
+                               if ((conf.chan.sig != SIG_PRI) && (conf.chan.sig != SIG_SS7))
                                        /* Hang it up to be sure it's good */
                                        zt_set_hook(tmp->subs[SUB_REAL].zfd, ZT_ONHOOK);
                        }
@@ -7837,13 +7930,13 @@ static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int
                        if (si.alarms) tmp->inalarm = 1;
                }
 
-               tmp->polarityonanswerdelay = polarityonanswerdelay;
-               tmp->answeronpolarityswitch = answeronpolarityswitch;
-               tmp->hanguponpolarityswitch = hanguponpolarityswitch;
-               tmp->sendcalleridafter = sendcalleridafter;
+               tmp->polarityonanswerdelay = conf.chan.polarityonanswerdelay;
+               tmp->answeronpolarityswitch = conf.chan.answeronpolarityswitch;
+               tmp->hanguponpolarityswitch = conf.chan.hanguponpolarityswitch;
+               tmp->sendcalleridafter = conf.chan.sendcalleridafter;
                if (!here) {
                        tmp->locallyblocked = tmp->remotelyblocked = 0;
-                       if ((signalling == SIG_PRI) || (signalling == SIG_SS7))
+                       if ((conf.chan.sig == SIG_PRI) || (conf.chan.sig == SIG_SS7))
                                tmp->inservice = 0;
                        else /* We default to in service on protocols that don't have a reset */
                                tmp->inservice = 1;
@@ -7925,7 +8018,7 @@ static inline int available(struct zt_pvt *p, int channelmatch, int groupmatch,
        if (p->guardtime && (time(NULL) < p->guardtime)) 
                return 0;
 
-       if (p->locallyblocked || p->remotelyblocked || !p->inservice)
+       if (p->locallyblocked || p->remotelyblocked)
                return 0;
                
        /* If no owner definitely available */
@@ -7977,8 +8070,7 @@ static inline int available(struct zt_pvt *p, int channelmatch, int groupmatch,
                                        return 1;
 #endif
                        } else if (par.rxisoffhook) {
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Channel %d off hook, can't use\n", p->channel);
+                               ast_debug(1, "Channel %d off hook, can't use\n", p->channel);
                                /* Not available when the other end is off hook */
                                return 0;
                        }
@@ -8062,9 +8154,8 @@ static int pri_find_empty_chan(struct zt_pri *pri, int backwards)
                if (!backwards && (x >= pri->numchans))
                        break;
                if (pri->pvts[x] && !pri->pvts[x]->inalarm && !pri->pvts[x]->owner) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Found empty available channel %d/%d\n", 
-                                       pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
+                       ast_debug(1, "Found empty available channel %d/%d\n", 
+                               pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
                        return x;
                }
                if (backwards)
@@ -8193,10 +8284,9 @@ static struct ast_channel *zt_request(const char *type, int format, void *data,
 #endif
 
                if (p && available(p, channelmatch, groupmatch, &busy, &channelmatched, &groupmatched)) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Using channel %d\n", p->channel);
-                               if (p->inalarm) 
-                                       goto next;
+                       ast_debug(1, "Using channel %d\n", p->channel);
+                       if (p->inalarm) 
+                               goto next;
 
                        callwait = (p->owner != NULL);
 #ifdef HAVE_PRI
@@ -8216,10 +8306,9 @@ static struct ast_channel *zt_request(const char *type, int format, void *data,
                                                ast_log(LOG_NOTICE, "Failed to allocate place holder pseudo channel!\n");
                                                p = NULL;
                                                break;
-                                       } else {
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "Allocated placeholder pseudo channel\n");
-                                       }
+                                       } else
+                                               ast_debug(1, "Allocated placeholder pseudo channel\n");
+
                                        p->pri = pri;
                                }
                        }
@@ -8339,25 +8428,30 @@ static void ss7_inservice(struct zt_ss7 *linkset, int startcic, int endcic)
        }
 }
 
-static int ss7_reset_linkset(struct zt_ss7 *linkset)
+static void ss7_reset_linkset(struct zt_ss7 *linkset)
 {
-       int i, startcic = -1, endcic;
+       int i, startcic = -1, endcic, dpc;
 
        if (linkset->numchans <= 0)
-               return 0;
+               return;
 
        startcic = linkset->pvts[0]->cic;
+       /* DB: CIC's DPC fix */
+       dpc = linkset->pvts[0]->dpc;
 
        for (i = 0; i < linkset->numchans; i++) {
-               if (linkset->pvts[i+1] && (linkset->pvts[i+1]->cic - linkset->pvts[i]->cic) == 1) {
+               if (linkset->pvts[i+1] && linkset->pvts[i+1]->dpc == dpc && ((linkset->pvts[i+1]->cic - linkset->pvts[i]->cic) == 1) && (linkset->pvts[i]->cic - startcic < 31)) {
                        continue;
                } else {
                        endcic = linkset->pvts[i]->cic;
                        ast_verbose("Resetting CICs %d to %d\n", startcic, endcic);
-                       isup_grs(linkset->ss7, startcic, endcic);
+                       isup_grs(linkset->ss7, startcic, endcic, dpc);
 
-                       if (linkset->pvts[i+1])
+                       /* DB: CIC's DPC fix */
+                       if (linkset->pvts[i+1]) {
                                startcic = linkset->pvts[i+1]->cic;
+                               dpc = linkset->pvts[i+1]->dpc;
+                       }
                }
        }
 }
@@ -8401,6 +8495,31 @@ static void ss7_start_call(struct zt_pvt *p, struct zt_ss7 *linkset)
                ast_log(LOG_WARNING, "Unable to start PBX on CIC %d\n", p->cic);
 }
 
+static void ss7_apply_plan_to_number(char *buf, size_t size, const struct zt_ss7 *ss7, const char *number, const unsigned nai)
+{
+       switch (nai) {
+       case SS7_NAI_INTERNATIONAL:
+               snprintf(buf, size, "%s%s", ss7->internationalprefix, number);
+               break;
+       case SS7_NAI_NATIONAL:
+               snprintf(buf, size, "%s%s", ss7->nationalprefix, number);
+               break;
+       case SS7_NAI_SUBSCRIBER:
+               snprintf(buf, size, "%s%s", ss7->subscriberprefix, number);
+               break;
+       case SS7_NAI_UNKNOWN:
+               snprintf(buf, size, "%s%s", ss7->unknownprefix, number);
+               break;
+       default:
+               snprintf(buf, size, "%s", number);
+               break;
+       }
+}
+static int ss7_pres_scr2cid_pres(char presentation_ind, char screening_ind)
+{
+    return ((presentation_ind & 0x3) << 5) | (screening_ind & 0x3);
+}
+
 static void *ss7_linkset(void *data)
 {
        int res, i;
@@ -8410,20 +8529,17 @@ static void *ss7_linkset(void *data)
        ss7_event *e = NULL;
        struct zt_pvt *p;
        int chanpos;
-       pthread_attr_t attr;
        struct pollfd pollers[NUM_DCHANS];
        int cic;
+       unsigned int dpc;
        int nextms = 0;
 
-       pthread_attr_init(&attr);
-       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
        ss7_start(ss7);
 
        while(1) {
                ast_mutex_lock(&linkset->lock);
                if ((next = ss7_schedule_next(ss7))) {
-                       gettimeofday(&tv, NULL);
+                       tv = ast_tvnow();
                        tv.tv_sec = next->tv_sec - tv.tv_sec;
                        tv.tv_usec = next->tv_usec - tv.tv_usec;
                        if (tv.tv_usec < 0) {
@@ -8464,13 +8580,13 @@ static void *ss7_linkset(void *data)
                                }
                                switch (x) {
                                case ZT_EVENT_OVERRUN:
-                                       ast_log(LOG_DEBUG, "Overrun detected!\n");
+                                       ast_debug(1, "Overrun detected!\n");
                                        break;
                                case ZT_EVENT_BADFCS:
-                                       ast_log(LOG_DEBUG, "Bad FCS\n");
+                                       ast_debug(1, "Bad FCS\n");
                                        break;
                                case ZT_EVENT_ABORT:
-                                       ast_log(LOG_DEBUG, "HDLC Abort\n");
+                                       ast_debug(1, "HDLC Abort\n");
                                        break;
                                case ZT_EVENT_ALARM:
                                        ast_log(LOG_ERROR, "Alarm on link!\n");
@@ -8508,14 +8624,23 @@ static void *ss7_linkset(void *data)
                while ((e = ss7_check_event(ss7))) {
                        switch (e->e) {
                        case SS7_EVENT_UP:
-                               ast_verbose("--- SS7 Up ---\n");
-                               ss7_reset_linkset(linkset);
+                               if (linkset->state != LINKSET_STATE_UP) {
+                                       ast_verbose("--- SS7 Up ---\n");
+                                       ss7_reset_linkset(linkset);
+                               }
+                               linkset->state = LINKSET_STATE_UP;
                                break;
                        case SS7_EVENT_DOWN:
                                ast_verbose("--- SS7 Down ---\n");
+                               linkset->state = LINKSET_STATE_DOWN;
+                               for (i = 0; i < linkset->numchans; i++) {
+                                       struct zt_pvt *p = linkset->pvts[i];
+                                       if (p)
+                                               p->inalarm = 1;
+                               }
                                break;
                        case MTP2_LINK_UP:
-                               ast_log(LOG_DEBUG, "MTP2 link up\n");
+                               ast_debug(1, "MTP2 link up\n");
                                break;
                        case ISUP_EVENT_CPG:
                                chanpos = ss7_find_cic(linkset, e->cpg.cic);
@@ -8534,13 +8659,13 @@ static void *ss7_linkset(void *data)
                                case CPG_EVENT_INBANDINFO:
                                        {
                                                struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, };
-                                               ast_log(LOG_DEBUG, "Queuing frame PROGRESS on CIC %d\n", p->cic);
-                                               zap_queue_frame(p, &f, ss7);
+                                               ast_debug(1, "Queuing frame PROGRESS on CIC %d\n", p->cic);
+                                               zap_queue_frame(p, &f, linkset);
                                                p->progress = 1;
                                        }
                                        break;
                                default:
-                                       ast_log(LOG_DEBUG, "Do not handle CPG with event type 0x%x\n", e->cpg.event);
+                                       ast_debug(1, "Do not handle CPG with event type 0x%x\n", e->cpg.event);
                                }
 
                                ast_mutex_unlock(&p->lock);
@@ -8556,12 +8681,20 @@ static void *ss7_linkset(void *data)
                                ast_mutex_lock(&p->lock);
                                p->inservice = 1;
                                p->remotelyblocked = 0;
+                               dpc = p->dpc;
+                               isup_set_call_dpc(e->rsc.call, dpc);
                                ast_mutex_unlock(&p->lock);
                                isup_rlc(ss7, e->rsc.call);
                                break;
                        case ISUP_EVENT_GRS:
-                               ast_log(LOG_DEBUG, "Got Reset for CICs %d to %d: Acknowledging\n", e->grs.startcic, e->grs.endcic);
-                               isup_gra(ss7, e->grs.startcic, e->grs.endcic);
+                               ast_debug(1, "Got Reset for CICs %d to %d: Acknowledging\n", e->grs.startcic, e->grs.endcic);
+                               chanpos = ss7_find_cic(linkset, e->grs.startcic);
+                               if (chanpos < 0) {
+                                       ast_log(LOG_WARNING, "GRS on unconfigured CIC %d\n", e->grs.startcic);
+                                       break;
+                               }
+                               p = linkset->pvts[chanpos];
+                               isup_gra(ss7, e->grs.startcic, e->grs.endcic, p->dpc);
                                ss7_block_cics(linkset, e->grs.startcic, e->grs.endcic, NULL, 0);
                                break;
                        case ISUP_EVENT_GRA:
@@ -8570,7 +8703,7 @@ static void *ss7_linkset(void *data)
                                ss7_block_cics(linkset, e->gra.startcic, e->gra.endcic, e->gra.status, 1);
                                break;
                        case ISUP_EVENT_IAM:
-                               ast_log(LOG_DEBUG, "Got IAM for CIC %d and number %s\n", e->iam.cic, e->iam.called_party_num);
+                               ast_debug(1, "Got IAM for CIC %d and called number %s, calling number %s\n", e->iam.cic, e->iam.called_party_num, e->iam.calling_party_num);
                                chanpos = ss7_find_cic(linkset, e->iam.cic);
                                if (chanpos < 0) {
                                        ast_log(LOG_WARNING, "IAM on unconfigured CIC %d\n", e->iam.cic);
@@ -8591,10 +8724,15 @@ static void *ss7_linkset(void *data)
                                        }
                                }
 
+                               dpc = p->dpc;
                                p->ss7call = e->iam.call;
+                               isup_set_call_dpc(p->ss7call, dpc);
 
-                               if (p->use_callerid)
-                                       ast_copy_string(p->cid_num, e->iam.calling_party_num, sizeof(p->cid_num));
+                               if ( (p->use_callerid) && (!ast_strlen_zero(e->iam.calling_party_num)) )
+                               {
+                                       ss7_apply_plan_to_number(p->cid_num, sizeof(p->cid_num), linkset, e->iam.calling_party_num, e->iam.calling_nai);
+                                       p->callingpres = ss7_pres_scr2cid_pres(e->iam.presentation_ind, e->iam.screening_ind);
+                               }
                                else
                                        p->cid_num[0] = 0;
 
@@ -8603,7 +8741,7 @@ static void *ss7_linkset(void *data)
                                        p->exten[1] = '\0';
                                } else if (!ast_strlen_zero(e->iam.called_party_num)) {
                                        char *st;
-                                       ast_copy_string(p->exten, e->iam.called_party_num, sizeof(p->exten));
+                                       ss7_apply_plan_to_number(p->exten, sizeof(p->exten), linkset, e->iam.called_party_num, e->iam.called_nai);
                                        st = strchr(p->exten, '#');
                                        if (st)
                                                *st = '\0';
@@ -8616,8 +8754,8 @@ static void *ss7_linkset(void *data)
                                p->cid_ton = 0;
                                /* Set DNID */
                                if (!ast_strlen_zero(e->iam.called_party_num))
-                                       ast_copy_string(p->dnid, e->iam.called_party_num, sizeof(p->exten));
-
+                                       ss7_apply_plan_to_number(p->dnid, sizeof(p->dnid), linkset, e->iam.called_party_num, e->iam.called_nai);
+                               
                                if (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
 
                                        if (e->iam.cot_check_required) {
@@ -8625,7 +8763,7 @@ static void *ss7_linkset(void *data)
                                        } else
                                                ss7_start_call(p, linkset);
                                } else {
-                                       ast_log(LOG_DEBUG, "Call on CIC for unconfigured extension %s\n", p->exten);
+                                       ast_debug(1, "Call on CIC for unconfigured extension %s\n", p->exten);
                                        isup_rel(ss7, e->iam.call, -1);
                                }
                                ast_mutex_unlock(&p->lock);
@@ -8651,9 +8789,10 @@ static void *ss7_linkset(void *data)
                                }
                                p = linkset->pvts[chanpos];
                                ast_mutex_lock(&p->lock);
-                               if (p->owner)
-                                       ast_queue_hangup(p->owner);
-                               else
+                               if (p->owner) {
+                                       p->owner->hangupcause = e->rel.cause;
+                                       p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+                               } else
                                        ast_log(LOG_WARNING, "REL on channel (CIC %d) without owner!\n", p->cic);
 
                                isup_rlc(ss7, e->rel.call);
@@ -8672,7 +8811,7 @@ static void *ss7_linkset(void *data)
 
                                        p = linkset->pvts[chanpos];
 
-                                       ast_log(LOG_DEBUG, "Queueing frame from SS7_EVENT_ACM on CIC %d\n", p->cic);
+                                       ast_debug(1, "Queueing frame from SS7_EVENT_ACM on CIC %d\n", p->cic);
 
                                        ast_mutex_lock(&p->lock);
                                        zap_queue_frame(p, &f, linkset);
@@ -8682,12 +8821,24 @@ static void *ss7_linkset(void *data)
                                }
                                break;
                        case ISUP_EVENT_CGB:
+                               chanpos = ss7_find_cic(linkset, e->cgb.startcic);
+                               if (chanpos < 0) {
+                                       ast_log(LOG_WARNING, "CGB on unconfigured CIC %d\n", e->cgb.startcic);
+                                       break;
+                               }
+                               p = linkset->pvts[chanpos];
                                ss7_block_cics(linkset, e->cgb.startcic, e->cgb.endcic, e->cgb.status, 1);
-                               isup_cgba(linkset->ss7, e->cgb.startcic, e->cgb.endcic, e->cgb.status);
+                               isup_cgba(linkset->ss7, e->cgb.startcic, e->cgb.endcic, p->dpc, e->cgb.status, e->cgb.type);
                                break;
                        case ISUP_EVENT_CGU:
-                               ss7_block_cics(linkset, e->cgu.startcic, e->cgu.endcic, e->cgb.status, 0);
-                               isup_cgua(linkset->ss7, e->cgu.startcic, e->cgu.endcic, e->cgb.status);
+                               chanpos = ss7_find_cic(linkset, e->cgu.startcic);
+                               if (chanpos < 0) {
+                                       ast_log(LOG_WARNING, "CGU on unconfigured CIC %d\n", e->cgu.startcic);
+                                       break;
+                               }
+                               p = linkset->pvts[chanpos];
+                               ss7_block_cics(linkset, e->cgu.startcic, e->cgu.endcic, e->cgu.status, 0);
+                               isup_cgua(linkset->ss7, e->cgu.startcic, e->cgu.endcic, p->dpc, e->cgu.status, e->cgu.type);
                                break;
                        case ISUP_EVENT_BLO:
                                chanpos = ss7_find_cic(linkset, e->blo.cic);
@@ -8696,9 +8847,11 @@ static void *ss7_linkset(void *data)
                                        break;
                                }
                                p = linkset->pvts[chanpos];
-                               ast_log(LOG_DEBUG, "Blocking CIC %d\n", e->blo.cic);
+                               ast_debug(1, "Blocking CIC %d\n", e->blo.cic);
+                               ast_mutex_lock(&p->lock);
                                p->remotelyblocked = 1;
-                               isup_bla(linkset->ss7, e->blo.cic);
+                               ast_mutex_unlock(&p->lock);
+                               isup_bla(linkset->ss7, e->blo.cic, p->dpc);
                                break;
                        case ISUP_EVENT_UBL:
                                chanpos = ss7_find_cic(linkset, e->ubl.cic);
@@ -8707,9 +8860,11 @@ static void *ss7_linkset(void *data)
                                        break;
                                }
                                p = linkset->pvts[chanpos];
-                               ast_log(LOG_DEBUG, "Unblocking CIC %d\n", e->ubl.cic);
+                               ast_debug(1, "Unblocking CIC %d\n", e->ubl.cic);
+                               ast_mutex_lock(&p->lock);
                                p->remotelyblocked = 0;
-                               isup_uba(linkset->ss7, e->ubl.cic);
+                               ast_mutex_unlock(&p->lock);
+                               isup_uba(linkset->ss7, e->ubl.cic, p->dpc);
                                break;
                        case ISUP_EVENT_CON:
                        case ISUP_EVENT_ANM:
@@ -8744,7 +8899,7 @@ static void *ss7_linkset(void *data)
                                }
                                break;
                        default:
-                               ast_log(LOG_DEBUG, "Unknown event %s\n", ss7_event2str(e->e));
+                               ast_debug(1, "Unknown event %s\n", ss7_event2str(e->e));
                                break;
                        }
                }
@@ -8756,6 +8911,7 @@ static void *ss7_linkset(void *data)
 
 static void zt_ss7_message(struct ss7 *ss7, char *s)
 {
+#if 0
        int i;
 
        for (i = 0; i < NUM_SPANS; i++)
@@ -8763,18 +8919,25 @@ static void zt_ss7_message(struct ss7 *ss7, char *s)
                        break;
 
        ast_verbose("[%d] %s", i+1, s);
+#else
+       ast_verbose("%s", s);
+#endif
 }
 
 static void zt_ss7_error(struct ss7 *ss7, char *s)
 {
+#if 0
        int i;
 
        for (i = 0; i < NUM_SPANS; i++)
                if (linksets[i].ss7 == ss7)
                        break;
 
-       ast_log(LOG_ERROR, "[%d] %s", i+1, s);
+#else
+       ast_log(LOG_ERROR, "%s", s);
+#endif
 }
+
 #endif /* HAVE_SS7 */
 
 #ifdef HAVE_PRI
@@ -8882,10 +9045,9 @@ static int pri_fixup_principle(struct zt_pri *pri, int principle, q931_call *c)
                                zt_close(crv->subs[SUB_REAL].zfd);
                                pri->pvts[principle]->call = crv->call;
                                pri_assign_bearer(crv, pri, pri->pvts[principle]);
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Assigning bearer %d/%d to CRV %d:%d\n",
-                                                                               pri->pvts[principle]->logicalspan, pri->pvts[principle]->prioffset,
-                                                                               pri->trunkgroup, crv->channel);
+                               ast_debug(1, "Assigning bearer %d/%d to CRV %d:%d\n",
+                                       pri->pvts[principle]->logicalspan, pri->pvts[principle]->prioffset,
+                                       pri->trunkgroup, crv->channel);
                                wakeup_sub(crv, SUB_REAL, pri);
                        }
                        return principle;
@@ -9092,6 +9254,10 @@ static char * redirectingreason2str(int redirectingreason)
 
 static void apply_plan_to_number(char *buf, size_t size, const struct zt_pri *pri, const char *number, const int plan)
 {
+       if (pri->dialplan == -2) { /* autodetect the TON but leave the number untouched */
+               snprintf(buf, size, "%s", number);
+               return;
+       }
        switch (plan) {
        case PRI_INTERNATIONAL_ISDN:            /* Q.931 dialplan == 0x11 international dialplan => prepend international prefix digits */
                snprintf(buf, size, "%s%s", pri->internationalprefix, number);
@@ -9136,7 +9302,7 @@ static void *pri_dchannel(void *vpri)
        int nextidle = -1;
        struct ast_channel *c;
        struct timeval tv, lowest, *next;
-       struct timeval lastidle = { 0, 0 };
+       struct timeval lastidle = ast_tvnow();
        int doidling=0;
        char *cc;
        char idlen[80];
@@ -9148,16 +9314,11 @@ static void *pri_dchannel(void *vpri)
        int cause=0;
        struct zt_pvt *crv;
        pthread_t threadid;
-       pthread_attr_t attr;
        char ani2str[6];
        char plancallingnum[256];
        char plancallingani[256];
        char calledtonstr[10];
        
-       pthread_attr_init(&attr);
-       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
-       gettimeofday(&lastidle, NULL);
        if (!ast_strlen_zero(pri->idledial) && !ast_strlen_zero(pri->idleext)) {
                /* Need to do idle dialing, check to be sure though */
                cc = strchr(pri->idleext, '@');
@@ -9227,7 +9388,7 @@ static void *pri_dchannel(void *vpri)
                                                }
                                        } else
                                                ast_log(LOG_WARNING, "Unable to request channel 'Zap/%s' for idle call\n", idlen);
-                                       gettimeofday(&lastidle, NULL);
+                                       lastidle = ast_tvnow();
                                }
                        } else if ((haveidles < pri->minunused) &&
                                   (activeidles > pri->minidle)) {
@@ -9314,8 +9475,7 @@ static void *pri_dchannel(void *vpri)
                                                pri_restart(pri->dchans[which]);
                                        }
                                
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Got event %s (%d) on D-channel for span %d\n", event2str(x), x, pri->span);
+                                       ast_debug(1, "Got event %s (%d) on D-channel for span %d\n", event2str(x), x, pri->span);
                                } else if (fds[which].revents & POLLIN) {
                                        e = pri_check_event(pri->dchans[which]);
                                }
@@ -9330,6 +9490,11 @@ static void *pri_dchannel(void *vpri)
                                pri_dump_event(pri->dchans[which], e);
                        if (e->e != PRI_EVENT_DCHAN_DOWN)
                                pri->dchanavail[which] |= DCHAN_UP;
+
+                       if ((e->e != PRI_EVENT_DCHAN_UP) && (e->e != PRI_EVENT_DCHAN_DOWN) && (pri->pri != pri->dchans[which]))
+                               /* Must be an NFAS group that has the secondary dchan active */
+                               pri->pri = pri->dchans[which];
+
                        switch (e->e) {
                        case PRI_EVENT_DCHAN_UP:
                                if (option_verbose > 1) 
@@ -9433,7 +9598,7 @@ static void *pri_dchannel(void *vpri)
                                        if (chanpos > -1) {
                                                ast_mutex_lock(&pri->pvts[chanpos]->lock);
                                                /* queue DTMF frame if the PBX for this call was already started (we're forwarding KEYPAD_DIGITs further on */
-                                               if (pri->overlapdial && pri->pvts[chanpos]->call==e->digit.call && pri->pvts[chanpos]->owner) {
+                                               if ((pri->overlapdial & ZAP_OVERLAPDIAL_INCOMING) && pri->pvts[chanpos]->call==e->digit.call && pri->pvts[chanpos]->owner) {
                                                        /* how to do that */
                                                        int digitlen = strlen(e->digit.digits);
                                                        char digit;
@@ -9461,7 +9626,7 @@ static void *pri_dchannel(void *vpri)
                                        if (chanpos > -1) {
                                                ast_mutex_lock(&pri->pvts[chanpos]->lock);
                                                /* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
-                                               if (pri->overlapdial && pri->pvts[chanpos]->call==e->ring.call && pri->pvts[chanpos]->owner) {
+                                               if ((pri->overlapdial & ZAP_OVERLAPDIAL_INCOMING) && pri->pvts[chanpos]->call==e->ring.call && pri->pvts[chanpos]->owner) {
                                                        /* how to do that */
                                                        int digitlen = strlen(e->ring.callednum);
                                                        char digit;
@@ -9496,12 +9661,9 @@ static void *pri_dchannel(void *vpri)
                                                                PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
                                                        break;
                                                } else {
-                                                       ast_log(LOG_WARNING, "Ring requested on channel %d/%d already in use on span %d.  Hanging up owner.\n", 
+                                                       /* This is where we handle initial glare */
+                                                       ast_debug(1, "Ring requested on channel %d/%d already in use or previously requested on span %d.  Attempting to renegotiate channel.\n", 
                                                        PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
-                                                       if (pri->pvts[chanpos]->realcall) 
-                                                               pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
-                                                       else
-                                                               pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
                                                        ast_mutex_unlock(&pri->pvts[chanpos]->lock);
                                                        chanpos = -1;
                                                }
@@ -9581,7 +9743,7 @@ static void *pri_dchannel(void *vpri)
                                                pri->pvts[chanpos]->exten[1] = '\0';
                                        }
                                        /* Make sure extension exists (or in overlap dial mode, can exist) */
-                                       if ((pri->overlapdial && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||
+                                       if (((pri->overlapdial & ZAP_OVERLAPDIAL_INCOMING) && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||
                                                ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
                                                /* Setup law */
                                                int law;
@@ -9601,7 +9763,7 @@ static void *pri_dchannel(void *vpri)
                                                res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
                                                if (res < 0)
                                                        ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pri->pvts[chanpos]->channel);
-                                               if (e->ring.complete || !pri->overlapdial) {
+                                               if (e->ring.complete || !(pri->overlapdial & ZAP_OVERLAPDIAL_INCOMING)) {
                                                        /* Just announce proceeding */
                                                        pri->pvts[chanpos]->proceeding = 1;
                                                        pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
@@ -9615,7 +9777,7 @@ static void *pri_dchannel(void *vpri)
                                                pri->pvts[chanpos]->callingpres = e->ring.callingpres;
                                        
                                                /* Start PBX */
-                                               if (pri->overlapdial && ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
+                                               if ((pri->overlapdial & ZAP_OVERLAPDIAL_INCOMING) && ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
                                                        /* Release the PRI lock while we create the channel */
                                                        ast_mutex_unlock(&pri->lock);
                                                        if (crv) {
@@ -9623,8 +9785,7 @@ static void *pri_dchannel(void *vpri)
                                                                pri_assign_bearer(crv, pri, pri->pvts[chanpos]);
                                                                c = zt_new(crv, AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
                                                                pri->pvts[chanpos]->owner = &inuse;
-                                                               if (option_debug)
-                                                                       ast_log(LOG_DEBUG, "Started up crv %d:%d on bearer channel %d\n", pri->trunkgroup, crv->channel, crv->bearer->channel);
+                                                               ast_debug(1, "Started up crv %d:%d on bearer channel %d\n", pri->trunkgroup, crv->channel, crv->bearer->channel);
                                                        } else {
                                                                c = zt_new(pri->pvts[chanpos], AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
                                                        }
@@ -9648,7 +9809,7 @@ static void *pri_dchannel(void *vpri)
                                                                pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
                                                        
                                                        ast_mutex_lock(&pri->lock);
-                                                       if (c && !ast_pthread_create(&threadid, &attr, ss_thread, c)) {
+                                                       if (c && !ast_pthread_create_detached(&threadid, NULL, ss_thread, c)) {
                                                                if (option_verbose > 2)
                                                                        ast_verbose(VERBOSE_PREFIX_3 "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
                                                                                plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
@@ -9710,8 +9871,12 @@ static void *pri_dchannel(void *vpri)
                                        if (crv)
                                                ast_mutex_unlock(&crv->lock);
                                        ast_mutex_unlock(&pri->pvts[chanpos]->lock);
-                               } else 
-                                       pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
+                               } else {
+                                       if (e->ring.flexible)
+                                               pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
+                                       else
+                                               pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
+                               }
                                break;
                        case PRI_EVENT_RINGING:
                                chanpos = pri_find_principle(pri, e->ringing.channel);
@@ -9729,10 +9894,9 @@ static void *pri_dchannel(void *vpri)
                                                        zt_enable_ec(pri->pvts[chanpos]);
                                                        pri->pvts[chanpos]->subs[SUB_REAL].needringing = 1;
                                                        pri->pvts[chanpos]->alerting = 1;
-                                               } else {
-                                                       if (option_debug)
-                                                               ast_log(LOG_DEBUG, "Deferring ringing notification because of extra digits to dial...\n");
-                                               }
+                                               } else
+                                                       ast_debug(1, "Deferring ringing notification because of extra digits to dial...\n");
+
 #ifdef PRI_PROGRESS_MASK
                                                if (e->ringing.progressmask & PRI_PROG_INBAND_AVAILABLE) {
 #else
@@ -9784,9 +9948,8 @@ static void *pri_dchannel(void *vpri)
                                                }
                                                
                                                ast_mutex_lock(&pri->pvts[chanpos]->lock);
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "Queuing frame from PRI_EVENT_PROGRESS on channel %d/%d span %d\n",
-                                                                       pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
+                                               ast_debug(1, "Queuing frame from PRI_EVENT_PROGRESS on channel %d/%d span %d\n",
+                                                       pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
                                                zap_queue_frame(pri->pvts[chanpos], &f, pri);
 #ifdef PRI_PROGRESS_MASK
                                                if (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) {
@@ -9811,9 +9974,8 @@ static void *pri_dchannel(void *vpri)
                                                struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROCEEDING, };
                                                
                                                ast_mutex_lock(&pri->pvts[chanpos]->lock);
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "Queuing frame from PRI_EVENT_PROCEEDING on channel %d/%d span %d\n",
-                                                                       pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
+                                               ast_debug(1, "Queuing frame from PRI_EVENT_PROCEEDING on channel %d/%d span %d\n",
+                                                       pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
                                                zap_queue_frame(pri->pvts[chanpos], &f, pri);
 #ifdef PRI_PROGRESS_MASK
                                                if (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) {
@@ -9877,8 +10039,7 @@ static void *pri_dchannel(void *vpri)
                                                        pri->pvts[chanpos]->dsp_features = 0;
                                                }
                                                if (pri->pvts[chanpos]->realcall && (pri->pvts[chanpos]->realcall->sig == SIG_FXSKS)) {
-                                                       if (option_debug)
-                                                               ast_log(LOG_DEBUG, "Starting up GR-303 trunk now that we got CONNECT...\n");
+                                                       ast_debug(1, "Starting up GR-303 trunk now that we got CONNECT...\n");
                                                        x = ZT_START;
                                                        res = ioctl(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_HOOK, &x);
                                                        if (res < 0) {
@@ -9893,14 +10054,12 @@ static void *pri_dchannel(void *vpri)
                                                        if (res < 0) {
                                                                ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d\n", pri->pvts[chanpos]->channel);
                                                                pri->pvts[chanpos]->dop.dialstr[0] = '\0';
-                                                       } else {
-                                                               if (option_debug)
-                                                                       ast_log(LOG_DEBUG, "Sent deferred digit string: %s\n", pri->pvts[chanpos]->dop.dialstr);
-                                                       }
+                                                       } else
+                                                               ast_debug(1, "Sent deferred digit string: %s\n", pri->pvts[chanpos]->dop.dialstr);
+
                                                        pri->pvts[chanpos]->dop.dialstr[0] = '\0';
                                                } else if (pri->pvts[chanpos]->confirmanswer) {
-                                                       if (option_debug)
-                                                               ast_log(LOG_DEBUG, "Waiting on answer confirmation on channel %d!\n", pri->pvts[chanpos]->channel);
+                                                       ast_debug(1, "Waiting on answer confirmation on channel %d!\n", pri->pvts[chanpos]->channel);
                                                } else {
                                                        pri->pvts[chanpos]->subs[SUB_REAL].needanswer =1;
                                                        /* Enable echo cancellation if it's not on already */
@@ -9934,25 +10093,29 @@ static void *pri_dchannel(void *vpri)
                                                        else if (pri->pvts[chanpos]->owner) {
                                                                /* Queue a BUSY instead of a hangup if our cause is appropriate */
                                                                pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
-                                                               switch (e->hangup.cause) {
-                                                               case PRI_CAUSE_USER_BUSY:
-                                                                       pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1;
-                                                                       break;
-                                                               case PRI_CAUSE_CALL_REJECTED:
-                                                               case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
-                                                               case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
-                                                               case PRI_CAUSE_SWITCH_CONGESTION:
-                                                               case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
-                                                               case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
-                                                                       pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1;
-                                                                       break;
-                                                               default:
+                                                               if (pri->pvts[chanpos]->owner->_state == AST_STATE_UP)
                                                                        pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+                                                               else {
+                                                                       switch (e->hangup.cause) {
+                                                                       case PRI_CAUSE_USER_BUSY:
+                                                                               pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1;
+                                                                               break;
+                                                                       case PRI_CAUSE_CALL_REJECTED:
+                                                                       case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
+                                                                       case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
+                                                                       case PRI_CAUSE_SWITCH_CONGESTION:
+                                                                       case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
+                                                                       case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
+                                                                               pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1;
+                                                                               break;
+                                                                       default:
+                                                                               pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+                                                                       }
                                                                }
                                                        }
                                                        if (option_verbose > 2) 
-                                                               ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d got hangup\n", 
-                                                                       pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+                                                               ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d got hangup, cause %d\n", 
+                                                                       pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, e->hangup.cause);
                                                } else {
                                                        pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
                                                        pri->pvts[chanpos]->call = NULL;
@@ -9998,23 +10161,27 @@ static void *pri_dchannel(void *vpri)
                                                        pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
                                                else if (pri->pvts[chanpos]->owner) {
                                                        pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
-                                                       switch (e->hangup.cause) {
-                                                       case PRI_CAUSE_USER_BUSY:
-                                                               pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1;
-                                                               break;
-                                                       case PRI_CAUSE_CALL_REJECTED:
-                                                       case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
-                                                       case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
-                                                       case PRI_CAUSE_SWITCH_CONGESTION:
-                                                       case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
-                                                       case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
-                                                               pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1;
-                                                               break;
-                                                       default:
+                                                       if (pri->pvts[chanpos]->owner->_state == AST_STATE_UP)
                                                                pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+                                                       else {
+                                                               switch (e->hangup.cause) {
+                                                                       case PRI_CAUSE_USER_BUSY:
+                                                                               pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1;
+                                                                               break;
+                                                                       case PRI_CAUSE_CALL_REJECTED:
+                                                                       case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
+                                                                       case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
+                                                                       case PRI_CAUSE_SWITCH_CONGESTION:
+                                                                       case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
+                                                                       case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
+                                                                               pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1;
+                                                                               break;
+                                                                       default:
+                                                                               pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+                                                               }
                                                        }
                                                        if (option_verbose > 2) 
-                                                               ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d got hangup request\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
+                                                               ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d got hangup request, cause %d\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span, e->hangup.cause);
                                                        if (e->hangup.aoc_units > -1)
                                                                if (option_verbose > 2)
                                                                        ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
@@ -10082,9 +10249,8 @@ static void *pri_dchannel(void *vpri)
                                                if (pri->pvts[x] && pri->pvts[x]->resetting) {
                                                        chanpos = x;
                                                        ast_mutex_lock(&pri->pvts[chanpos]->lock);
-                                                       if (option_debug)
-                                                               ast_log(LOG_DEBUG, "Assuming restart ack is really for channel %d/%d span %d\n", pri->pvts[chanpos]->logicalspan, 
-                                                                               pri->pvts[chanpos]->prioffset, pri->span);
+                                                       ast_debug(1, "Assuming restart ack is really for channel %d/%d span %d\n", pri->pvts[chanpos]->logicalspan, 
+                                                               pri->pvts[chanpos]->prioffset, pri->span);
                                                        if (pri->pvts[chanpos]->realcall) 
                                                                pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
                                                        else if (pri->pvts[chanpos]->owner) {
@@ -10139,8 +10305,7 @@ static void *pri_dchannel(void *vpri)
                                                pri->pvts[chanpos]->setup_ack = 1;
                                                /* Send any queued digits */
                                                for (x = 0;x < strlen(pri->pvts[chanpos]->dialdest); x++) {
-                                                       if (option_debug)
-                                                               ast_log(LOG_DEBUG, "Sending pending digit '%c'\n", pri->pvts[chanpos]->dialdest[x]);
+                                                       ast_debug(1, "Sending pending digit '%c'\n", pri->pvts[chanpos]->dialdest[x]);
                                                        pri_information(pri->pri, pri->pvts[chanpos]->call, 
                                                                pri->pvts[chanpos]->dialdest[x]);
                                                }
@@ -10171,8 +10336,7 @@ static void *pri_dchannel(void *vpri)
                                }
                                break;
                        default:
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Event: %d\n", e->e);
+                               ast_debug(1, "Event: %d\n", e->e);
                        }
                }       
                ast_mutex_unlock(&pri->lock);
@@ -10192,7 +10356,7 @@ static int start_pri(struct zt_pri *pri)
        for (i = 0; i < NUM_DCHANS; i++) {
                if (!pri->dchannels[i])
                        break;
-               pri->fds[i] = open("/dev/zap/channel", O_RDWR, 0600);
+               pri->fds[i] = open("/dev/zap/channel", O_RDWR);
                x = pri->dchannels[i];
                if ((pri->fds[i] < 0) || (ioctl(pri->fds[i],ZT_SPECIFY,&x) == -1)) {
                        ast_log(LOG_ERROR, "Unable to open D-channel %d (%s)\n", x, strerror(errno));
@@ -10235,8 +10399,8 @@ static int start_pri(struct zt_pri *pri)
                pri->dchans[i] = pri_new(pri->fds[i], pri->nodetype, pri->switchtype);
                /* Force overlap dial if we're doing GR-303! */
                if (pri->switchtype == PRI_SWITCH_GR303_TMC)
-                       pri->overlapdial = 1;
-               pri_set_overlapdial(pri->dchans[i],pri->overlapdial);
+                       pri->overlapdial |= ZAP_OVERLAPDIAL_BOTH;
+               pri_set_overlapdial(pri->dchans[i],(pri->overlapdial & ZAP_OVERLAPDIAL_OUTGOING)?1:0);
                /* Enslave to master if appropriate */
                if (i)
                        pri_enslave(pri->dchans[0], pri->dchans[i]);
@@ -10309,7 +10473,7 @@ static int handle_pri_set_debug_file(int fd, int argc, char **argv)
                if (ast_strlen_zero(argv[4]))
                        return RESULT_SHOWUSAGE;
 
-               myfd = open(argv[4], O_CREAT|O_WRONLY);
+               myfd = open(argv[4], O_CREAT|O_WRONLY, AST_FILE_MODE);
                if (myfd < 0) {
                        ast_cli(fd, "Unable to open '%s' for writing\n", argv[4]);
                        return RESULT_SUCCESS;
@@ -10484,12 +10648,12 @@ static int handle_pri_show_span(int fd, int argc, char *argv[])
                        info_str = pri_dump_info_str(pris[span-1].pri);
                        if (info_str) {
                                ast_cli(fd, "%s", info_str);
-                               free(info_str);
+                               ast_free(info_str);
                        }
 #else
                        pri_dump_info(pris[span-1].pri);
 #endif
-                       ast_cli(fd, "\n");
+                       ast_cli(fd, "Overlap Recv: %s\n\n", (pris[span-1].overlapdial & ZAP_OVERLAPDIAL_INCOMING)?"Yes":"No");
                }
        }
        return RESULT_SUCCESS;
@@ -10580,25 +10744,14 @@ static struct ast_cli_entry zap_pri_cli[] = {
 
 static int zap_destroy_channel(int fd, int argc, char **argv)
 {
-       int channel = 0;
-       struct zt_pvt *tmp = NULL;
-       struct zt_pvt *prev = NULL;
+       int channel;
        
-       if (argc != 4) {
+       if (argc != 4)
                return RESULT_SHOWUSAGE;
-       }
+       
        channel = atoi(argv[3]);
 
-       tmp = iflist;
-       while (tmp) {
-               if (tmp->channel == channel) {
-                       destroy_channel(prev, tmp, 1);
-                       return RESULT_SUCCESS;
-               }
-               prev = tmp;
-               tmp = tmp->next;
-       }
-       return RESULT_FAILURE;
+       return zap_destroy_channel_bynum(channel);
 }
 
 static int setup_zap(int reload);
@@ -10607,14 +10760,12 @@ static int zap_restart(void)
        if (option_verbose > 0)
                ast_verbose(VERBOSE_PREFIX_1 "Destroying channels and reloading zaptel configuration.\n");
        while (iflist) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Destroying zaptel channel no. %d\n", iflist->channel);
+               ast_debug(1, "Destroying zaptel channel no. %d\n", iflist->channel);
                /* Also updates iflist: */
                destroy_channel(NULL, iflist, 1);
        }
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Channels destroyed. Now re-reading config.\n");
-       if (setup_zap(0) != 0) {
+       ast_debug(1, "Channels destroyed. Now re-reading config.\n");
+       if (setup_zap(1) != 0) {
                ast_log(LOG_WARNING, "Reload channels from zap config failed!\n");
                return 1;
        }
@@ -10632,7 +10783,7 @@ static int zap_restart_cmd(int fd, int argc, char **argv)
        return RESULT_SUCCESS;
 }
 
-static int action_zaprestart(struct mansession *s, struct message *m)
+static int action_zaprestart(struct mansession *s, const struct message *m)
 {
        if (zap_restart() != 0) {
                astman_send_error(s, m, "Failed rereading zaptel configuration");
@@ -10646,6 +10797,8 @@ static int zap_show_channels(int fd, int argc, char **argv)
 {
 #define FORMAT "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s\n"
 #define FORMAT2 "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s\n"
+       unsigned int targetnum = 0;
+       int filtertype = 0;
        struct zt_pvt *tmp = NULL;
        char tmps[20] = "";
        char statestr[20] = "";
@@ -10661,27 +10814,42 @@ static int zap_show_channels(int fd, int argc, char **argv)
        lock = &iflock;
        start = iflist;
 
+       /* syntax: zap show channels [ group <group> | context <context> | trunkgroup <trunkgroup> ] */
+
+       if (!((argc == 3) || (argc == 5)))
+               return RESULT_SHOWUSAGE;
+
+       if (argc == 5) {
 #ifdef HAVE_PRI
-       if (argc == 4) {
-               if ((trunkgroup = atoi(argv[3])) < 1)
-                       return RESULT_SHOWUSAGE;
-               for (x = 0; x < NUM_SPANS; x++) {
-                       if (pris[x].trunkgroup == trunkgroup) {
-                               pri = pris + x;
-                               break;
+               if (!strcasecmp(argv[3], "trunkgroup")) {
+                       /* this option requires no special handling, so leave filtertype to zero */
+                       if ((trunkgroup = atoi(argv[4])) < 1)
+                               return RESULT_SHOWUSAGE;
+                       for (x = 0; x < NUM_SPANS; x++) {
+                               if (pris[x].trunkgroup == trunkgroup) {
+                                       pri = pris + x;
+                                       break;
+                               }
                        }
+                       if (pri) {
+                               start = pri->crvs;
+                               lock = &pri->lock;
+                       } else {
+                               ast_cli(fd, "No such trunk group %d\n", trunkgroup);
+                               return RESULT_FAILURE;
+                       }
+               } else
+#endif 
+               if (!strcasecmp(argv[3], "group")) {
+                       targetnum = atoi(argv[4]);
+                       if ((targetnum < 0) || (targetnum > 63))
+                               return RESULT_SHOWUSAGE;
+                       targetnum = 1 << targetnum;
+                       filtertype = 1;
+               } else if (!strcasecmp(argv[3], "context")) {
+                       filtertype = 2;
                }
-               if (pri) {
-                       start = pri->crvs;
-                       lock = &pri->lock;
-               } else {
-                       ast_cli(fd, "No such trunk group %d\n", trunkgroup);
-                       return RESULT_FAILURE;
-               }
-       } else
-#endif
-       if (argc != 3)
-               return RESULT_SHOWUSAGE;
+       }
 
        ast_mutex_lock(lock);
 #ifdef HAVE_PRI
@@ -10692,6 +10860,24 @@ static int zap_show_channels(int fd, int argc, char **argv)
        
        tmp = start;
        while (tmp) {
+               if (filtertype) {
+                       switch(filtertype) {
+                       case 1: /* zap show channels group <group> */
+                               if (tmp->group != targetnum) {
+                                       tmp = tmp->next;
+                                       continue;
+                               }
+                               break;
+                       case 2: /* zap show channels context <context> */
+                               if (strcasecmp(tmp->context, argv[4])) {
+                                       tmp = tmp->next;
+                                       continue;
+                               }
+                               break;
+                       default:
+                               ;
+                       }
+               }
                if (tmp->channel > 0) {
                        snprintf(tmps, sizeof(tmps), "%d", tmp->channel);
                } else
@@ -10793,6 +10979,7 @@ static int zap_show_channel(int fd, int argc, char **argv)
                        ast_cli(fd, "Propagated Conference: %d\n", tmp->propconfno);
                        ast_cli(fd, "Real in conference: %d\n", tmp->inconference);
                        ast_cli(fd, "DSP: %s\n", tmp->dsp ? "yes" : "no");
+                       ast_cli(fd, "TDD: %s\n", tmp->tdd ? "yes" : "no");
                        ast_cli(fd, "Relax DTMF: %s\n", tmp->dtmfrelax ? "yes" : "no");
                        ast_cli(fd, "Dialing/CallwaitCAS: %d/%d\n", tmp->dialing, tmp->callwaitcas);
                        ast_cli(fd, "Default law: %s\n", tmp->law == ZT_LAW_MULAW ? "ulaw" : tmp->law == ZT_LAW_ALAW ? "alaw" : "unknown");
@@ -10947,29 +11134,57 @@ static int zap_show_status(int fd, int argc, char *argv[]) {
 #undef FORMAT2
 }
 
-static char show_channels_usage[] =
-       "Usage: zap show channels\n"
-       "       Shows a list of available channels\n";
+static int zap_show_version(int fd, int argc, char *argv[])
+{
+       int pseudo_fd = -1;
+       struct zt_versioninfo vi;
+
+       if ((pseudo_fd = open("/dev/zap/ctl", O_RDONLY)) < 0) {
+               ast_cli(fd, "Failed to open control file to get version.\n");
+               return RESULT_SUCCESS;
+       }
+
+       strcpy(vi.version, "Unknown");
+       strcpy(vi.echo_canceller, "Unknown");
 
-static char show_channel_usage[] =
+       if (ioctl(pseudo_fd, ZT_GETVERSION, &vi))
+               ast_cli(fd, "Failed to get version from control file.\n");
+       else
+               ast_cli(fd, "Zaptel Version: %s Echo Canceller: %s\n", vi.version, vi.echo_canceller);
+
+       close(pseudo_fd);
+
+       return RESULT_SUCCESS;
+}
+
+static const char show_channels_usage[] =
+       "Usage: zap show channels [ trunkgroup <trunkgroup> | group <group> | context <context> ]\n"
+       "       Shows a list of available channels with optional filtering\n"
+       "       <group> must be a number between 0 and 63\n";
+
+static const char show_channel_usage[] =
        "Usage: zap show channel <chan num>\n"
        "       Detailed information about a given channel\n";
 
-static char zap_show_status_usage[] =
+static const char zap_show_status_usage[] =
        "Usage: zap show status\n"
        "       Shows a list of Zaptel cards with status\n";
 
-static char destroy_channel_usage[] =
+static const char destroy_channel_usage[] =
        "Usage: zap destroy channel <chan num>\n"
        "       DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.  Immediately re