Make --with-pjproject-bundled the default for Asterisk 15
[asterisk/asterisk.git] / channels / sig_pri.c
index e94f08e..1b228af 100644 (file)
  * \author Matthew Fredrickson <creslin@digium.com>
  */
 
+/*** MODULEINFO
+       <support_level>core</support_level>
+ ***/
+/*** DOCUMENTATION
+       <managerEvent language="en_US" name="MCID">
+               <managerEventInstance class="EVENT_FLAG_CALL">
+                       <synopsis>Published when a malicious call ID request arrives.</synopsis>
+                       <syntax>
+                               <channel_snapshot/>
+                               <parameter name="MCallerIDNumValid">
+                               </parameter>
+                               <parameter name="MCallerIDNum">
+                               </parameter>
+                               <parameter name="MCallerIDton">
+                               </parameter>
+                               <parameter name="MCallerIDNumPlan">
+                               </parameter>
+                               <parameter name="MCallerIDNumPres">
+                               </parameter>
+                               <parameter name="MCallerIDNameValid">
+                               </parameter>
+                               <parameter name="MCallerIDName">
+                               </parameter>
+                               <parameter name="MCallerIDNameCharSet">
+                               </parameter>
+                               <parameter name="MCallerIDNamePres">
+                               </parameter>
+                               <parameter name="MCallerIDSubaddr">
+                               </parameter>
+                               <parameter name="MCallerIDSubaddrType">
+                               </parameter>
+                               <parameter name="MCallerIDSubaddrOdd">
+                               </parameter>
+                               <parameter name="MCallerIDPres">
+                               </parameter>
+                               <parameter name="MConnectedIDNumValid">
+                               </parameter>
+                               <parameter name="MConnectedIDNum">
+                               </parameter>
+                               <parameter name="MConnectedIDton">
+                               </parameter>
+                               <parameter name="MConnectedIDNumPlan">
+                               </parameter>
+                               <parameter name="MConnectedIDNumPres">
+                               </parameter>
+                               <parameter name="MConnectedIDNameValid">
+                               </parameter>
+                               <parameter name="MConnectedIDName">
+                               </parameter>
+                               <parameter name="MConnectedIDNameCharSet">
+                               </parameter>
+                               <parameter name="MConnectedIDNamePres">
+                               </parameter>
+                               <parameter name="MConnectedIDSubaddr">
+                               </parameter>
+                               <parameter name="MConnectedIDSubaddrType">
+                               </parameter>
+                               <parameter name="MConnectedIDSubaddrOdd">
+                               </parameter>
+                               <parameter name="MConnectedIDPres">
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
+ ***/
 
 #include "asterisk.h"
 
 #include "asterisk/transcap.h"
 #include "asterisk/features.h"
 #include "asterisk/aoc.h"
+#include "asterisk/bridge.h"
+#include "asterisk/stasis_channels.h"
 
 #include "sig_pri.h"
 #ifndef PRI_EVENT_FACILITY
-#error please update libpri
+#error "Upgrade your libpri"
 #endif
 
+/*** DOCUMENTATION
+ ***/
+
+
 /* define this to send PRI user-user information elements */
 #undef SUPPORT_USERUSER
 
  */
 //#define ALWAYS_PICK_CHANNEL  1
 
-/*!
- * Define to force a RESTART on a channel that returns a cause
- * code of PRI_CAUSE_REQUESTED_CHAN_UNAVAIL(44).  If the cause
- * is because of a stuck channel on the peer and the channel is
- * always the next channel we pick for an outgoing call then
- * this can help.
- */
-#define FORCE_RESTART_UNAVAIL_CHANS            1
-
 #if defined(HAVE_PRI_CCSS)
 struct sig_pri_cc_agent_prv {
        /*! Asterisk span D channel control structure. */
@@ -115,13 +177,6 @@ static int pri_gendigittimeout = 8000;
 
 #define DCHAN_AVAILABLE        (DCHAN_NOTINALARM | DCHAN_UP)
 
-#define PRI_DEADLOCK_AVOIDANCE(p) \
-       do { \
-               sig_pri_unlock_private(p); \
-               usleep(1); \
-               sig_pri_lock_private(p); \
-       } while (0)
-
 static int pri_active_dchan_index(struct sig_pri_span *pri);
 
 static const char *sig_pri_call_level2str(enum sig_pri_call_level level)
@@ -161,30 +216,31 @@ static unsigned int PVT_TO_CHANNEL(struct sig_pri_chan *p)
 
 static void sig_pri_handle_dchan_exception(struct sig_pri_span *pri, int index)
 {
-       if (pri->calls->handle_dchan_exception)
-               pri->calls->handle_dchan_exception(pri, index);
+       if (sig_pri_callbacks.handle_dchan_exception) {
+               sig_pri_callbacks.handle_dchan_exception(pri, index);
+       }
 }
 
 static void sig_pri_set_dialing(struct sig_pri_chan *p, int is_dialing)
 {
-       if (p->calls->set_dialing) {
-               p->calls->set_dialing(p->chan_pvt, is_dialing);
+       if (sig_pri_callbacks.set_dialing) {
+               sig_pri_callbacks.set_dialing(p->chan_pvt, is_dialing);
        }
 }
 
 static void sig_pri_set_digital(struct sig_pri_chan *p, int is_digital)
 {
        p->digital = is_digital;
-       if (p->calls->set_digital) {
-               p->calls->set_digital(p->chan_pvt, is_digital);
+       if (sig_pri_callbacks.set_digital) {
+               sig_pri_callbacks.set_digital(p->chan_pvt, is_digital);
        }
 }
 
 static void sig_pri_set_outgoing(struct sig_pri_chan *p, int is_outgoing)
 {
        p->outgoing = is_outgoing;
-       if (p->calls->set_outgoing) {
-               p->calls->set_outgoing(p->chan_pvt, is_outgoing);
+       if (sig_pri_callbacks.set_outgoing) {
+               sig_pri_callbacks.set_outgoing(p->chan_pvt, is_outgoing);
        }
 }
 
@@ -203,15 +259,15 @@ void sig_pri_set_alarm(struct sig_pri_chan *p, int in_alarm)
        p->resetting = SIG_PRI_RESET_IDLE;
 
        p->inalarm = in_alarm;
-       if (p->calls->set_alarm) {
-               p->calls->set_alarm(p->chan_pvt, in_alarm);
+       if (sig_pri_callbacks.set_alarm) {
+               sig_pri_callbacks.set_alarm(p->chan_pvt, in_alarm);
        }
 }
 
 static const char *sig_pri_get_orig_dialstring(struct sig_pri_chan *p)
 {
-       if (p->calls->get_orig_dialstring) {
-               return p->calls->get_orig_dialstring(p->chan_pvt);
+       if (sig_pri_callbacks.get_orig_dialstring) {
+               return sig_pri_callbacks.get_orig_dialstring(p->chan_pvt);
        }
        ast_log(LOG_ERROR, "get_orig_dialstring callback not defined\n");
        return "";
@@ -220,8 +276,8 @@ static const char *sig_pri_get_orig_dialstring(struct sig_pri_chan *p)
 #if defined(HAVE_PRI_CCSS)
 static void sig_pri_make_cc_dialstring(struct sig_pri_chan *p, char *buf, size_t buf_size)
 {
-       if (p->calls->make_cc_dialstring) {
-               p->calls->make_cc_dialstring(p->chan_pvt, buf, buf_size);
+       if (sig_pri_callbacks.make_cc_dialstring) {
+               sig_pri_callbacks.make_cc_dialstring(p->chan_pvt, buf, buf_size);
        } else {
                ast_log(LOG_ERROR, "make_cc_dialstring callback not defined\n");
                buf[0] = '\0';
@@ -231,8 +287,8 @@ static void sig_pri_make_cc_dialstring(struct sig_pri_chan *p, char *buf, size_t
 
 static void sig_pri_dial_digits(struct sig_pri_chan *p, const char *dial_string)
 {
-       if (p->calls->dial_digits) {
-               p->calls->dial_digits(p->chan_pvt, dial_string);
+       if (sig_pri_callbacks.dial_digits) {
+               sig_pri_callbacks.dial_digits(p->chan_pvt, dial_string);
        }
 }
 
@@ -249,8 +305,8 @@ static void sig_pri_dial_digits(struct sig_pri_chan *p, const char *dial_string)
  */
 static void sig_pri_span_devstate_changed(struct sig_pri_span *pri)
 {
-       if (pri->calls->update_span_devstate) {
-               pri->calls->update_span_devstate(pri);
+       if (sig_pri_callbacks.update_span_devstate) {
+               sig_pri_callbacks.update_span_devstate(pri);
        }
 }
 
@@ -267,7 +323,7 @@ static void sig_pri_set_caller_id(struct sig_pri_chan *p)
 {
        struct ast_party_caller caller;
 
-       if (p->calls->set_callerid) {
+       if (sig_pri_callbacks.set_callerid) {
                ast_party_caller_init(&caller);
 
                caller.id.name.str = p->cid_name;
@@ -293,7 +349,7 @@ static void sig_pri_set_caller_id(struct sig_pri_chan *p)
                caller.ani.number.valid = 1;
 
                caller.ani2 = p->cid_ani2;
-               p->calls->set_callerid(p->chan_pvt, &caller);
+               sig_pri_callbacks.set_callerid(p->chan_pvt, &caller);
        }
 }
 
@@ -309,8 +365,8 @@ static void sig_pri_set_caller_id(struct sig_pri_chan *p)
  */
 static void sig_pri_set_dnid(struct sig_pri_chan *p, const char *dnid)
 {
-       if (p->calls->set_dnid) {
-               p->calls->set_dnid(p->chan_pvt, dnid);
+       if (sig_pri_callbacks.set_dnid) {
+               sig_pri_callbacks.set_dnid(p->chan_pvt, dnid);
        }
 }
 
@@ -326,46 +382,48 @@ static void sig_pri_set_dnid(struct sig_pri_chan *p, const char *dnid)
  */
 static void sig_pri_set_rdnis(struct sig_pri_chan *p, const char *rdnis)
 {
-       if (p->calls->set_rdnis) {
-               p->calls->set_rdnis(p->chan_pvt, rdnis);
+       if (sig_pri_callbacks.set_rdnis) {
+               sig_pri_callbacks.set_rdnis(p->chan_pvt, rdnis);
        }
 }
 
 static void sig_pri_unlock_private(struct sig_pri_chan *p)
 {
-       if (p->calls->unlock_private)
-               p->calls->unlock_private(p->chan_pvt);
+       if (sig_pri_callbacks.unlock_private) {
+               sig_pri_callbacks.unlock_private(p->chan_pvt);
+       }
 }
 
 static void sig_pri_lock_private(struct sig_pri_chan *p)
 {
-       if (p->calls->lock_private)
-               p->calls->lock_private(p->chan_pvt);
+       if (sig_pri_callbacks.lock_private) {
+               sig_pri_callbacks.lock_private(p->chan_pvt);
+       }
 }
 
 static void sig_pri_deadlock_avoidance_private(struct sig_pri_chan *p)
 {
-       if (p->calls->deadlock_avoidance_private) {
-               p->calls->deadlock_avoidance_private(p->chan_pvt);
+       if (sig_pri_callbacks.deadlock_avoidance_private) {
+               sig_pri_callbacks.deadlock_avoidance_private(p->chan_pvt);
        } else {
                /* Fallback to the old way if callback not present. */
-               PRI_DEADLOCK_AVOIDANCE(p);
+               sig_pri_unlock_private(p);
+               sched_yield();
+               sig_pri_lock_private(p);
        }
 }
 
 static void pri_grab(struct sig_pri_chan *p, struct sig_pri_span *pri)
 {
-       int res;
-
        /* Grab the lock first */
-       do {
-               res = ast_mutex_trylock(&pri->lock);
-               if (res) {
-                       sig_pri_deadlock_avoidance_private(p);
-               }
-       } while (res);
+       while (ast_mutex_trylock(&pri->lock)) {
+               /* Avoid deadlock */
+               sig_pri_deadlock_avoidance_private(p);
+       }
        /* Then break the poll */
-       pthread_kill(pri->master, SIGURG);
+       if (pri->master != AST_PTHREADT_NULL) {
+               pthread_kill(pri->master, SIGURG);
+       }
 }
 
 /*!
@@ -662,12 +720,7 @@ static int ast_to_pri_char_set(enum AST_PARTY_CHAR_SET ast_char_set)
  */
 static void sig_pri_set_subaddress(struct ast_party_subaddress *ast_subaddress, const struct pri_party_subaddress *pri_subaddress)
 {
-       char *cnum, *ptr;
-       int x, len;
-
-       if (ast_subaddress->str) {
-               ast_free(ast_subaddress->str);
-       }
+       ast_free(ast_subaddress->str);
        if (pri_subaddress->length <= 0) {
                ast_party_subaddress_init(ast_subaddress);
                return;
@@ -677,8 +730,14 @@ static void sig_pri_set_subaddress(struct ast_party_subaddress *ast_subaddress,
                /* NSAP */
                ast_subaddress->str = ast_strdup((char *) pri_subaddress->data);
        } else {
+               char *cnum;
+               char *ptr;
+               int x;
+               int len;
+
                /* User Specified */
-               if (!(cnum = ast_malloc(2 * pri_subaddress->length + 1))) {
+               cnum = ast_malloc(2 * pri_subaddress->length + 1);
+               if (!cnum) {
                        ast_party_subaddress_init(ast_subaddress);
                        return;
                }
@@ -686,15 +745,15 @@ static void sig_pri_set_subaddress(struct ast_party_subaddress *ast_subaddress,
                ptr = cnum;
                len = pri_subaddress->length - 1; /* -1 account for zero based indexing */
                for (x = 0; x < len; ++x) {
-                       ptr += sprintf(ptr, "%02x", pri_subaddress->data[x]);
+                       ptr += sprintf(ptr, "%02hhx", (unsigned char)pri_subaddress->data[x]);
                }
 
                if (pri_subaddress->odd_even_indicator) {
                        /* ODD */
-                       sprintf(ptr, "%01x", (pri_subaddress->data[len]) >> 4);
+                       sprintf(ptr, "%01hhx", (unsigned char)((pri_subaddress->data[len]) >> 4));
                } else {
                        /* EVEN */
-                       sprintf(ptr, "%02x", pri_subaddress->data[len]);
+                       sprintf(ptr, "%02hhx", (unsigned char)pri_subaddress->data[len]);
                }
                ast_subaddress->str = cnum;
        }
@@ -903,15 +962,18 @@ static void sig_pri_redirecting_update(struct sig_pri_chan *pvt, struct ast_chan
 {
        struct pri_party_redirecting pri_redirecting;
        const struct ast_party_redirecting *ast_redirecting;
+       struct ast_party_id redirecting_from = ast_channel_redirecting_effective_from(ast);
+       struct ast_party_id redirecting_to = ast_channel_redirecting_effective_to(ast);
+       struct ast_party_id redirecting_orig = ast_channel_redirecting_effective_orig(ast);
 
        memset(&pri_redirecting, 0, sizeof(pri_redirecting));
        ast_redirecting = ast_channel_redirecting(ast);
-       sig_pri_party_id_from_ast(&pri_redirecting.from, &ast_redirecting->from);
-       sig_pri_party_id_from_ast(&pri_redirecting.to, &ast_redirecting->to);
-       sig_pri_party_id_from_ast(&pri_redirecting.orig_called, &ast_redirecting->orig);
+       sig_pri_party_id_from_ast(&pri_redirecting.from, &redirecting_from);
+       sig_pri_party_id_from_ast(&pri_redirecting.to, &redirecting_to);
+       sig_pri_party_id_from_ast(&pri_redirecting.orig_called, &redirecting_orig);
        pri_redirecting.count = ast_redirecting->count;
-       pri_redirecting.orig_reason = ast_to_pri_reason(ast_redirecting->orig_reason);
-       pri_redirecting.reason = ast_to_pri_reason(ast_redirecting->reason);
+       pri_redirecting.orig_reason = ast_to_pri_reason(ast_redirecting->orig_reason.code);
+       pri_redirecting.reason = ast_to_pri_reason(ast_redirecting->reason.code);
 
        pri_redirecting_update(pvt->pri->pri, pvt->call, &pri_redirecting);
 }
@@ -927,39 +989,44 @@ static void sig_pri_redirecting_update(struct sig_pri_chan *pvt, struct ast_chan
  */
 static void sig_pri_dsp_reset_and_flush_digits(struct sig_pri_chan *p)
 {
-       if (p->calls->dsp_reset_and_flush_digits) {
-               p->calls->dsp_reset_and_flush_digits(p->chan_pvt);
+       if (sig_pri_callbacks.dsp_reset_and_flush_digits) {
+               sig_pri_callbacks.dsp_reset_and_flush_digits(p->chan_pvt);
        }
 }
 
 static int sig_pri_set_echocanceller(struct sig_pri_chan *p, int enable)
 {
-       if (p->calls->set_echocanceller)
-               return p->calls->set_echocanceller(p->chan_pvt, enable);
-       else
+       if (sig_pri_callbacks.set_echocanceller) {
+               return sig_pri_callbacks.set_echocanceller(p->chan_pvt, enable);
+       } else {
                return -1;
+       }
 }
 
 static void sig_pri_fixup_chans(struct sig_pri_chan *old_chan, struct sig_pri_chan *new_chan)
 {
-       if (old_chan->calls->fixup_chans)
-               old_chan->calls->fixup_chans(old_chan->chan_pvt, new_chan->chan_pvt);
+       if (sig_pri_callbacks.fixup_chans) {
+               sig_pri_callbacks.fixup_chans(old_chan->chan_pvt, new_chan->chan_pvt);
+       }
 }
 
 static int sig_pri_play_tone(struct sig_pri_chan *p, enum sig_pri_tone tone)
 {
-       if (p->calls->play_tone)
-               return p->calls->play_tone(p->chan_pvt, tone);
-       else
+       if (sig_pri_callbacks.play_tone) {
+               return sig_pri_callbacks.play_tone(p->chan_pvt, tone);
+       } else {
                return -1;
+       }
 }
 
-static struct ast_channel *sig_pri_new_ast_channel(struct sig_pri_chan *p, int state, int ulaw, int transfercapability, char *exten, const struct ast_channel *requestor)
+static struct ast_channel *sig_pri_new_ast_channel(struct sig_pri_chan *p, int state,
+       enum sig_pri_law law, int transfercapability, char *exten,
+       const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
 {
        struct ast_channel *c;
 
-       if (p->calls->new_ast_channel) {
-               c = p->calls->new_ast_channel(p->chan_pvt, state, ulaw, exten, requestor);
+       if (sig_pri_callbacks.new_ast_channel) {
+               c = sig_pri_callbacks.new_ast_channel(p->chan_pvt, state, law, exten, assignedids, requestor);
        } else {
                return NULL;
        }
@@ -967,8 +1034,8 @@ static struct ast_channel *sig_pri_new_ast_channel(struct sig_pri_chan *p, int s
                return NULL;
        }
 
-       if (!p->owner)
-               p->owner = c;
+       ast_assert(p->owner == NULL || p->owner == c);
+       p->owner = c;
        p->isidlecall = 0;
        p->alreadyhungup = 0;
        ast_channel_transfercapability_set(c, transfercapability);
@@ -1001,8 +1068,8 @@ static void sig_pri_open_media(struct sig_pri_chan *p)
                return;
        }
 
-       if (p->calls->open_media) {
-               p->calls->open_media(p->chan_pvt);
+       if (sig_pri_callbacks.open_media) {
+               sig_pri_callbacks.open_media(p->chan_pvt);
        }
 }
 
@@ -1019,19 +1086,22 @@ static void sig_pri_open_media(struct sig_pri_chan *p)
  */
 static void sig_pri_ami_channel_event(struct sig_pri_chan *p)
 {
-       if (p->calls->ami_channel_event) {
-               p->calls->ami_channel_event(p->chan_pvt, p->owner);
+       if (sig_pri_callbacks.ami_channel_event) {
+               sig_pri_callbacks.ami_channel_event(p->chan_pvt, p->owner);
        }
 }
 
-struct ast_channel *sig_pri_request(struct sig_pri_chan *p, enum sig_pri_law law, const struct ast_channel *requestor, int transfercapability)
+struct ast_channel *sig_pri_request(struct sig_pri_chan *p, enum sig_pri_law law,
+       const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
+       int transfercapability)
 {
        struct ast_channel *ast;
 
        ast_debug(1, "%s %d\n", __FUNCTION__, p->channel);
 
        sig_pri_set_outgoing(p, 1);
-       ast = sig_pri_new_ast_channel(p, AST_STATE_RESERVED, law, transfercapability, p->exten, requestor);
+       ast = sig_pri_new_ast_channel(p, AST_STATE_RESERVED, law, transfercapability,
+               p->exten, assignedids, requestor);
        if (!ast) {
                sig_pri_set_outgoing(p, 0);
        }
@@ -1205,10 +1275,11 @@ static void sig_pri_lock_owner(struct sig_pri_span *pri, int chanpos)
                        /* We got the lock */
                        break;
                }
-               /* We must unlock the PRI to avoid the possibility of a deadlock */
-               ast_mutex_unlock(&pri->lock);
-               sig_pri_deadlock_avoidance_private(pri->pvts[chanpos]);
-               ast_mutex_lock(&pri->lock);
+
+               /* Avoid deadlock */
+               sig_pri_unlock_private(pri->pvts[chanpos]);
+               DEADLOCK_AVOIDANCE(&pri->lock);
+               sig_pri_lock_private(pri->pvts[chanpos]);
        }
 }
 
@@ -1237,6 +1308,50 @@ static void pri_queue_frame(struct sig_pri_span *pri, int chanpos, struct ast_fr
 
 /*!
  * \internal
+ * \brief Queue a hold frame onto the owner channel.
+ * \since 12
+ *
+ * \param pri PRI span control structure.
+ * \param chanpos Channel position in the span.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_queue_hold(struct sig_pri_span *pri, int chanpos)
+{
+       sig_pri_lock_owner(pri, chanpos);
+       if (pri->pvts[chanpos]->owner) {
+               ast_queue_hold(pri->pvts[chanpos]->owner, NULL);
+               ast_channel_unlock(pri->pvts[chanpos]->owner);
+       }
+}
+
+/*!
+ * \internal
+ * \brief Queue an unhold frame onto the owner channel.
+ * \since 12
+ *
+ * \param pri PRI span control structure.
+ * \param chanpos Channel position in the span.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_queue_unhold(struct sig_pri_span *pri, int chanpos)
+{
+       sig_pri_lock_owner(pri, chanpos);
+       if (pri->pvts[chanpos]->owner) {
+               ast_queue_unhold(pri->pvts[chanpos]->owner);
+               ast_channel_unlock(pri->pvts[chanpos]->owner);
+       }
+}
+
+/*!
+ * \internal
  * \brief Queue a control frame of the specified subclass onto the owner channel.
  * \since 1.8
  *
@@ -1252,10 +1367,9 @@ static void pri_queue_frame(struct sig_pri_span *pri, int chanpos, struct ast_fr
 static void pri_queue_control(struct sig_pri_span *pri, int chanpos, int subclass)
 {
        struct ast_frame f = {AST_FRAME_CONTROL, };
-       struct sig_pri_chan *p = pri->pvts[chanpos];
 
-       if (p->calls->queue_control) {
-               p->calls->queue_control(p->chan_pvt, subclass);
+       if (sig_pri_callbacks.queue_control) {
+               sig_pri_callbacks.queue_control(pri->pvts[chanpos]->chan_pvt, subclass);
        }
 
        f.subclass.integer = subclass;
@@ -1264,6 +1378,65 @@ static void pri_queue_control(struct sig_pri_span *pri, int chanpos, int subclas
 
 /*!
  * \internal
+ * \brief Queue a request to hangup control frame onto the owner channel.
+ *
+ * \param pri PRI span control structure.
+ * \param chanpos Channel position in the span.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_queue_hangup(struct sig_pri_span *pri, int chanpos)
+{
+       if (sig_pri_callbacks.queue_control) {
+               sig_pri_callbacks.queue_control(pri->pvts[chanpos]->chan_pvt, AST_CONTROL_HANGUP);
+       }
+
+       sig_pri_lock_owner(pri, chanpos);
+       if (pri->pvts[chanpos]->owner) {
+               ast_queue_hangup(pri->pvts[chanpos]->owner);
+               ast_channel_unlock(pri->pvts[chanpos]->owner);
+       }
+}
+
+/*!
+ * \internal
+ * \brief Queue a PVT_CAUSE_CODE frame onto the owner channel.
+ * \since 11
+ *
+ * \param pri PRI span control structure.
+ * \param chanpos Channel position in the span.
+ * \param cause String describing the cause to be placed into the frame.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
+ *
+ * \return Nothing
+ */
+static void pri_queue_pvt_cause_data(struct sig_pri_span *pri, int chanpos, const char *cause, int ast_cause)
+{
+       struct ast_channel *chan;
+       struct ast_control_pvt_cause_code *cause_code;
+
+       sig_pri_lock_owner(pri, chanpos);
+       chan = pri->pvts[chanpos]->owner;
+       if (chan) {
+               int datalen = sizeof(*cause_code) + strlen(cause);
+               cause_code = ast_alloca(datalen);
+               memset(cause_code, 0, datalen);
+               cause_code->ast_cause = ast_cause;
+               ast_copy_string(cause_code->chan_name, ast_channel_name(chan), AST_CHANNEL_NAME);
+               ast_copy_string(cause_code->code, cause, datalen + 1 - sizeof(*cause_code));
+               ast_queue_control_data(chan, AST_CONTROL_PVT_CAUSE_CODE, cause_code, datalen);
+               ast_channel_hangupcause_hash_set(chan, cause_code, datalen);
+               ast_channel_unlock(chan);
+       }
+}
+
+/*!
+ * \internal
  * \brief Find the channel associated with the libpri call.
  * \since 10.0
  *
@@ -1294,6 +1467,27 @@ static int pri_find_principle_by_call(struct sig_pri_span *pri, q931_call *call)
 
 /*!
  * \internal
+ * \brief Queue the span for destruction
+ * \since 13.0
+ *
+ * \param pri PRI span control structure.
+ *
+ * Asks the channel driver to queue the span for destruction at a
+ * possibly later time, if (e.g.) locking considerations don't allow
+ * destroying it right now.
+ *
+ * \return Nothing
+ */
+static void pri_destroy_later(struct sig_pri_span *pri)
+{
+       if (!sig_pri_callbacks.destroy_later) {
+               return;
+       }
+       sig_pri_callbacks.destroy_later(pri);
+}
+
+/*!
+ * \internal
  * \brief Kill the call.
  * \since 10.0
  *
@@ -1471,6 +1665,9 @@ static int pri_fixup_principle(struct sig_pri_span *pri, int principle, q931_cal
 #if defined(HAVE_PRI_CALL_WAITING)
                new_chan->is_call_waiting = old_chan->is_call_waiting;
 #endif /* defined(HAVE_PRI_CALL_WAITING) */
+#if defined(HAVE_PRI_SETUP_ACK_INBAND)
+               new_chan->no_dialed_digits = old_chan->no_dialed_digits;
+#endif /* defined(HAVE_PRI_SETUP_ACK_INBAND) */
 
 #if defined(HAVE_PRI_AOC_EVENTS)
                old_chan->aoc_s_request_invoke_id_valid = 0;
@@ -1486,6 +1683,9 @@ static int pri_fixup_principle(struct sig_pri_span *pri, int principle, q931_cal
 #if defined(HAVE_PRI_CALL_WAITING)
                old_chan->is_call_waiting = 0;
 #endif /* defined(HAVE_PRI_CALL_WAITING) */
+#if defined(HAVE_PRI_SETUP_ACK_INBAND)
+               old_chan->no_dialed_digits = 0;
+#endif /* defined(HAVE_PRI_SETUP_ACK_INBAND) */
 
                /* More stuff to transfer to the new channel. */
                new_chan->call_level = old_chan->call_level;
@@ -1500,6 +1700,10 @@ static int pri_fixup_principle(struct sig_pri_span *pri, int principle, q931_cal
                strcpy(new_chan->moh_suggested, old_chan->moh_suggested);
                new_chan->moh_state = old_chan->moh_state;
                old_chan->moh_state = SIG_PRI_MOH_STATE_IDLE;
+#if defined(HAVE_PRI_TRANSFER)
+               new_chan->xfer_data = old_chan->xfer_data;
+               old_chan->xfer_data = NULL;
+#endif /* defined(HAVE_PRI_TRANSFER) */
 
 #if defined(HAVE_PRI_AOC_EVENTS)
                new_chan->aoc_s_request_invoke_id = old_chan->aoc_s_request_invoke_id;
@@ -1750,8 +1954,8 @@ static void sig_pri_init_config(struct sig_pri_chan *pvt, struct sig_pri_span *p
        ast_copy_string(pvt->context, pri->ch_cfg.context, sizeof(pvt->context));
        ast_copy_string(pvt->mohinterpret, pri->ch_cfg.mohinterpret, sizeof(pvt->mohinterpret));
 
-       if (pri->calls->init_config) {
-               pri->calls->init_config(pvt->chan_pvt, pri);
+       if (sig_pri_callbacks.init_config) {
+               sig_pri_callbacks.init_config(pvt->chan_pvt, pri);
        }
 }
 #endif /* defined(HAVE_PRI_CALL_WAITING) */
@@ -1822,8 +2026,8 @@ static int pri_find_empty_nobch(struct sig_pri_span *pri)
        }
 
        /* Need to create a new interface. */
-       if (pri->calls->new_nobch_intf) {
-               idx = pri->calls->new_nobch_intf(pri);
+       if (sig_pri_callbacks.new_nobch_intf) {
+               idx = sig_pri_callbacks.new_nobch_intf(pri);
        } else {
                idx = -1;
        }
@@ -1838,7 +2042,14 @@ static void *do_idle_thread(void *v_pvt)
        struct ast_frame *f;
        char ex[80];
        /* Wait up to 30 seconds for an answer */
-       int newms, ms = 30000;
+       int timeout_ms = 30000;
+       int ms;
+       struct timeval start;
+       ast_callid callid;
+
+       if ((callid = ast_channel_callid(chan))) {
+               ast_callid_threadassoc_add(callid);
+       }
 
        ast_verb(3, "Initiating idle call on channel %s\n", ast_channel_name(chan));
        snprintf(ex, sizeof(ex), "%d/%s", pvt->channel, pvt->pri->idledial);
@@ -1847,7 +2058,12 @@ static void *do_idle_thread(void *v_pvt)
                ast_hangup(chan);
                return NULL;
        }
-       while ((newms = ast_waitfor(chan, ms)) > 0) {
+       start = ast_tvnow();
+       while ((ms = ast_remaining_ms(start, timeout_ms))) {
+               if (ast_waitfor(chan, ms) <= 0) {
+                       break;
+               }
+
                f = ast_read(chan);
                if (!f) {
                        /* Got hangup */
@@ -1873,7 +2089,6 @@ static void *do_idle_thread(void *v_pvt)
                        };
                }
                ast_frfree(f);
-               ms = newms;
        }
        /* Hangup the channel since nothing happend */
        ast_hangup(chan);
@@ -1888,12 +2103,17 @@ static void *pri_ss_thread(void *data)
        int res;
        int len;
        int timeout;
+       ast_callid callid;
 
        if (!chan) {
                /* We lost the owner before we could get started. */
                return NULL;
        }
 
+       if ((callid = ast_channel_callid(chan))) {
+               ast_callid_threadassoc_add(callid);
+       }
+
        /*
         * In the bizarre case where the channel has become a zombie before we
         * even get started here, abort safely.
@@ -1957,10 +2177,10 @@ static void *pri_ss_thread(void *data)
                /* Start the real PBX */
                ast_channel_exten_set(chan, exten);
                sig_pri_dsp_reset_and_flush_digits(p);
-#if defined(ISSUE_16789)
+#if defined(JIRA_ASTERISK_15594)
                /*
-                * Conditionaled out this code to effectively revert the Mantis
-                * issue 16789 change.  It breaks overlap dialing through
+                * Conditionaled out this code to effectively revert the JIRA
+                * ASTERISK-15594 change.  It breaks overlap dialing through
                 * Asterisk.  There is not enough information available at this
                 * point to know if dialing is complete.  The
                 * ast_exists_extension(), ast_matchmore_extension(), and
@@ -1983,10 +2203,12 @@ static void *pri_ss_thread(void *data)
                        }
                        sig_pri_unlock_private(p);
                }
-#endif /* defined(ISSUE_16789) */
+#endif /* defined(JIRA_ASTERISK_15594) */
 
                sig_pri_set_echocanceller(p, 1);
+               ast_channel_lock(chan);
                ast_setstate(chan, AST_STATE_RING);
+               ast_channel_unlock(chan);
                res = ast_pbx_run(chan);
                if (res) {
                        ast_log(LOG_WARNING, "PBX exited non-zero!\n");
@@ -2122,8 +2344,8 @@ static void sig_pri_redirecting_convert(struct ast_party_redirecting *ast_redire
        sig_pri_party_id_convert(&ast_redirecting->from, &pri_redirecting->from, pri);
        sig_pri_party_id_convert(&ast_redirecting->to, &pri_redirecting->to, pri);
        ast_redirecting->count = pri_redirecting->count;
-       ast_redirecting->reason = pri_to_ast_reason(pri_redirecting->reason);
-       ast_redirecting->orig_reason = pri_to_ast_reason(pri_redirecting->orig_reason);
+       ast_redirecting->reason.code = pri_to_ast_reason(pri_redirecting->reason);
+       ast_redirecting->orig_reason.code = pri_to_ast_reason(pri_redirecting->orig_reason);
 }
 
 /*!
@@ -2160,9 +2382,74 @@ static int sig_pri_msn_match(const char *msn_patterns, const char *exten)
 }
 
 #if defined(HAVE_PRI_MCID)
+static void party_number_json_to_ami(struct ast_str **msg, const char *prefix, struct ast_json *number)
+{
+       const char *num_txt, *pres_txt;
+       int plan, pres;
+       if (!number) {
+               ast_str_append(msg, 0,
+                       "%sNumValid: 0\r\n"
+                       "%sNum: \r\n"
+                       "%ston: 0\r\n",
+                       prefix, prefix, prefix);
+               return;
+       }
+
+       num_txt = ast_json_string_get(ast_json_object_get(number, "number"));
+       plan = ast_json_integer_get(ast_json_object_get(number, "plan"));
+       pres = ast_json_integer_get(ast_json_object_get(number, "presentation"));
+       pres_txt = ast_json_string_get(ast_json_object_get(number, "presentation_txt"));
+
+       ast_str_append(msg, 0, "%sNumValid: 1\r\n", prefix);
+       ast_str_append(msg, 0, "%sNum: %s\r\n", prefix, num_txt);
+       ast_str_append(msg, 0, "%ston: %d\r\n", prefix, plan);
+       ast_str_append(msg, 0, "%sNumPlan: %d\r\n", prefix, plan);
+       ast_str_append(msg, 0, "%sNumPres: %d (%s)\r\n", prefix, pres, pres_txt);
+}
+
+static void party_name_json_to_ami(struct ast_str **msg, const char *prefix, struct ast_json *name)
+{
+       const char *name_txt, *pres_txt, *charset;
+       int pres;
+       if (!name) {
+               ast_str_append(msg, 0,
+                       "%sNameValid: 0\r\n"
+                       "%sName: \r\n",
+                       prefix, prefix);
+               return;
+       }
+
+       name_txt = ast_json_string_get(ast_json_object_get(name, "name"));
+       charset = ast_json_string_get(ast_json_object_get(name, "character_set"));
+       pres = ast_json_integer_get(ast_json_object_get(name, "presentation"));
+       pres_txt = ast_json_string_get(ast_json_object_get(name, "presentation_txt"));
+
+       ast_str_append(msg, 0, "%sNameValid: 1\r\n", prefix);
+       ast_str_append(msg, 0, "%sName: %s\r\n", prefix, name_txt);
+       ast_str_append(msg, 0, "%sNameCharSet: %s\r\n", prefix, charset);
+       ast_str_append(msg, 0, "%sNamePres: %d (%s)\r\n", prefix, pres, pres_txt);
+}
+
+static void party_subaddress_json_to_ami(struct ast_str **msg, const char *prefix, struct ast_json *subaddress)
+{
+       const char *subaddress_txt, *type_txt;
+       int odd;
+       if (!subaddress) {
+               return;
+       }
+
+       subaddress_txt = ast_json_string_get(ast_json_object_get(subaddress, "subaddress"));
+       type_txt = ast_json_string_get(ast_json_object_get(subaddress, "type"));
+       odd = ast_json_is_true(ast_json_object_get(subaddress, "odd")) ? 1 : 0;
+
+       ast_str_append(msg, 0, "%sSubaddr: %s\r\n", prefix, subaddress_txt);
+       ast_str_append(msg, 0, "%sSubaddrType: %s\r\n", prefix, type_txt);
+       ast_str_append(msg, 0, "%sSubaddrOdd: %d\r\n", prefix, odd);
+}
+
 /*!
  * \internal
- * \brief Append the given party id to the event string.
+ * \brief Append the given JSON party id to the event string.
  * \since 1.8
  *
  * \param msg Event message string being built.
@@ -2171,58 +2458,72 @@ static int sig_pri_msn_match(const char *msn_patterns, const char *exten)
  *
  * \return Nothing
  */
-static void sig_pri_event_party_id(struct ast_str **msg, const char *prefix, struct ast_party_id *party)
+static void party_json_to_ami(struct ast_str **msg, const char *prefix, struct ast_json *party)
 {
-       int pres;
+       struct ast_json *presentation = ast_json_object_get(party, "presentation");
+       struct ast_json *presentation_txt = ast_json_object_get(party, "presentation_txt");
+       struct ast_json *name = ast_json_object_get(party, "name");
+       struct ast_json *number = ast_json_object_get(party, "number");
+       struct ast_json *subaddress = ast_json_object_get(party, "subaddress");
 
        /* Combined party presentation */
-       pres = ast_party_id_presentation(party);
-       ast_str_append(msg, 0, "%sPres: %d (%s)\r\n", prefix, pres,
-               ast_describe_caller_presentation(pres));
+       ast_str_append(msg, 0, "%sPres: %jd (%s)\r\n", prefix,
+               ast_json_integer_get(presentation),
+               ast_json_string_get(presentation_txt));
 
        /* Party number */
-       ast_str_append(msg, 0, "%sNumValid: %d\r\n", prefix,
-               (unsigned) party->number.valid);
-       ast_str_append(msg, 0, "%sNum: %s\r\n", prefix,
-               S_COR(party->number.valid, party->number.str, ""));
-       ast_str_append(msg, 0, "%ston: %d\r\n", prefix, party->number.plan);
-       if (party->number.valid) {
-               ast_str_append(msg, 0, "%sNumPlan: %d\r\n", prefix, party->number.plan);
-               ast_str_append(msg, 0, "%sNumPres: %d (%s)\r\n", prefix,
-                       party->number.presentation,
-                       ast_describe_caller_presentation(party->number.presentation));
-       }
+       party_number_json_to_ami(msg, prefix, number);
 
        /* Party name */
-       ast_str_append(msg, 0, "%sNameValid: %d\r\n", prefix,
-               (unsigned) party->name.valid);
-       ast_str_append(msg, 0, "%sName: %s\r\n", prefix,
-               S_COR(party->name.valid, party->name.str, ""));
-       if (party->name.valid) {
-               ast_str_append(msg, 0, "%sNameCharSet: %s\r\n", prefix,
-                       ast_party_name_charset_describe(party->name.char_set));
-               ast_str_append(msg, 0, "%sNamePres: %d (%s)\r\n", prefix,
-                       party->name.presentation,
-                       ast_describe_caller_presentation(party->name.presentation));
-       }
+       party_name_json_to_ami(msg, prefix, name);
 
-#if defined(HAVE_PRI_SUBADDR)
        /* Party subaddress */
-       if (party->subaddress.valid) {
-               static const char subaddress[] = "Subaddr";
+       party_subaddress_json_to_ami(msg, prefix, subaddress);
+}
+
+static struct ast_manager_event_blob *mcid_to_ami(struct stasis_message *msg)
+{
+       RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
+       RAII_VAR(struct ast_str *, party_string, ast_str_create(256), ast_free);
+       struct ast_channel_blob *obj = stasis_message_data(msg);
 
-               ast_str_append(msg, 0, "%s%s: %s\r\n", prefix, subaddress,
-                       S_OR(party->subaddress.str, ""));
-               ast_str_append(msg, 0, "%s%sType: %d\r\n", prefix, subaddress,
-                       party->subaddress.type);
-               ast_str_append(msg, 0, "%s%sOdd: %d\r\n", prefix, subaddress,
-                       party->subaddress.odd_even_indicator);
+       if (obj->snapshot) {
+               channel_string = ast_manager_build_channel_state_string(obj->snapshot);
+               if (!channel_string) {
+                       return NULL;
+               }
        }
-#endif /* defined(HAVE_PRI_SUBADDR) */
+
+       party_json_to_ami(&party_string, "MCallerID", ast_json_object_get(obj->blob, "caller"));
+       party_json_to_ami(&party_string, "MConnectedID", ast_json_object_get(obj->blob, "connected"));
+
+       return ast_manager_event_blob_create(EVENT_FLAG_CALL, "MCID",
+               "%s"
+               "%s",
+               S_COR(obj->snapshot, ast_str_buffer(channel_string), ""), ast_str_buffer(party_string));
+}
+
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(mcid_type,
+       .to_ami = mcid_to_ami,
+       );
+
+static void send_mcid(struct ast_channel *chan, struct ast_party_id *caller, struct ast_party_id *connected)
+{
+       RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+
+       ast_assert(caller != NULL);
+       ast_assert(connected != NULL);
+
+       blob = ast_json_pack("{s: o, s: o}",
+               "caller", ast_json_party_id(caller),
+               "connected", ast_json_party_id(connected));
+       if (!blob) {
+               return;
+       }
+
+       ast_channel_publish_blob(chan, mcid_type(), blob);
 }
-#endif /* defined(HAVE_PRI_MCID) */
 
-#if defined(HAVE_PRI_MCID)
 /*!
  * \internal
  * \brief Handle the MCID event.
@@ -2240,15 +2541,12 @@ static void sig_pri_event_party_id(struct ast_str **msg, const char *prefix, str
  */
 static void sig_pri_mcid_event(struct sig_pri_span *pri, const struct pri_subcmd_mcid_req *mcid, struct ast_channel *owner)
 {
-       struct ast_channel *chans[1];
-       struct ast_str *msg;
-       struct ast_party_id party;
-
-       msg = ast_str_create(4096);
-       if (!msg) {
-               return;
-       }
+       struct ast_party_id caller_party;
+       struct ast_party_id connected_party;
 
+       /* Always use libpri's called party information. */
+       ast_party_id_init(&connected_party);
+       sig_pri_party_id_convert(&connected_party, &mcid->answerer, pri);
        if (owner) {
                /*
                 * The owner channel is present.
@@ -2256,31 +2554,18 @@ static void sig_pri_mcid_event(struct sig_pri_span *pri, const struct pri_subcmd
                 */
                ast_queue_control(owner, AST_CONTROL_MCID);
 
-               ast_str_append(&msg, 0, "Channel: %s\r\n", ast_channel_name(owner));
-               ast_str_append(&msg, 0, "UniqueID: %s\r\n", ast_channel_uniqueid(owner));
-
-               sig_pri_event_party_id(&msg, "CallerID", &ast_channel_connected(owner)->id);
+               send_mcid(owner, &ast_channel_connected(owner)->id, &connected_party);
        } else {
                /*
                 * Since we no longer have an owner channel,
                 * we have to use the caller information supplied by libpri.
                 */
-               ast_party_id_init(&party);
-               sig_pri_party_id_convert(&party, &mcid->originator, pri);
-               sig_pri_event_party_id(&msg, "CallerID", &party);
-               ast_party_id_free(&party);
+               ast_party_id_init(&caller_party);
+               sig_pri_party_id_convert(&caller_party, &mcid->originator, pri);
+               send_mcid(owner, &caller_party, &connected_party);
+               ast_party_id_free(&caller_party);
        }
-
-       /* Always use libpri's called party information. */
-       ast_party_id_init(&party);
-       sig_pri_party_id_convert(&party, &mcid->answerer, pri);
-       sig_pri_event_party_id(&msg, "ConnectedID", &party);
-       ast_party_id_free(&party);
-
-       chans[0] = owner;
-       ast_manager_event_multichan(EVENT_FLAG_CALL, "MCID", owner ? 1 : 0, chans, "%s",
-               ast_str_buffer(msg));
-       ast_free(msg);
+       ast_party_id_free(&connected_party);
 }
 #endif /* defined(HAVE_PRI_MCID) */
 
@@ -2291,6 +2576,8 @@ struct xfer_rsp_data {
        q931_call *call;
        /*! Invocation ID to use when sending a reply to the transfer request. */
        int invoke_id;
+       /*! TRUE if the transfer response has been made. */
+       int responded;
 };
 #endif /* defined(HAVE_PRI_TRANSFER) */
 
@@ -2300,14 +2587,19 @@ struct xfer_rsp_data {
  * \brief Send the transfer success/fail response message.
  * \since 1.8
  *
- * \param data Callback user data pointer
+ * \param rsp Transfer response data.
  * \param is_successful TRUE if the transfer was successful.
  *
+ * \note Assumes the rsp->pri->lock is already obtained.
+ *
  * \return Nothing
  */
-static void sig_pri_transfer_rsp(void *data, int is_successful)
+static void sig_pri_transfer_rsp(struct xfer_rsp_data *rsp, int is_successful)
 {
-       struct xfer_rsp_data *rsp = data;
+       if (rsp->responded) {
+               return;
+       }
+       rsp->responded = 1;
 
        pri_transfer_rsp(rsp->pri->pri, rsp->call, rsp->invoke_id, is_successful);
 }
@@ -2315,19 +2607,6 @@ static void sig_pri_transfer_rsp(void *data, int is_successful)
 
 #if defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER)
 /*!
- * \brief Protocol callback to indicate if transfer will happen.
- * \since 1.8
- *
- * \param data Callback user data pointer
- * \param is_successful TRUE if the transfer will happen.
- *
- * \return Nothing
- */
-typedef void (*xfer_rsp_callback)(void *data, int is_successful);
-#endif /* defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER) */
-
-#if defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER)
-/*!
  * \internal
  * \brief Attempt to transfer the two calls to each other.
  * \since 1.8
@@ -2337,15 +2616,14 @@ typedef void (*xfer_rsp_callback)(void *data, int is_successful);
  * \param call_1_held TRUE if call_1_pri is on hold.
  * \param call_2_pri Second call involved in the transfer. (target; usually active/ringing)
  * \param call_2_held TRUE if call_2_pri is on hold.
- * \param rsp_callback Protocol callback to indicate if transfer will happen. NULL if not used.
- * \param data Callback user data pointer
+ * \param xfer_data Transfer response data if non-NULL.
  *
  * \note Assumes the pri->lock is already obtained.
  *
  * \retval 0 on success.
  * \retval -1 on error.
  */
-static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_pri, int call_1_held, q931_call *call_2_pri, int call_2_held, xfer_rsp_callback rsp_callback, void *data)
+static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_pri, int call_1_held, q931_call *call_2_pri, int call_2_held, struct xfer_rsp_data *xfer_data)
 {
        struct attempt_xfer_call {
                q931_call *pri;
@@ -2354,10 +2632,9 @@ static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_
                int chanpos;
        };
        int retval;
-       struct ast_channel *transferee;
+       enum ast_transfer_result xfer_res;
        struct attempt_xfer_call *call_1;
        struct attempt_xfer_call *call_2;
-       struct attempt_xfer_call *swap_call;
        struct attempt_xfer_call c1;
        struct attempt_xfer_call c2;
 
@@ -2373,118 +2650,104 @@ static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_
        call_2->chanpos = pri_find_principle_by_call(pri, call_2->pri);
        if (call_1->chanpos < 0 || call_2->chanpos < 0) {
                /* Calls not found in span control. */
-               if (rsp_callback) {
+#if defined(HAVE_PRI_TRANSFER)
+               if (xfer_data) {
                        /* Transfer failed. */
-                       rsp_callback(data, 0);
+                       sig_pri_transfer_rsp(xfer_data, 0);
                }
+#endif /* defined(HAVE_PRI_TRANSFER) */
                return -1;
        }
 
-       /* Attempt to make transferee and target consistent. */
-       if (!call_1->held && call_2->held) {
-               /*
-                * Swap call_1 and call_2 to make call_1 the transferee(held call)
-                * and call_2 the target(active call).
-                */
-               swap_call = call_1;
-               call_1 = call_2;
-               call_2 = swap_call;
-       }
-
-       /* Deadlock avoidance is attempted. */
+       /* Get call_1 owner. */
        sig_pri_lock_private(pri->pvts[call_1->chanpos]);
        sig_pri_lock_owner(pri, call_1->chanpos);
+       call_1->ast = pri->pvts[call_1->chanpos]->owner;
+       if (call_1->ast) {
+               ast_channel_ref(call_1->ast);
+               ast_channel_unlock(call_1->ast);
+       }
+       sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
+
+       /* Get call_2 owner. */
        sig_pri_lock_private(pri->pvts[call_2->chanpos]);
        sig_pri_lock_owner(pri, call_2->chanpos);
-
-       call_1->ast = pri->pvts[call_1->chanpos]->owner;
        call_2->ast = pri->pvts[call_2->chanpos]->owner;
+       if (call_2->ast) {
+               ast_channel_ref(call_2->ast);
+               ast_channel_unlock(call_2->ast);
+       }
+       sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
+
        if (!call_1->ast || !call_2->ast) {
                /* At least one owner is not present. */
                if (call_1->ast) {
-                       ast_channel_unlock(call_1->ast);
+                       ast_channel_unref(call_1->ast);
                }
                if (call_2->ast) {
-                       ast_channel_unlock(call_2->ast);
+                       ast_channel_unref(call_2->ast);
                }
-               sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
-               sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
-               if (rsp_callback) {
+#if defined(HAVE_PRI_TRANSFER)
+               if (xfer_data) {
                        /* Transfer failed. */
-                       rsp_callback(data, 0);
+                       sig_pri_transfer_rsp(xfer_data, 0);
                }
+#endif /* defined(HAVE_PRI_TRANSFER) */
                return -1;
        }
 
-       for (;;) {
-               transferee = ast_bridged_channel(call_1->ast);
-               if (transferee) {
-                       break;
-               }
-
-               /* Try masquerading the other way. */
-               swap_call = call_1;
-               call_1 = call_2;
-               call_2 = swap_call;
-
-               transferee = ast_bridged_channel(call_1->ast);
-               if (transferee) {
-                       break;
-               }
+       ast_verb(3, "TRANSFERRING %s to %s\n",
+               ast_channel_name(call_1->ast), ast_channel_name(call_2->ast));
 
-               /* Could not transfer.  Neither call is bridged. */
-               ast_channel_unlock(call_1->ast);
-               ast_channel_unlock(call_2->ast);
+#if defined(HAVE_PRI_TRANSFER)
+       if (xfer_data) {
+               /*
+                * Add traps on the transferer channels in case threading causes
+                * them to hangup before ast_bridge_transfer_attended() returns
+                * and we can get the pri->lock back.
+                */
+               sig_pri_lock_private(pri->pvts[call_1->chanpos]);
+               pri->pvts[call_1->chanpos]->xfer_data = xfer_data;
                sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
+               sig_pri_lock_private(pri->pvts[call_2->chanpos]);
+               pri->pvts[call_2->chanpos]->xfer_data = xfer_data;
                sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
-
-               if (rsp_callback) {
-                       /* Transfer failed. */
-                       rsp_callback(data, 0);
-               }
-               return -1;
        }
+#endif /* defined(HAVE_PRI_TRANSFER) */
 
-       ast_verb(3, "TRANSFERRING %s to %s\n", ast_channel_name(call_1->ast), ast_channel_name(call_2->ast));
-
-       /*
-        * Setup transfer masquerade.
-        *
-        * Note:  There is an extremely nasty deadlock avoidance issue
-        * with ast_channel_transfer_masquerade().  Deadlock may be possible if
-        * the channels involved are proxies (chan_agent channels) and
-        * it is called with locks.  Unfortunately, there is no simple
-        * or even merely difficult way to guarantee deadlock avoidance
-        * and still be able to send an ECT success response without the
-        * possibility of the bridged channel hanging up on us.
-        */
        ast_mutex_unlock(&pri->lock);
-       retval = ast_channel_transfer_masquerade(
-               call_2->ast,
-               ast_channel_connected(call_2->ast),
-               call_2->held,
-               transferee,
-               ast_channel_connected(call_1->ast),
-               call_1->held);
-
-       /* Reacquire the pri->lock to hold off completion of the transfer masquerade. */
+       xfer_res = ast_bridge_transfer_attended(call_1->ast, call_2->ast);
        ast_mutex_lock(&pri->lock);
+       retval = (xfer_res != AST_BRIDGE_TRANSFER_SUCCESS) ? -1 : 0;
 
-       ast_channel_unlock(call_1->ast);
-       ast_channel_unlock(call_2->ast);
-       sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
-       sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
+#if defined(HAVE_PRI_TRANSFER)
+       if (xfer_data) {
+               int rsp_chanpos;
 
-       if (rsp_callback) {
                /*
-                * Report transfer status.
+                * Remove the transferrer channel traps.
                 *
-                * Must do the callback before the masquerade completes to ensure
-                * that the protocol message goes out before the call leg is
-                * disconnected.
+                * We must refind chanpos because we released pri->lock.
                 */
-               rsp_callback(data, retval ? 0 : 1);
+               rsp_chanpos = pri_find_principle_by_call(pri, call_1->pri);
+               if (0 <= rsp_chanpos) {
+                       sig_pri_lock_private(pri->pvts[rsp_chanpos]);
+                       pri->pvts[rsp_chanpos]->xfer_data = NULL;
+                       sig_pri_unlock_private(pri->pvts[rsp_chanpos]);
+               }
+               rsp_chanpos = pri_find_principle_by_call(pri, call_2->pri);
+               if (0 <= rsp_chanpos) {
+                       sig_pri_lock_private(pri->pvts[rsp_chanpos]);
+                       pri->pvts[rsp_chanpos]->xfer_data = NULL;
+                       sig_pri_unlock_private(pri->pvts[rsp_chanpos]);
+               }
+
+               /* Report transfer status. */
+               sig_pri_transfer_rsp(xfer_data, retval ? 0 : 1);
        }
+#endif /* defined(HAVE_PRI_TRANSFER) */
+       ast_channel_unref(call_1->ast);
+       ast_channel_unref(call_2->ast);
        return retval;
 }
 #endif /* defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER) */
@@ -2610,7 +2873,7 @@ static void sig_pri_cc_monitor_instance_destroy(void *data)
                pri_cc_cancel(monitor_instance->pri->pri, monitor_instance->cc_id);
                ast_mutex_unlock(&monitor_instance->pri->lock);
        }
-       monitor_instance->pri->calls->module_unref();
+       sig_pri_callbacks.module_unref();
 }
 #endif /* defined(HAVE_PRI_CCSS) */
 
@@ -2637,7 +2900,7 @@ static struct sig_pri_cc_monitor_instance *sig_pri_cc_monitor_instance_init(int
 {
        struct sig_pri_cc_monitor_instance *monitor_instance;
 
-       if (!pri->calls->module_ref || !pri->calls->module_unref) {
+       if (!sig_pri_callbacks.module_ref || !sig_pri_callbacks.module_unref) {
                return NULL;
        }
 
@@ -2652,7 +2915,7 @@ static struct sig_pri_cc_monitor_instance *sig_pri_cc_monitor_instance_init(int
        monitor_instance->core_id = core_id;
        strcpy(monitor_instance->name, device_name);
 
-       pri->calls->module_ref();
+       sig_pri_callbacks.module_ref();
 
        ao2_link(sig_pri_cc_monitors, monitor_instance);
        return monitor_instance;
@@ -3787,14 +4050,14 @@ static void sig_pri_send_aoce_termination_request(struct sig_pri_span *pri, int
        }
 
        if (!(decoded = ast_aoc_create(AST_AOC_REQUEST, 0, AST_AOC_REQUEST_E))) {
-               ast_softhangup_nolock(pvt->owner, AST_SOFTHANGUP_DEV);
+               ast_queue_hangup(pvt->owner);
                goto cleanup_termination_request;
        }
 
        ast_aoc_set_termination_request(decoded);
 
        if (!(encoded = ast_aoc_encode(decoded, &encoded_size, pvt->owner))) {
-               ast_softhangup_nolock(pvt->owner, AST_SOFTHANGUP_DEV);
+               ast_queue_hangup(pvt->owner);
                goto cleanup_termination_request;
        }
 
@@ -3803,7 +4066,7 @@ static void sig_pri_send_aoce_termination_request(struct sig_pri_span *pri, int
        whentohangup.tv_sec = ms / 1000;
 
        if (ast_queue_control_data(pvt->owner, AST_CONTROL_AOC, encoded, encoded_size)) {
-               ast_softhangup_nolock(pvt->owner, AST_SOFTHANGUP_DEV);
+               ast_queue_hangup(pvt->owner);
                goto cleanup_termination_request;
        }
 
@@ -4047,61 +4310,24 @@ static void sig_pri_handle_cis_subcmds(struct sig_pri_span *pri, int event_id,
        }
 }
 
-#if defined(HAVE_PRI_AOC_EVENTS)
 /*!
  * \internal
- * \brief detect if AOC-S subcmd is present.
+ * \brief Handle the call associated PRI subcommand events.
  * \since 1.8
  *
+ * \param pri PRI span control structure.
+ * \param chanpos Channel position in the span.
+ * \param event_id PRI event id
  * \param subcmds Subcommands to process if any. (Could be NULL).
+ * \param call_rsp libpri opaque call structure to send any responses toward.
+ * Could be NULL either because it is not available or the call is for the
+ * dummy call reference.  However, this should not be NULL in the cases that
+ * need to use the pointer to send a response message back.
  *
- * \note Knowing whether or not an AOC-E subcmd is present on certain
- * PRI hangup events is necessary to determine what method to use to hangup
- * the ast_channel.  If an AOC-E subcmd just came in, then a new AOC-E was queued
- * on the ast_channel.  If a soft hangup is used, the AOC-E msg will never make it
- * across the bridge, but if a AST_CONTROL_HANGUP frame is queued behind it
- * we can ensure the AOC-E frame makes it to it's destination before the hangup
- * frame is read.
- *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
  *
- * \retval 0 AOC-E is not present in subcmd list
- * \retval 1 AOC-E is present in subcmd list
- */
-static int detect_aoc_e_subcmd(const struct pri_subcommands *subcmds)
-{
-       int i;
-
-       if (!subcmds) {
-               return 0;
-       }
-       for (i = 0; i < subcmds->counter_subcmd; ++i) {
-               const struct pri_subcommand *subcmd = &subcmds->subcmd[i];
-               if (subcmd->cmd == PRI_SUBCMD_AOC_E) {
-                       return 1;
-               }
-       }
-       return 0;
-}
-#endif /* defined(HAVE_PRI_AOC_EVENTS) */
-
-/*!
- * \internal
- * \brief Handle the call associated PRI subcommand events.
- * \since 1.8
- *
- * \param pri PRI span control structure.
- * \param chanpos Channel position in the span.
- * \param event_id PRI event id
- * \param subcmds Subcommands to process if any. (Could be NULL).
- * \param call_rsp libpri opaque call structure to send any responses toward.
- * Could be NULL either because it is not available or the call is for the
- * dummy call reference.  However, this should not be NULL in the cases that
- * need to use the pointer to send a response message back.
- *
- * \note Assumes the pri->lock is already obtained.
- * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
- *
- * \return Nothing
+ * \return Nothing
  */
 static void sig_pri_handle_subcmds(struct sig_pri_span *pri, int chanpos, int event_id,
        const struct pri_subcommands *subcmds, q931_call *call_rsp)
@@ -4151,14 +4377,11 @@ static void sig_pri_handle_subcmds(struct sig_pri_span *pri, int chanpos, int ev
 
                                pri->pvts[chanpos]->cid_subaddr[0] = '\0';
 #if defined(HAVE_PRI_SUBADDR)
-                               if (ast_connected.id.subaddress.valid) {
-                                       ast_party_subaddress_set(&ast_channel_caller(owner)->id.subaddress,
-                                               &ast_connected.id.subaddress);
-                                       if (ast_connected.id.subaddress.str) {
-                                               ast_copy_string(pri->pvts[chanpos]->cid_subaddr,
-                                                       ast_connected.id.subaddress.str,
-                                                       sizeof(pri->pvts[chanpos]->cid_subaddr));
-                                       }
+                               if (ast_connected.id.subaddress.str) {
+                                       ast_copy_string(pri->pvts[chanpos]->cid_subaddr,
+                                               ast_connected.id.subaddress.str,
+                                               sizeof(pri->pvts[chanpos]->cid_subaddr));
+                                       caller_id_update = 1;
                                }
 #endif /* defined(HAVE_PRI_SUBADDR) */
                                if (caller_id_update) {
@@ -4172,12 +4395,13 @@ static void sig_pri_handle_subcmds(struct sig_pri_span *pri, int chanpos, int ev
                                        ast_caller.id = ast_connected.id;
                                        ast_caller.ani = ast_connected.id;
                                        ast_channel_set_caller_event(owner, &ast_caller, NULL);
-                               }
 
-                               /* Update the connected line information on the other channel */
-                               if (event_id != PRI_EVENT_RING) {
-                                       /* This connected_line update was not from a SETUP message. */
-                                       ast_channel_queue_connected_line_update(owner, &ast_connected, NULL);
+                                       /* Update the connected line information on the other channel */
+                                       if (event_id != PRI_EVENT_RING) {
+                                               /* This connected_line update was not from a SETUP message. */
+                                               ast_channel_queue_connected_line_update(owner, &ast_connected,
+                                                       NULL);
+                                       }
                                }
 
                                ast_party_connected_line_free(&ast_connected);
@@ -4196,6 +4420,12 @@ static void sig_pri_handle_subcmds(struct sig_pri_span *pri, int chanpos, int ev
                                ast_channel_set_redirecting(owner, &ast_redirecting, NULL);
                                if (event_id != PRI_EVENT_RING) {
                                        /* This redirection was not from a SETUP message. */
+
+                                       /* Invalidate any earlier private redirecting id representations */
+                                       ast_party_id_invalidate(&ast_redirecting.priv_orig);
+                                       ast_party_id_invalidate(&ast_redirecting.priv_from);
+                                       ast_party_id_invalidate(&ast_redirecting.priv_to);
+
                                        ast_channel_queue_redirecting_update(owner, &ast_redirecting, NULL);
                                }
                                ast_party_redirecting_free(&ast_redirecting);
@@ -4346,10 +4576,11 @@ static void sig_pri_handle_subcmds(struct sig_pri_span *pri, int chanpos, int ev
                        xfer_rsp.pri = pri;
                        xfer_rsp.call = call_rsp;
                        xfer_rsp.invoke_id = subcmd->u.transfer.invoke_id;
+                       xfer_rsp.responded = 0;
                        sig_pri_attempt_transfer(pri,
                                subcmd->u.transfer.call_1, subcmd->u.transfer.is_call_1_held,
                                subcmd->u.transfer.call_2, subcmd->u.transfer.is_call_2_held,
-                               sig_pri_transfer_rsp, &xfer_rsp);
+                               &xfer_rsp);
                        sig_pri_lock_private(pri->pvts[chanpos]);
                        break;
 #endif /* defined(HAVE_PRI_TRANSFER) */
@@ -4449,7 +4680,7 @@ static void sig_pri_handle_subcmds(struct sig_pri_span *pri, int chanpos, int ev
                                        f.frametype = AST_FRAME_TEXT;
                                        f.subclass.integer = 0;
                                        f.offset = 0;
-                                       f.data.ptr = &subcmd->u.display.text;
+                                       f.data.ptr = (void *)&subcmd->u.display.text;
                                        f.datalen = subcmd->u.display.length + 1;
                                        ast_queue_frame(owner, &f);
                                        ast_channel_unlock(owner);
@@ -4571,7 +4802,7 @@ static const char *sig_pri_moh_event_str(enum sig_pri_moh_event event)
  * \since 10.0
  *
  * \param pvt Channel private control structure.
- * 
+ *
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -4615,7 +4846,7 @@ static enum sig_pri_moh_state sig_pri_moh_retrieve_call(struct sig_pri_chan *pvt
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- * 
+ *
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -4679,7 +4910,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_idle(struct ast_channel *chan, str
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- * 
+ *
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -4691,6 +4922,12 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_notify(struct ast_channel *chan, s
 
        next_state = pvt->moh_state;
        switch (event) {
+       case SIG_PRI_MOH_EVENT_HOLD:
+               if (strcasecmp(pvt->mohinterpret, "passthrough")) {
+                       /* Restart MOH in case it was stopped by other means. */
+                       ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
+               }
+               break;
        case SIG_PRI_MOH_EVENT_UNHOLD:
                pri_notify(pvt->pri->pri, pvt->call, pvt->prioffset, PRI_NOTIFY_REMOTE_RETRIEVAL);
                /* Fall through */
@@ -4713,7 +4950,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_notify(struct ast_channel *chan, s
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- * 
+ *
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -4725,6 +4962,10 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_moh(struct ast_channel *chan, stru
 
        next_state = pvt->moh_state;
        switch (event) {
+       case SIG_PRI_MOH_EVENT_HOLD:
+               /* Restart MOH in case it was stopped by other means. */
+               ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
+               break;
        case SIG_PRI_MOH_EVENT_RESET:
        case SIG_PRI_MOH_EVENT_UNHOLD:
                ast_moh_stop(chan);
@@ -4746,7 +4987,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_moh(struct ast_channel *chan, stru
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- * 
+ *
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -4791,7 +5032,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_hold_req(struct ast_channel *chan,
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- * 
+ *
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -4832,7 +5073,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_pend_unhold(struct ast_channel *ch
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- * 
+ *
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -4874,7 +5115,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_hold(struct ast_channel *chan, str
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- * 
+ *
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -4916,7 +5157,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_retrieve_req(struct ast_channel *c
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- * 
+ *
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -4994,7 +5235,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_pend_hold(struct ast_channel *chan
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- * 
+ *
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -5034,7 +5275,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_retrieve_fail(struct ast_channel *
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- * 
+ *
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -5067,7 +5308,7 @@ static const sig_pri_moh_fsm_state sig_pri_moh_fsm[SIG_PRI_MOH_STATE_NUM] = {
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- * 
+ *
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -5090,7 +5331,7 @@ static void sig_pri_moh_fsm_event(struct ast_channel *chan, struct sig_pri_chan
        if (orig_state < SIG_PRI_MOH_STATE_IDLE || SIG_PRI_MOH_STATE_NUM <= orig_state
                || !sig_pri_moh_fsm[orig_state]) {
                /* Programming error: State not implemented. */
-               ast_log(LOG_ERROR, "MOH state not implemented: %s(%d)\n",
+               ast_log(LOG_ERROR, "MOH state not implemented: %s(%u)\n",
                        sig_pri_moh_state_str(orig_state), orig_state);
                return;
        }
@@ -5100,28 +5341,56 @@ static void sig_pri_moh_fsm_event(struct ast_channel *chan, struct sig_pri_chan
                (orig_state == next_state) ? "$" : sig_pri_moh_state_str(next_state));
 }
 
-#if defined(HAVE_PRI_CALL_HOLD)
 /*!
  * \internal
- * \brief Post an AMI hold event.
- * \since 10.0
+ * \brief Set callid threadstorage for the pri_dchannel thread when a new call is created
+ *
+ * \return A new callid which has been bound to threadstorage. The threadstorage
+ *         should be unbound when the pri_dchannel primary loop wraps.
+ */
+static ast_callid func_pri_dchannel_new_callid(void)
+{
+       ast_callid callid = ast_create_callid();
+
+       if (callid) {
+               ast_callid_threadassoc_add(callid);
+       }
+
+       return callid;
+}
+
+/*!
+ * \internal
+ * \brief Set callid threadstorage for the pri_dchannel thread to that of an existing channel
  *
- * \param chan Channel to post event to
- * \param is_held TRUE if the call was placed on hold.
+ * \param pri PRI span control structure.
+ * \param chanpos channel position in the span
  *
- * \return Nothing
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
+ *
+ * \return The callid which has also been bound to threadstorage if it exists.
+ *         The threadstorage should be unbound when the pri_dchannel primary loop wraps.
  */
-static void sig_pri_ami_hold_event(struct ast_channel *chan, int is_held)
+static ast_callid func_pri_dchannel_chanpos_callid(struct sig_pri_span *pri, int chanpos)
 {
-       ast_manager_event(chan, EVENT_FLAG_CALL, "Hold",
-               "Status: %s\r\n"
-               "Channel: %s\r\n"
-               "Uniqueid: %s\r\n",
-               is_held ? "On" : "Off",
-               ast_channel_name(chan),
-               ast_channel_uniqueid(chan));
+       if (chanpos < 0) {
+               return 0;
+       }
+
+       sig_pri_lock_owner(pri, chanpos);
+       if (pri->pvts[chanpos]->owner) {
+               ast_callid callid;
+               callid = ast_channel_callid(pri->pvts[chanpos]->owner);
+               ast_channel_unlock(pri->pvts[chanpos]->owner);
+               if (callid) {
+                       ast_callid_threadassoc_add(callid);
+                       return callid;
+               }
+       }
+
+       return 0;
 }
-#endif /* defined(HAVE_PRI_CALL_HOLD) */
 
 #if defined(HAVE_PRI_CALL_HOLD)
 /*!
@@ -5143,6 +5412,7 @@ static int sig_pri_handle_hold(struct sig_pri_span *pri, pri_event *ev)
        int chanpos_old;
        int chanpos_new;
        struct ast_channel *owner;
+       ast_callid callid = 0;
 
        chanpos_old = pri_find_principle_by_call(pri, ev->hold.call);
        if (chanpos_old < 0) {
@@ -5162,6 +5432,13 @@ static int sig_pri_handle_hold(struct sig_pri_span *pri, pri_event *ev)
        if (!owner) {
                goto done_with_private;
        }
+
+       callid = ast_channel_callid(owner);
+
+       if (callid) {
+               ast_callid_threadassoc_add(callid);
+       }
+
        if (pri->pvts[chanpos_old]->call_level != SIG_PRI_CALL_LEVEL_CONNECT) {
                /*
                 * Make things simple.  Don't allow placing a call on hold that
@@ -5175,13 +5452,11 @@ static int sig_pri_handle_hold(struct sig_pri_span *pri, pri_event *ev)
                goto done_with_owner;
        }
        sig_pri_handle_subcmds(pri, chanpos_old, ev->e, ev->hold.subcmds, ev->hold.call);
-       pri_queue_control(pri, chanpos_old, AST_CONTROL_HOLD);
+       sig_pri_queue_hold(pri, chanpos_old);
        chanpos_new = pri_fixup_principle(pri, chanpos_new, ev->hold.call);
        if (chanpos_new < 0) {
                /* Should never happen. */
-               pri_queue_control(pri, chanpos_old, AST_CONTROL_UNHOLD);
-       } else {
-               sig_pri_ami_hold_event(owner, 1);
+               sig_pri_queue_unhold(pri, chanpos_old);
        }
 
 done_with_owner:;
@@ -5196,6 +5471,10 @@ done_with_private:;
                retval = 0;
        }
 
+       if (callid) {
+               ast_callid_threadassoc_remove();
+       }
+
        return retval;
 }
 #endif /* defined(HAVE_PRI_CALL_HOLD) */
@@ -5216,6 +5495,7 @@ done_with_private:;
 static void sig_pri_handle_hold_ack(struct sig_pri_span *pri, pri_event *ev)
 {
        int chanpos;
+       ast_callid callid;
 
        /*
         * We were successfully put on hold by the remote party
@@ -5238,11 +5518,17 @@ static void sig_pri_handle_hold_ack(struct sig_pri_span *pri, pri_event *ev)
        }
 
        sig_pri_lock_private(pri->pvts[chanpos]);
+       callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
        sig_pri_handle_subcmds(pri, chanpos, ev->e, ev->hold_ack.subcmds, ev->hold_ack.call);
        sig_pri_moh_fsm_event(pri->pvts[chanpos]->owner, pri->pvts[chanpos],
                SIG_PRI_MOH_EVENT_HOLD_ACK);
        sig_pri_unlock_private(pri->pvts[chanpos]);
        sig_pri_span_devstate_changed(pri);
+
+       if (callid) {
+               ast_callid_threadassoc_remove();
+       }
 }
 #endif /* defined(HAVE_PRI_CALL_HOLD) */
 
@@ -5262,6 +5548,7 @@ static void sig_pri_handle_hold_ack(struct sig_pri_span *pri, pri_event *ev)
 static void sig_pri_handle_hold_rej(struct sig_pri_span *pri, pri_event *ev)
 {
        int chanpos;
+       ast_callid callid;
 
        chanpos = pri_find_principle(pri, ev->hold_rej.channel, ev->hold_rej.call);
        if (chanpos < 0) {
@@ -5281,10 +5568,16 @@ static void sig_pri_handle_hold_rej(struct sig_pri_span *pri, pri_event *ev)
                ev->hold_rej.cause, pri_cause2str(ev->hold_rej.cause));
 
        sig_pri_lock_private(pri->pvts[chanpos]);
+       callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
        sig_pri_handle_subcmds(pri, chanpos, ev->e, ev->hold_rej.subcmds, ev->hold_rej.call);
        sig_pri_moh_fsm_event(pri->pvts[chanpos]->owner, pri->pvts[chanpos],
                SIG_PRI_MOH_EVENT_HOLD_REJ);
        sig_pri_unlock_private(pri->pvts[chanpos]);
+
+       if (callid) {
+               ast_callid_threadassoc_remove();
+       }
 }
 #endif /* defined(HAVE_PRI_CALL_HOLD) */
 
@@ -5304,6 +5597,7 @@ static void sig_pri_handle_hold_rej(struct sig_pri_span *pri, pri_event *ev)
 static void sig_pri_handle_retrieve(struct sig_pri_span *pri, pri_event *ev)
 {
        int chanpos;
+       ast_callid callid;
 
        if (!(ev->retrieve.channel & PRI_HELD_CALL)) {
                /* The call is not currently held. */
@@ -5345,19 +5639,19 @@ static void sig_pri_handle_retrieve(struct sig_pri_span *pri, pri_event *ev)
                return;
        }
        sig_pri_lock_private(pri->pvts[chanpos]);
+       callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
        sig_pri_handle_subcmds(pri, chanpos, ev->e, ev->retrieve.subcmds, ev->retrieve.call);
-       sig_pri_lock_owner(pri, chanpos);
-       pri_queue_control(pri, chanpos, AST_CONTROL_UNHOLD);
-       if (pri->pvts[chanpos]->owner) {
-               sig_pri_ami_hold_event(pri->pvts[chanpos]->owner, 0);
-               ast_channel_unlock(pri->pvts[chanpos]->owner);
-       }
+       sig_pri_queue_unhold(pri, chanpos);
        pri_retrieve_ack(pri->pri, ev->retrieve.call,
                PVT_TO_CHANNEL(pri->pvts[chanpos]));
        sig_pri_moh_fsm_event(pri->pvts[chanpos]->owner, pri->pvts[chanpos],
                SIG_PRI_MOH_EVENT_REMOTE_RETRIEVE_ACK);
        sig_pri_unlock_private(pri->pvts[chanpos]);
        sig_pri_span_devstate_changed(pri);
+
+       if (callid) {
+               ast_callid_threadassoc_remove();
+       }
 }
 #endif /* defined(HAVE_PRI_CALL_HOLD) */
 
@@ -5377,6 +5671,7 @@ static void sig_pri_handle_retrieve(struct sig_pri_span *pri, pri_event *ev)
 static void sig_pri_handle_retrieve_ack(struct sig_pri_span *pri, pri_event *ev)
 {
        int chanpos;
+       ast_callid callid;
 
        chanpos = pri_find_fixup_principle(pri, ev->retrieve_ack.channel,
                ev->retrieve_ack.call);
@@ -5385,12 +5680,18 @@ static void sig_pri_handle_retrieve_ack(struct sig_pri_span *pri, pri_event *ev)
        }
 
        sig_pri_lock_private(pri->pvts[chanpos]);
+       callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
        sig_pri_handle_subcmds(pri, chanpos, ev->e, ev->retrieve_ack.subcmds,
                ev->retrieve_ack.call);
        sig_pri_moh_fsm_event(pri->pvts[chanpos]->owner, pri->pvts[chanpos],
                SIG_PRI_MOH_EVENT_RETRIEVE_ACK);
        sig_pri_unlock_private(pri->pvts[chanpos]);
        sig_pri_span_devstate_changed(pri);
+
+       if (callid) {
+               ast_callid_threadassoc_remove();
+       }
 }
 #endif /* defined(HAVE_PRI_CALL_HOLD) */
 
@@ -5410,6 +5711,7 @@ static void sig_pri_handle_retrieve_ack(struct sig_pri_span *pri, pri_event *ev)
 static void sig_pri_handle_retrieve_rej(struct sig_pri_span *pri, pri_event *ev)
 {
        int chanpos;
+       ast_callid callid;
 
        chanpos = pri_find_principle(pri, ev->retrieve_rej.channel, ev->retrieve_rej.call);
        if (chanpos < 0) {
@@ -5429,35 +5731,505 @@ static void sig_pri_handle_retrieve_rej(struct sig_pri_span *pri, pri_event *ev)
                ev->retrieve_rej.cause, pri_cause2str(ev->retrieve_rej.cause));
 
        sig_pri_lock_private(pri->pvts[chanpos]);
+       callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
        sig_pri_handle_subcmds(pri, chanpos, ev->e, ev->retrieve_rej.subcmds,
                ev->retrieve_rej.call);
        sig_pri_moh_fsm_event(pri->pvts[chanpos]->owner, pri->pvts[chanpos],
                SIG_PRI_MOH_EVENT_RETRIEVE_REJ);
        sig_pri_unlock_private(pri->pvts[chanpos]);
+
+       if (callid) {
+               ast_callid_threadassoc_remove();
+       }
 }
 #endif /* defined(HAVE_PRI_CALL_HOLD) */
 
+/*!
+ * \internal
+ * \brief Setup channel variables on the owner.
+ *
+ * \param pri PRI span control structure.
+ * \param chanpos Channel position in the span.
+ * \param ev SETUP event received.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
+ *
+ * \return Nothing
+ */
+static void setup_incoming_channel(struct sig_pri_span *pri, int chanpos, pri_event *ev)
+{
+       struct ast_channel *owner;
+       char ani2str[6];
+       char calledtonstr[10];
+
+       sig_pri_lock_owner(pri, chanpos);
+       owner = pri->pvts[chanpos]->owner;
+       if (!owner) {
+               return;
+       }
+
+       ast_channel_stage_snapshot(owner);
+
+#if defined(HAVE_PRI_SUBADDR)
+       if (ev->ring.calling.subaddress.valid) {
+               /* Set Calling Subaddress */
+               sig_pri_set_subaddress(&ast_channel_caller(owner)->id.subaddress,
+                       &ev->ring.calling.subaddress);
+               if (!ev->ring.calling.subaddress.type
+                       && !ast_strlen_zero((char *) ev->ring.calling.subaddress.data)) {
+                       /* NSAP */
+                       pbx_builtin_setvar_helper(owner, "CALLINGSUBADDR",
+                               (char *) ev->ring.calling.subaddress.data);
+               }
+       }
+       if (ev->ring.called_subaddress.valid) {
+               /* Set Called Subaddress */
+               sig_pri_set_subaddress(&ast_channel_dialed(owner)->subaddress,
+                       &ev->ring.called_subaddress);
+               if (!ev->ring.called_subaddress.type
+                       && !ast_strlen_zero((char *) ev->ring.called_subaddress.data)) {
+                       /* NSAP */
+                       pbx_builtin_setvar_helper(owner, "CALLEDSUBADDR",
+                               (char *) ev->ring.called_subaddress.data);
+               }
+       }
+#else
+       if (!ast_strlen_zero(ev->ring.callingsubaddr)) {
+               pbx_builtin_setvar_helper(owner, "CALLINGSUBADDR", ev->ring.callingsubaddr);
+       }
+#endif /* !defined(HAVE_PRI_SUBADDR) */
+       if (ev->ring.ani2 >= 0) {
+               ast_channel_caller(owner)->ani2 = ev->ring.ani2;
+               snprintf(ani2str, sizeof(ani2str), "%d", ev->ring.ani2);
+               pbx_builtin_setvar_helper(owner, "ANI2", ani2str);
+       }
+
+#ifdef SUPPORT_USERUSER
+       if (!ast_strlen_zero(ev->ring.useruserinfo)) {
+               pbx_builtin_setvar_helper(owner, "USERUSERINFO", ev->ring.useruserinfo);
+       }
+#endif
+
+       snprintf(calledtonstr, sizeof(calledtonstr), "%d", ev->ring.calledplan);
+       pbx_builtin_setvar_helper(owner, "CALLEDTON", calledtonstr);
+       ast_channel_dialed(owner)->number.plan = ev->ring.calledplan;
+
+       if (ev->ring.redirectingreason >= 0) {
+               /* This is now just a status variable.  Use REDIRECTING() dialplan function. */
+               pbx_builtin_setvar_helper(owner, "PRIREDIRECTREASON",
+                       redirectingreason2str(ev->ring.redirectingreason));
+       }
+#if defined(HAVE_PRI_REVERSE_CHARGE)
+       pri->pvts[chanpos]->reverse_charging_indication = ev->ring.reversecharge;
+#endif
+#if defined(HAVE_PRI_SETUP_KEYPAD)
+       ast_copy_string(pri->pvts[chanpos]->keypad_digits,
+               ev->ring.keypad_digits, sizeof(pri->pvts[chanpos]->keypad_digits));
+#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
+
+       /*
+        * It's ok to call this with the owner already locked here
+        * since it will want to do this anyway if there are any
+        * subcmds.
+        */
+       sig_pri_handle_subcmds(pri, chanpos, ev->e, ev->ring.subcmds,
+               ev->ring.call);
+
+       ast_channel_stage_snapshot_done(owner);
+       ast_channel_unlock(owner);
+}
+
+/*!
+ * \internal
+ * \brief Handle the incoming SETUP event from libpri.
+ *
+ * \param pri PRI span control structure.
+ * \param e SETUP event received.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_handle_setup(struct sig_pri_span *pri, pri_event *e)
+{
+       int exten_exists_or_can_exist;
+       int could_match_more;
+       int need_dialtone;
+       enum sig_pri_law law;
+       int chanpos = -1;
+       ast_callid callid = 0;
+       struct ast_channel *c;
+       char plancallingnum[AST_MAX_EXTENSION];
+       char plancallingani[AST_MAX_EXTENSION];
+       pthread_t threadid;
+
+       if (!ast_strlen_zero(pri->msn_list)
+               && !sig_pri_msn_match(pri->msn_list, e->ring.callednum)) {
+               /* The call is not for us so ignore it. */
+               ast_verb(3,
+                       "Ignoring call to '%s' on span %d.  Its not in the MSN list: %s\n",
+                       e->ring.callednum, pri->span, pri->msn_list);
+               pri_destroycall(pri->pri, e->ring.call);
+               goto setup_exit;
+       }
+       if (sig_pri_is_cis_call(e->ring.channel)) {
+               sig_pri_handle_cis_subcmds(pri, e->e, e->ring.subcmds, e->ring.call);
+               goto setup_exit;
+       }
+       chanpos = pri_find_principle_by_call(pri, e->ring.call);
+       if (-1 < chanpos) {
+               /* Libpri has already filtered out duplicate SETUPs. */
+               ast_log(LOG_WARNING,
+                       "Span %d: Got SETUP with duplicate call ptr (%p).  Dropping call.\n",
+                       pri->span, e->ring.call);
+               pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_TEMPORARY_FAILURE);
+               goto setup_exit;
+       }
+       if (e->ring.channel == -1 || PRI_CHANNEL(e->ring.channel) == 0xFF) {
+               /* Any channel requested. */
+               chanpos = pri_find_empty_chan(pri, 1);
+               if (-1 < chanpos) {
+                       callid = func_pri_dchannel_new_callid();
+               }
+       } else if (PRI_CHANNEL(e->ring.channel) == 0x00) {
+               /* No channel specified. */
+#if defined(HAVE_PRI_CALL_WAITING)
+               if (!pri->allow_call_waiting_calls)
+#endif /* defined(HAVE_PRI_CALL_WAITING) */
+               {
+                       /* We will not accept incoming call waiting calls. */
+                       pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
+                       goto setup_exit;
+               }
+#if defined(HAVE_PRI_CALL_WAITING)
+               chanpos = pri_find_empty_nobch(pri);
+               if (chanpos < 0) {
+                       /* We could not find/create a call interface. */
+                       pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
+                       goto setup_exit;
+               }
+
+               callid = func_pri_dchannel_new_callid();
+
+               /* Setup the call interface to use. */
+               sig_pri_init_config(pri->pvts[chanpos], pri);
+#endif /* defined(HAVE_PRI_CALL_WAITING) */
+       } else {
+               /* A channel is specified. */
+               callid = func_pri_dchannel_new_callid();
+               chanpos = pri_find_principle(pri, e->ring.channel, e->ring.call);
+               if (chanpos < 0) {
+                       ast_log(LOG_WARNING,
+                               "Span %d: SETUP on unconfigured channel %d/%d\n",
+                               pri->span, PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel));
+               } else {
+                       switch (pri->pvts[chanpos]->resetting) {
+                       case SIG_PRI_RESET_IDLE:
+                               break;
+                       case SIG_PRI_RESET_ACTIVE:
+                               /*
+                                * The peer may have lost the expected ack or not received the
+                                * RESTART yet.
+                                */
+                               pri->pvts[chanpos]->resetting = SIG_PRI_RESET_NO_ACK;
+                               break;
+                       case SIG_PRI_RESET_NO_ACK:
+                               /* The peer likely is not going to ack the RESTART. */
+                               ast_debug(1,
+                                       "Span %d: Second SETUP while waiting for RESTART ACKNOWLEDGE on channel %d/%d\n",
+                                       pri->span, PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel));
+
+                               /* Assume we got the ack. */
+                               pri->pvts[chanpos]->resetting = SIG_PRI_RESET_IDLE;
+                               if (pri->resetting) {
+                                       /* Go on to the next idle channel to RESTART. */
+                                       pri_check_restart(pri);
+                               }
+                               break;
+                       }
+                       if (!sig_pri_is_chan_available(pri->pvts[chanpos])) {
+                               /* This is where we handle initial glare */
+                               ast_debug(1,
+                                       "Span %d: SETUP requested unavailable channel %d/%d.  Attempting to renegotiate.\n",
+                                       pri->span, PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel));
+                               chanpos = -1;
+                       }
+               }
+#if defined(ALWAYS_PICK_CHANNEL)
+               if (e->ring.flexible) {
+                       chanpos = -1;
+               }
+#endif /* defined(ALWAYS_PICK_CHANNEL) */
+               if (chanpos < 0 && e->ring.flexible) {
+                       /* We can try to pick another channel. */
+                       chanpos = pri_find_empty_chan(pri, 1);
+               }
+       }
+       if (chanpos < 0) {
+               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);
+               }
+               goto setup_exit;
+       }
+
+       sig_pri_lock_private(pri->pvts[chanpos]);
+
+       /* Mark channel as in use so noone else will steal it. */
+       pri->pvts[chanpos]->call = e->ring.call;
+
+       /* Use plancallingnum as a scratch buffer since it is initialized next. */
+       apply_plan_to_existing_number(plancallingnum, sizeof(plancallingnum), pri,
+               e->ring.redirectingnum, e->ring.callingplanrdnis);
+       sig_pri_set_rdnis(pri->pvts[chanpos], plancallingnum);
+
+       /* Setup caller-id info */
+       apply_plan_to_existing_number(plancallingnum, sizeof(plancallingnum), pri,
+               e->ring.callingnum, e->ring.callingplan);
+       pri->pvts[chanpos]->cid_ani2 = 0;
+       if (pri->pvts[chanpos]->use_callerid) {
+               ast_shrink_phone_number(plancallingnum);
+               ast_copy_string(pri->pvts[chanpos]->cid_num, plancallingnum,
+                       sizeof(pri->pvts[chanpos]->cid_num));
+#ifdef PRI_ANI
+               apply_plan_to_existing_number(plancallingani, sizeof(plancallingani),
+                       pri, e->ring.callingani, e->ring.callingplanani);
+               ast_shrink_phone_number(plancallingani);
+               ast_copy_string(pri->pvts[chanpos]->cid_ani, plancallingani,
+                       sizeof(pri->pvts[chanpos]->cid_ani));
+#endif
+               pri->pvts[chanpos]->cid_subaddr[0] = '\0';
+#if defined(HAVE_PRI_SUBADDR)
+               if (e->ring.calling.subaddress.valid) {
+                       struct ast_party_subaddress calling_subaddress;
+
+                       ast_party_subaddress_init(&calling_subaddress);
+                       sig_pri_set_subaddress(&calling_subaddress,
+                               &e->ring.calling.subaddress);
+                       if (calling_subaddress.str) {
+                               ast_copy_string(pri->pvts[chanpos]->cid_subaddr,
+                                       calling_subaddress.str,
+                                       sizeof(pri->pvts[chanpos]->cid_subaddr));
+                       }
+                       ast_party_subaddress_free(&calling_subaddress);
+               }
+#endif /* defined(HAVE_PRI_SUBADDR) */
+               ast_copy_string(pri->pvts[chanpos]->cid_name, e->ring.callingname,
+                       sizeof(pri->pvts[chanpos]->cid_name));
+               /* this is the callingplan (TON/NPI), e->ring.callingplan>>4 would be the TON */
+               pri->pvts[chanpos]->cid_ton = e->ring.callingplan;
+               pri->pvts[chanpos]->callingpres = e->ring.callingpres;
+               if (e->ring.ani2 >= 0) {
+                       pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
+               }
+       } else {
+               pri->pvts[chanpos]->cid_num[0] = '\0';
+               pri->pvts[chanpos]->cid_subaddr[0] = '\0';
+               pri->pvts[chanpos]->cid_ani[0] = '\0';
+               pri->pvts[chanpos]->cid_name[0] = '\0';
+               pri->pvts[chanpos]->cid_ton = 0;
+               pri->pvts[chanpos]->callingpres = 0;
+       }
+
+       /* Setup the user tag for party id's from this device for this call. */
+       if (pri->append_msn_to_user_tag) {
+               snprintf(pri->pvts[chanpos]->user_tag,
+                       sizeof(pri->pvts[chanpos]->user_tag), "%s_%s",
+                       pri->initial_user_tag,
+                       pri->nodetype == PRI_NETWORK
+                               ? plancallingnum : e->ring.callednum);
+       } else {
+               ast_copy_string(pri->pvts[chanpos]->user_tag,
+                       pri->initial_user_tag, sizeof(pri->pvts[chanpos]->user_tag));
+       }
+
+       sig_pri_set_caller_id(pri->pvts[chanpos]);
+
+       /* Set DNID on all incoming calls -- even immediate */
+       sig_pri_set_dnid(pri->pvts[chanpos], e->ring.callednum);
+
+       if (pri->pvts[chanpos]->immediate) {
+               /* immediate=yes go to s|1 */
+               ast_verb(3, "Going to extension s|1 because of immediate=yes\n");
+               pri->pvts[chanpos]->exten[0] = 's';
+               pri->pvts[chanpos]->exten[1] = '\0';
+       } else if (!ast_strlen_zero(e->ring.callednum)) {
+               /* Get called number */
+               ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum,
+                       sizeof(pri->pvts[chanpos]->exten));
+       } else if (pri->overlapdial) {
+               pri->pvts[chanpos]->exten[0] = '\0';
+       } else {
+               /* Some PRI circuits are set up to send _no_ digits.  Handle them as 's'. */
+               pri->pvts[chanpos]->exten[0] = 's';
+               pri->pvts[chanpos]->exten[1] = '\0';
+       }
+       /* No number yet, but received "sending complete"? */
+       if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
+               ast_verb(3, "Going to extension s|1 because of Complete received\n");
+               pri->pvts[chanpos]->exten[0] = 's';
+               pri->pvts[chanpos]->exten[1] = '\0';
+       }
+
+       /* Make sure extension exists (or in overlap dial mode, can exist) */
+       exten_exists_or_can_exist = ((pri->overlapdial & DAHDI_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);
+       if (!exten_exists_or_can_exist) {
+               ast_verb(3,
+                       "Span %d: Extension %s@%s does not exist.  Rejecting call from '%s'.\n",
+                       pri->span, pri->pvts[chanpos]->exten, pri->pvts[chanpos]->context,
+                       pri->pvts[chanpos]->cid_num);
+               pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED);
+               pri->pvts[chanpos]->call = NULL;
+               pri->pvts[chanpos]->exten[0] = '\0';
+               sig_pri_unlock_private(pri->pvts[chanpos]);
+               sig_pri_span_devstate_changed(pri);
+               goto setup_exit;
+       }
+
+       /* Select audio companding mode. */
+       switch (e->ring.layer1) {
+       case PRI_LAYER_1_ALAW:
+               law = SIG_PRI_ALAW;
+               break;
+       case PRI_LAYER_1_ULAW:
+               law = SIG_PRI_ULAW;
+               break;
+       default:
+               /* This is a data call to us. */
+               law = SIG_PRI_DEFLAW;
+               break;
+       }
+
+       could_match_more = !e->ring.complete
+               && (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
+               && ast_matchmore_extension(NULL, pri->pvts[chanpos]->context,
+                       pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num);
+
+       need_dialtone = could_match_more
+               /*
+                * Must explicitly check the digital capability this
+                * way instead of checking the pvt->digital flag
+                * because the flag hasn't been set yet.
+                */
+               && !(e->ring.ctype & AST_TRANS_CAP_DIGITAL)
+               && !pri->pvts[chanpos]->no_b_channel
+               && (!strlen(pri->pvts[chanpos]->exten)
+                       || ast_ignore_pattern(pri->pvts[chanpos]->context,
+                               pri->pvts[chanpos]->exten));
+
+       if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
+               /* Just announce proceeding */
+               pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_PROCEEDING;
+               pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
+       } else if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
+               pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_CONNECT;
+               pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
+       } else {
+               pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_OVERLAP;
+#if defined(HAVE_PRI_SETUP_ACK_INBAND)
+               pri_setup_ack(pri->pri, e->ring.call,
+                       PVT_TO_CHANNEL(pri->pvts[chanpos]), 1, need_dialtone);
+#else  /* !defined(HAVE_PRI_SETUP_ACK_INBAND) */
+               pri_need_more_info(pri->pri, e->ring.call,
+                       PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
+#endif /* !defined(HAVE_PRI_SETUP_ACK_INBAND) */
+       }
+
+       /*
+        * Release the PRI lock while we create the channel so other
+        * threads can send D channel messages.  We must also release
+        * the private lock to prevent deadlock while creating the
+        * channel.
+        */
+       sig_pri_unlock_private(pri->pvts[chanpos]);
+       ast_mutex_unlock(&pri->lock);
+       c = sig_pri_new_ast_channel(pri->pvts[chanpos],
+               could_match_more ? AST_STATE_RESERVED : AST_STATE_RING, law, e->ring.ctype,
+               pri->pvts[chanpos]->exten, NULL, NULL);
+       ast_mutex_lock(&pri->lock);
+       sig_pri_lock_private(pri->pvts[chanpos]);
+
+       if (c) {
+               setup_incoming_channel(pri, chanpos, e);
+
+               /* Start PBX */
+               if (could_match_more) {
+#if !defined(HAVE_PRI_SETUP_ACK_INBAND)
+                       if (need_dialtone) {
+                               /* Indicate that we are providing dialtone. */
+                               pri->pvts[chanpos]->progress = 1;/* No need to send plain PROGRESS again. */
+#ifdef HAVE_PRI_PROG_W_CAUSE
+                               pri_progress_with_cause(pri->pri, e->ring.call,
+                                       PVT_TO_CHANNEL(pri->pvts[chanpos]), 1, -1);/* no cause at all */
+#else
+                               pri_progress(pri->pri, e->ring.call,
+                                       PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
+#endif
+                       }
+#endif /* !defined(HAVE_PRI_SETUP_ACK_INBAND) */
+
+                       if (!ast_pthread_create_detached(&threadid, NULL, pri_ss_thread,
+                               pri->pvts[chanpos])) {
+                               ast_verb(3, "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
+                                       plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
+                                       pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,
+                                       pri->span);
+                               sig_pri_unlock_private(pri->pvts[chanpos]);
+                               goto setup_exit;
+                       }
+               } else {
+                       if (!ast_pbx_start(c)) {
+                               ast_verb(3, "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n",
+                                       plancallingnum, pri->pvts[chanpos]->exten,
+                                       pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,
+                                       pri->span);
+                               sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
+                               sig_pri_unlock_private(pri->pvts[chanpos]);
+                               goto setup_exit;
+                       }
+               }
+       }
+       ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
+               pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+       if (c) {
+               /* Avoid deadlock while destroying channel */
+               sig_pri_unlock_private(pri->pvts[chanpos]);
+               ast_mutex_unlock(&pri->lock);
+               ast_hangup(c);
+               ast_mutex_lock(&pri->lock);
+       } else {
+               pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
+               pri->pvts[chanpos]->call = NULL;
+               sig_pri_unlock_private(pri->pvts[chanpos]);
+               sig_pri_span_devstate_changed(pri);
+       }
+
+setup_exit:;
+       if (callid) {
+               ast_callid_threadassoc_remove();
+       }
+}
+
 static void *pri_dchannel(void *vpri)
 {
        struct sig_pri_span *pri = vpri;
        pri_event *e;
        struct pollfd fds[SIG_PRI_NUM_DCHANS];
        int res;
-       int chanpos = 0;
        int x;
-       int law;
-       struct ast_channel *c;
        struct timeval tv, lowest, *next;
        int doidling=0;
        char *cc;
        time_t t;
        int i, which=-1;
        int numdchans;
-       pthread_t threadid;
-       char ani2str[6];
-       char plancallingnum[AST_MAX_EXTENSION];
-       char plancallingani[AST_MAX_EXTENSION];
-       char calledtonstr[10];
        struct timeval lastidle = { 0, 0 };
        pthread_t p;
        struct ast_channel *idle;
@@ -5488,6 +6260,8 @@ static void *pri_dchannel(void *vpri)
                        ast_log(LOG_WARNING, "Idle dial string '%s' lacks '@context'\n", pri->idleext);
        }
        for (;;) {
+               ast_callid callid = 0;
+
                for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
                        if (!pri->dchans[i])
                                break;
@@ -5549,7 +6323,7 @@ static void *pri_dchannel(void *vpri)
                                         */
                                        sig_pri_lock_private(pri->pvts[nextidle]);
                                        sig_pri_unlock_private(pri->pvts[nextidle]);
-                                       idle = sig_pri_request(pri->pvts[nextidle], AST_FORMAT_ULAW, NULL, 0);
+                                       idle = sig_pri_request(pri->pvts[nextidle], SIG_PRI_ULAW, NULL, NULL, 0);
                                        ast_mutex_lock(&pri->lock);
                                        if (idle) {
                                                pri->pvts[nextidle]->isidlecall = 1;
@@ -5646,11 +6420,22 @@ static void *pri_dchannel(void *vpri)
                                }
                                if (e)
                                        break;
+
+                               if ((errno != 0) && (errno != EINTR)) {
+                                       ast_log(LOG_NOTICE, "pri_check_event returned error %d (%s)\n",
+                                               errno, strerror(errno));
+                               }
+                               if (errno == ENODEV) {
+                                       pri_destroy_later(pri);
+                               }
                        }
                } else if (errno != EINTR)
                        ast_log(LOG_WARNING, "pri_event returned error %d (%s)\n", errno, strerror(errno));
 
                if (e) {
+                       int chanpos = -1;
+                       char cause_str[35];
+
                        if (pri->debug) {
                                ast_verbose("Span %d: Processing event %s(%d)\n",
                                        pri->span, pri_event2str(e->e), e->e);
@@ -5760,9 +6545,8 @@ static void *pri_dchannel(void *vpri)
                                                                pri->pvts[chanpos]->call = NULL;
                                                        }
                                                }
-                                               /* Force soft hangup if appropriate */
-                                               if (pri->pvts[chanpos]->owner)
-                                                       ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
+                                               /* Force hangup if appropriate */
+                                               sig_pri_queue_hangup(pri, chanpos);
                                                sig_pri_unlock_private(pri->pvts[chanpos]);
                                        }
                                } else {
@@ -5774,8 +6558,8 @@ static void *pri_dchannel(void *vpri)
                                                                pri_destroycall(pri->pri, pri->pvts[x]->call);
                                                                pri->pvts[x]->call = NULL;
                                                        }
-                                                       if (pri->pvts[x]->owner)
-                                                               ast_channel_softhangup_internal_flag_add(pri->pvts[x]->owner, AST_SOFTHANGUP_DEV);
+                                                       /* Force hangup if appropriate */
+                                                       sig_pri_queue_hangup(pri, x);
                                                        sig_pri_unlock_private(pri->pvts[x]);
                                                }
                                }
@@ -5794,6 +6578,9 @@ static void *pri_dchannel(void *vpri)
                                        break;
                                }
                                sig_pri_lock_private(pri->pvts[chanpos]);
+
+                               callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
                                sig_pri_handle_subcmds(pri, chanpos, e->e, e->digit.subcmds,
                                        e->digit.call);
                                /* queue DTMF frame if the PBX for this call was already started (we're forwarding KEYPAD_DIGITs further on */
@@ -5825,6 +6612,9 @@ static void *pri_dchannel(void *vpri)
                                        break;
                                }
                                sig_pri_lock_private(pri->pvts[chanpos]);
+
+                               callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
                                sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.subcmds, e->ring.call);
                                /* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
                                if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
@@ -5898,483 +6688,7 @@ static void *pri_dchannel(void *vpri)
                                break;
 #endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
                        case PRI_EVENT_RING:
-                               if (!ast_strlen_zero(pri->msn_list)
-                                       && !sig_pri_msn_match(pri->msn_list, e->ring.callednum)) {
-                                       /* The call is not for us so ignore it. */
-                                       ast_verb(3,
-                                               "Ignoring call to '%s' on span %d.  Its not in the MSN list: %s\n",
-                                               e->ring.callednum, pri->span, pri->msn_list);
-                                       pri_destroycall(pri->pri, e->ring.call);
-                                       break;
-                               }
-                               if (sig_pri_is_cis_call(e->ring.channel)) {
-                                       sig_pri_handle_cis_subcmds(pri, e->e, e->ring.subcmds,
-                                               e->ring.call);
-                                       break;
-                               }
-                               chanpos = pri_find_principle_by_call(pri, e->ring.call);
-                               if (-1 < chanpos) {
-                                       /* Libpri has already filtered out duplicate SETUPs. */
-                                       ast_log(LOG_WARNING,
-                                               "Span %d: Got SETUP with duplicate call ptr (%p).  Dropping call.\n",
-                                               pri->span, e->ring.call);
-                                       pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_TEMPORARY_FAILURE);
-                                       break;
-                               }
-                               if (e->ring.channel == -1 || PRI_CHANNEL(e->ring.channel) == 0xFF) {
-                                       /* Any channel requested. */
-                                       chanpos = pri_find_empty_chan(pri, 1);
-                               } else if (PRI_CHANNEL(e->ring.channel) == 0x00) {
-                                       /* No channel specified. */
-#if defined(HAVE_PRI_CALL_WAITING)
-                                       if (!pri->allow_call_waiting_calls)
-#endif /* defined(HAVE_PRI_CALL_WAITING) */
-                                       {
-                                               /* We will not accept incoming call waiting calls. */
-                                               pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
-                                               break;
-                                       }
-#if defined(HAVE_PRI_CALL_WAITING)
-                                       chanpos = pri_find_empty_nobch(pri);
-                                       if (chanpos < 0) {
-                                               /* We could not find/create a call interface. */
-                                               pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
-                                               break;
-                                       }
-                                       /* Setup the call interface to use. */
-                                       sig_pri_init_config(pri->pvts[chanpos], pri);
-#endif /* defined(HAVE_PRI_CALL_WAITING) */
-                               } else {
-                                       /* A channel is specified. */
-                                       chanpos = pri_find_principle(pri, e->ring.channel, e->ring.call);
-                                       if (chanpos < 0) {
-                                               ast_log(LOG_WARNING,
-                                                       "Span %d: SETUP on unconfigured channel %d/%d\n",
-                                                       pri->span, PRI_SPAN(e->ring.channel),
-                                                       PRI_CHANNEL(e->ring.channel));
-                                       } else {
-                                               switch (pri->pvts[chanpos]->resetting) {
-                                               case SIG_PRI_RESET_IDLE:
-                                                       break;
-                                               case SIG_PRI_RESET_ACTIVE:
-                                                       /*
-                                                        * The peer may have lost the expected ack or not received the
-                                                        * RESTART yet.
-                                                        */
-                                                       pri->pvts[chanpos]->resetting = SIG_PRI_RESET_NO_ACK;
-                                                       break;
-                                               case SIG_PRI_RESET_NO_ACK:
-                                                       /* The peer likely is not going to ack the RESTART. */
-                                                       ast_debug(1,
-                                                               "Span %d: Second SETUP while waiting for RESTART ACKNOWLEDGE on channel %d/%d\n",
-                                                               pri->span, PRI_SPAN(e->ring.channel),
-                                                               PRI_CHANNEL(e->ring.channel));
-
-                                                       /* Assume we got the ack. */
-                                                       pri->pvts[chanpos]->resetting = SIG_PRI_RESET_IDLE;
-                                                       if (pri->resetting) {
-                                                               /* Go on to the next idle channel to RESTART. */
-                                                               pri_check_restart(pri);
-                                                       }
-                                                       break;
-                                               }
-                                               if (!sig_pri_is_chan_available(pri->pvts[chanpos])) {
-                                                       /* This is where we handle initial glare */
-                                                       ast_debug(1,
-                                                               "Span %d: SETUP requested unavailable channel %d/%d.  Attempting to renegotiate.\n",
-                                                               pri->span, PRI_SPAN(e->ring.channel),
-                                                               PRI_CHANNEL(e->ring.channel));
-                                                       chanpos = -1;
-                                               }
-                                       }
-#if defined(ALWAYS_PICK_CHANNEL)
-                                       if (e->ring.flexible) {
-                                               chanpos = -1;
-                                       }
-#endif /* defined(ALWAYS_PICK_CHANNEL) */
-                                       if (chanpos < 0 && e->ring.flexible) {
-                                               /* We can try to pick another channel. */
-                                               chanpos = pri_find_empty_chan(pri, 1);
-                                       }
-                               }
-                               if (chanpos < 0) {
-                                       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;
-                               }
-
-                               sig_pri_lock_private(pri->pvts[chanpos]);
-
-                               /* Mark channel as in use so noone else will steal it. */
-                               pri->pvts[chanpos]->call = e->ring.call;
-
-                               /* Use plancallingnum as a scratch buffer since it is initialized next. */
-                               apply_plan_to_existing_number(plancallingnum, sizeof(plancallingnum), pri,
-                                       e->ring.redirectingnum, e->ring.callingplanrdnis);
-                               sig_pri_set_rdnis(pri->pvts[chanpos], plancallingnum);
-
-                               /* Setup caller-id info */
-                               apply_plan_to_existing_number(plancallingnum, sizeof(plancallingnum), pri,
-                                       e->ring.callingnum, e->ring.callingplan);
-                               pri->pvts[chanpos]->cid_ani2 = 0;
-                               if (pri->pvts[chanpos]->use_callerid) {
-                                       ast_shrink_phone_number(plancallingnum);
-                                       ast_copy_string(pri->pvts[chanpos]->cid_num, plancallingnum, sizeof(pri->pvts[chanpos]->cid_num));
-#ifdef PRI_ANI
-                                       apply_plan_to_existing_number(plancallingani, sizeof(plancallingani),
-                                               pri, e->ring.callingani, e->ring.callingplanani);
-                                       ast_shrink_phone_number(plancallingani);
-                                       ast_copy_string(pri->pvts[chanpos]->cid_ani, plancallingani,
-                                               sizeof(pri->pvts[chanpos]->cid_ani));
-#endif
-                                       pri->pvts[chanpos]->cid_subaddr[0] = '\0';
-#if defined(HAVE_PRI_SUBADDR)
-                                       if (e->ring.calling.subaddress.valid) {
-                                               struct ast_party_subaddress calling_subaddress;
-
-                                               ast_party_subaddress_init(&calling_subaddress);
-                                               sig_pri_set_subaddress(&calling_subaddress,
-                                                       &e->ring.calling.subaddress);
-                                               if (calling_subaddress.str) {
-                                                       ast_copy_string(pri->pvts[chanpos]->cid_subaddr,
-                                                               calling_subaddress.str,
-                                                               sizeof(pri->pvts[chanpos]->cid_subaddr));
-                                               }
-                                               ast_party_subaddress_free(&calling_subaddress);
-                                       }
-#endif /* defined(HAVE_PRI_SUBADDR) */
-                                       ast_copy_string(pri->pvts[chanpos]->cid_name, e->ring.callingname, sizeof(pri->pvts[chanpos]->cid_name));
-                                       pri->pvts[chanpos]->cid_ton = e->ring.callingplan; /* this is the callingplan (TON/NPI), e->ring.callingplan>>4 would be the TON */
-                                       pri->pvts[chanpos]->callingpres = e->ring.callingpres;
-                                       if (e->ring.ani2 >= 0) {
-                                               pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
-                                       }
-                               } else {
-                                       pri->pvts[chanpos]->cid_num[0] = '\0';
-                                       pri->pvts[chanpos]->cid_subaddr[0] = '\0';
-                                       pri->pvts[chanpos]->cid_ani[0] = '\0';
-                                       pri->pvts[chanpos]->cid_name[0] = '\0';
-                                       pri->pvts[chanpos]->cid_ton = 0;
-                                       pri->pvts[chanpos]->callingpres = 0;
-                               }
-
-                               /* Setup the user tag for party id's from this device for this call. */
-                               if (pri->append_msn_to_user_tag) {
-                                       snprintf(pri->pvts[chanpos]->user_tag,
-                                               sizeof(pri->pvts[chanpos]->user_tag), "%s_%s",
-                                               pri->initial_user_tag,
-                                               pri->nodetype == PRI_NETWORK
-                                                       ? plancallingnum : e->ring.callednum);
-                               } else {
-                                       ast_copy_string(pri->pvts[chanpos]->user_tag,
-                                               pri->initial_user_tag, sizeof(pri->pvts[chanpos]->user_tag));
-                               }
-
-                               sig_pri_set_caller_id(pri->pvts[chanpos]);
-
-                               /* Set DNID on all incoming calls -- even immediate */
-                               sig_pri_set_dnid(pri->pvts[chanpos], e->ring.callednum);
-
-                               /* If immediate=yes go to s|1 */
-                               if (pri->pvts[chanpos]->immediate) {
-                                       ast_verb(3, "Going to extension s|1 because of immediate=yes\n");
-                                       pri->pvts[chanpos]->exten[0] = 's';
-                                       pri->pvts[chanpos]->exten[1] = '\0';
-                               }
-                               /* Get called number */
-                               else if (!ast_strlen_zero(e->ring.callednum)) {
-                                       ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
-                               } else if (pri->overlapdial)
-                                       pri->pvts[chanpos]->exten[0] = '\0';
-                               else {
-                                       /* Some PRI circuits are set up to send _no_ digits.  Handle them as 's'. */
-                                       pri->pvts[chanpos]->exten[0] = 's';
-                                       pri->pvts[chanpos]->exten[1] = '\0';
-                               }
-                               /* No number yet, but received "sending complete"? */
-                               if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
-                                       ast_verb(3, "Going to extension s|1 because of Complete received\n");
-                                       pri->pvts[chanpos]->exten[0] = 's';
-                                       pri->pvts[chanpos]->exten[1] = '\0';
-                               }
-
-                               /* Make sure extension exists (or in overlap dial mode, can exist) */
-                               if (((pri->overlapdial & DAHDI_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)) {
-                                       /* Select audio companding mode. */
-                                       switch (e->ring.layer1) {
-                                       case PRI_LAYER_1_ALAW:
-                                               law = SIG_PRI_ALAW;
-                                               break;
-                                       case PRI_LAYER_1_ULAW:
-                                               law = SIG_PRI_ULAW;
-                                               break;
-                                       default:
-                                               /* This is a data call to us. */
-                                               law = SIG_PRI_DEFLAW;
-                                               break;
-                                       }
-
-                                       if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
-                                               /* Just announce proceeding */
-                                               pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_PROCEEDING;
-                                               pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
-                                       } else if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
-                                               pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_CONNECT;
-                                               pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
-                                       } else {
-                                               pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_OVERLAP;
-                                               pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
-                                       }
-
-                                       /* Start PBX */
-                                       if (!e->ring.complete
-                                               && (pri->overlapdial & DAHDI_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 so other
-                                                * threads can send D channel messages.  We must also release
-                                                * the private lock to prevent deadlock while creating the
-                                                * channel.
-                                                */
-                                               sig_pri_unlock_private(pri->pvts[chanpos]);
-                                               ast_mutex_unlock(&pri->lock);
-                                               c = sig_pri_new_ast_channel(pri->pvts[chanpos],
-                                                       AST_STATE_RESERVED, law, e->ring.ctype,
-                                                       pri->pvts[chanpos]->exten, NULL);
-                                               ast_mutex_lock(&pri->lock);
-                                               sig_pri_lock_private(pri->pvts[chanpos]);
-                                               if (c) {
-#if defined(HAVE_PRI_SUBADDR)
-                                                       if (e->ring.calling.subaddress.valid) {
-                                                               /* Set Calling Subaddress */
-                                                               sig_pri_lock_owner(pri, chanpos);
-                                                               sig_pri_set_subaddress(
-                                                                       &ast_channel_caller(pri->pvts[chanpos]->owner)->id.subaddress,
-                                                                       &e->ring.calling.subaddress);
-                                                               if (!e->ring.calling.subaddress.type
-                                                                       && !ast_strlen_zero(
-                                                                               (char *) e->ring.calling.subaddress.data)) {
-                                                                       /* NSAP */
-                                                                       pbx_builtin_setvar_helper(c, "CALLINGSUBADDR",
-                                                                               (char *) e->ring.calling.subaddress.data);
-                                                               }
-                                                               ast_channel_unlock(c);
-                                                       }
-                                                       if (e->ring.called_subaddress.valid) {
-                                                               /* Set Called Subaddress */
-                                                               sig_pri_lock_owner(pri, chanpos);
-                                                               sig_pri_set_subaddress(
-                                                                       &ast_channel_dialed(pri->pvts[chanpos]->owner)->subaddress,
-                                                                       &e->ring.called_subaddress);
-                                                               if (!e->ring.called_subaddress.type
-                                                                       && !ast_strlen_zero(
-                                                                               (char *) e->ring.called_subaddress.data)) {
-                                                                       /* NSAP */
-                                                                       pbx_builtin_setvar_helper(c, "CALLEDSUBADDR",
-                                                                               (char *) e->ring.called_subaddress.data);
-                                                               }
-                                                               ast_channel_unlock(c);
-                                                       }
-#else
-                                                       if (!ast_strlen_zero(e->ring.callingsubaddr)) {
-                                                               pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
-                                                       }
-#endif /* !defined(HAVE_PRI_SUBADDR) */
-                                                       if (e->ring.ani2 >= 0) {
-                                                               snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
-                                                               pbx_builtin_setvar_helper(c, "ANI2", ani2str);
-                                                       }
-
-#ifdef SUPPORT_USERUSER
-                                                       if (!ast_strlen_zero(e->ring.useruserinfo)) {
-                                                               pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
-                                                       }
-#endif
-
-                                                       snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
-                                                       pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
-                                                       if (e->ring.redirectingreason >= 0) {
-                                                               /* This is now just a status variable.  Use REDIRECTING() dialplan function. */
-                                                               pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
-                                                       }
-#if defined(HAVE_PRI_REVERSE_CHARGE)
-                                                       pri->pvts[chanpos]->reverse_charging_indication = e->ring.reversecharge;
-#endif
-#if defined(HAVE_PRI_SETUP_KEYPAD)
-                                                       ast_copy_string(pri->pvts[chanpos]->keypad_digits,
-                                                               e->ring.keypad_digits,
-                                                               sizeof(pri->pvts[chanpos]->keypad_digits));
-#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
-
-                                                       sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.subcmds,
-                                                               e->ring.call);
-
-                                                       if (!pri->pvts[chanpos]->digital
-                                                               && !pri->pvts[chanpos]->no_b_channel) {
-                                                               /*
-                                                                * Call has a channel.
-                                                                * Indicate that we are providing dialtone.
-                                                                */
-                                                               pri->pvts[chanpos]->progress = 1;/* No need to send plain PROGRESS again. */
-#ifdef HAVE_PRI_PROG_W_CAUSE
-                                                               pri_progress_with_cause(pri->pri, e->ring.call,
-                                                                       PVT_TO_CHANNEL(pri->pvts[chanpos]), 1, -1);/* no cause at all */
-#else
-                                                               pri_progress(pri->pri, e->ring.call,
-                                                                       PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
-#endif
-                                                       }
-                                               }
-                                               if (c && !ast_pthread_create_detached(&threadid, NULL, pri_ss_thread, pri->pvts[chanpos])) {
-                                                       ast_verb(3, "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
-                                                               plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
-                                                               pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
-                                               } else {
-                                                       ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
-                                                               pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
-                                                       if (c) {
-                                                               /* Avoid deadlock while destroying channel */
-                                                               sig_pri_unlock_private(pri->pvts[chanpos]);
-                                                               ast_mutex_unlock(&pri->lock);
-                                                               ast_hangup(c);
-                                                               ast_mutex_lock(&pri->lock);
-                                                       } else {
-                                                               pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
-                                                               pri->pvts[chanpos]->call = NULL;
-                                                               sig_pri_unlock_private(pri->pvts[chanpos]);
-                                                               sig_pri_span_devstate_changed(pri);
-                                                       }
-                                                       break;
-                                               }
-                                       } else {
-                                               /*
-                                                * Release the PRI lock while we create the channel so other
-                                                * threads can send D channel messages.  We must also release
-                                                * the private lock to prevent deadlock while creating the
-                                                * channel.
-                                                */
-                                               sig_pri_unlock_private(pri->pvts[chanpos]);
-                                               ast_mutex_unlock(&pri->lock);
-                                               c = sig_pri_new_ast_channel(pri->pvts[chanpos],
-                                                       AST_STATE_RING, law, e->ring.ctype,
-                                                       pri->pvts[chanpos]->exten, NULL);
-                                               ast_mutex_lock(&pri->lock);
-                                               sig_pri_lock_private(pri->pvts[chanpos]);
-                                               if (c) {
-                                                       /*
-                                                        * It is reasonably safe to set the following
-                                                        * channel variables while the PRI and DAHDI private
-                                                        * structures are locked.  The PBX has not been
-                                                        * started yet and it is unlikely that any other task
-                                                        * will do anything with the channel we have just
-                                                        * created.
-                                                        */
-#if defined(HAVE_PRI_SUBADDR)
-                                                       if (e->ring.calling.subaddress.valid) {
-                                                               /* Set Calling Subaddress */
-                                                               sig_pri_lock_owner(pri, chanpos);
-                                                               sig_pri_set_subaddress(
-                                                                       &ast_channel_caller(pri->pvts[chanpos]->owner)->id.subaddress,
-                                                                       &e->ring.calling.subaddress);
-                                                               if (!e->ring.calling.subaddress.type
-                                                                       && !ast_strlen_zero(
-                                                                               (char *) e->ring.calling.subaddress.data)) {
-                                                                       /* NSAP */
-                                                                       pbx_builtin_setvar_helper(c, "CALLINGSUBADDR",
-                                                                               (char *) e->ring.calling.subaddress.data);
-                                                               }
-                                                               ast_channel_unlock(c);
-                                                       }
-                                                       if (e->ring.called_subaddress.valid) {
-                                                               /* Set Called Subaddress */
-                                                               sig_pri_lock_owner(pri, chanpos);
-                                                               sig_pri_set_subaddress(
-                                                                       &ast_channel_dialed(pri->pvts[chanpos]->owner)->subaddress,
-                                                                       &e->ring.called_subaddress);
-                                                               if (!e->ring.called_subaddress.type
-                                                                       && !ast_strlen_zero(
-                                                                               (char *) e->ring.called_subaddress.data)) {
-                                                                       /* NSAP */
-                                                                       pbx_builtin_setvar_helper(c, "CALLEDSUBADDR",
-                                                                               (char *) e->ring.called_subaddress.data);
-                                                               }
-                                                               ast_channel_unlock(c);
-                                                       }
-#else
-                                                       if (!ast_strlen_zero(e->ring.callingsubaddr)) {
-                                                               pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
-                                                       }
-#endif /* !defined(HAVE_PRI_SUBADDR) */
-                                                       if (e->ring.ani2 >= 0) {
-                                                               snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
-                                                               pbx_builtin_setvar_helper(c, "ANI2", ani2str);
-                                                       }
-
-#ifdef SUPPORT_USERUSER
-                                                       if (!ast_strlen_zero(e->ring.useruserinfo)) {
-                                                               pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
-                                                       }
-#endif
-
-                                                       if (e->ring.redirectingreason >= 0) {
-                                                               /* This is now just a status variable.  Use REDIRECTING() dialplan function. */
-                                                               pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
-                                                       }
-#if defined(HAVE_PRI_REVERSE_CHARGE)
-                                                       pri->pvts[chanpos]->reverse_charging_indication = e->ring.reversecharge;
-#endif
-#if defined(HAVE_PRI_SETUP_KEYPAD)
-                                                       ast_copy_string(pri->pvts[chanpos]->keypad_digits,
-                                                               e->ring.keypad_digits,
-                                                               sizeof(pri->pvts[chanpos]->keypad_digits));
-#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
-
-                                                       snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
-                                                       pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
-
-                                                       sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.subcmds,
-                                                               e->ring.call);
-                                               }
-                                               if (c && !ast_pbx_start(c)) {
-                                                       ast_verb(3, "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n",
-                                                               plancallingnum, pri->pvts[chanpos]->exten,
-                                                               pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
-                                                       sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
-                                               } else {
-                                                       ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
-                                                               pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
-                                                       if (c) {
-                                                               /* Avoid deadlock while destroying channel */
-                                                               sig_pri_unlock_private(pri->pvts[chanpos]);
-                                                               ast_mutex_unlock(&pri->lock);
-                                                               ast_hangup(c);
-                                                               ast_mutex_lock(&pri->lock);
-                                                       } else {
-                                                               pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
-                                                               pri->pvts[chanpos]->call = NULL;
-                                                               sig_pri_unlock_private(pri->pvts[chanpos]);
-                                                               sig_pri_span_devstate_changed(pri);
-                                                       }
-                                                       break;
-                                               }
-                                       }
-                               } else {
-                                       ast_verb(3,
-                                               "Span %d: Extension %s@%s does not exist.  Rejecting call from '%s'.\n",
-                                               pri->span, pri->pvts[chanpos]->exten, pri->pvts[chanpos]->context,
-                                               pri->pvts[chanpos]->cid_num);
-                                       pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED);
-                                       pri->pvts[chanpos]->call = NULL;
-                                       pri->pvts[chanpos]->exten[0] = '\0';
-                                       sig_pri_unlock_private(pri->pvts[chanpos]);
-                                       sig_pri_span_devstate_changed(pri);
-                                       break;
-                               }
-                               sig_pri_unlock_private(pri->pvts[chanpos]);
+                               sig_pri_handle_setup(pri, e);
                                break;
                        case PRI_EVENT_RINGING:
                                if (sig_pri_is_cis_call(e->ringing.channel)) {
@@ -6389,6 +6703,8 @@ static void *pri_dchannel(void *vpri)
                                }
                                sig_pri_lock_private(pri->pvts[chanpos]);
 
+                               callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
                                sig_pri_handle_subcmds(pri, chanpos, e->e, e->ringing.subcmds,
                                        e->ringing.call);
                                sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCNR);
@@ -6447,10 +6763,18 @@ static void *pri_dchannel(void *vpri)
                                        break;
                                }
                                sig_pri_lock_private(pri->pvts[chanpos]);
+
+                               callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
                                sig_pri_handle_subcmds(pri, chanpos, e->e, e->proceeding.subcmds,
                                        e->proceeding.call);
 
                                if (e->proceeding.cause > -1) {
+                                       if (pri->pvts[chanpos]->owner) {
+                                               snprintf(cause_str, sizeof(cause_str), "PRI PRI_EVENT_PROGRESS (%d)", e->proceeding.cause);
+                                               pri_queue_pvt_cause_data(pri, chanpos, cause_str, e->proceeding.cause);
+                                       }
+
                                        ast_verb(3, "PROGRESS with cause code %d received\n", e->proceeding.cause);
 
                                        /* Work around broken, out of spec USER_BUSY cause in a progress message */
@@ -6497,6 +6821,9 @@ static void *pri_dchannel(void *vpri)
                                        break;
                                }
                                sig_pri_lock_private(pri->pvts[chanpos]);
+
+                               callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
                                sig_pri_handle_subcmds(pri, chanpos, e->e, e->proceeding.subcmds,
                                        e->proceeding.call);
                                if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING) {
@@ -6510,8 +6837,15 @@ static void *pri_dchannel(void *vpri)
                                if (!pri->pvts[chanpos]->progress
                                        && !pri->pvts[chanpos]->no_b_channel
 #ifdef PRI_PROGRESS_MASK
-                                       && (e->proceeding.progressmask
-                                               & (PRI_PROG_CALL_NOT_E2E_ISDN | PRI_PROG_INBAND_AVAILABLE))
+                                       /*
+                                        * We only care about PRI_PROG_INBAND_AVAILABLE to open the
+                                        * voice path.
+                                        *
+                                        * We explicitly DO NOT want to check PRI_PROG_CALL_NOT_E2E_ISDN
+                                        * because it will mess up ISDN to SIP interoperability for
+                                        * the ALERTING message.
+                                        */
+                                       && (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)
 #else
                                        && e->proceeding.progress == 8
 #endif
@@ -6519,9 +6853,17 @@ static void *pri_dchannel(void *vpri)
                                        /* Bring voice path up */
                                        pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
                                        pri->pvts[chanpos]->progress = 1;
+                                       sig_pri_set_dialing(pri->pvts[chanpos], 0);
                                        sig_pri_open_media(pri->pvts[chanpos]);
+                               } else if (pri->inband_on_proceeding) {
+                                       /*
+                                        * XXX This is to accomodate a broken switch that sends a
+                                        * PROCEEDING without any progress indication ie for
+                                        * inband audio.  This should be part of the conditional
+                                        * test above to bring the voice path up.
+                                        */
+                                       sig_pri_set_dialing(pri->pvts[chanpos], 0);
                                }
-                               sig_pri_set_dialing(pri->pvts[chanpos], 0);
                                sig_pri_unlock_private(pri->pvts[chanpos]);
                                break;
                        case PRI_EVENT_FACILITY:
@@ -6543,6 +6885,9 @@ static void *pri_dchannel(void *vpri)
                                        break;
                                }
                                sig_pri_lock_private(pri->pvts[chanpos]);
+
+                               callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
 #if defined(HAVE_PRI_CALL_REROUTING)
                                sig_pri_handle_subcmds(pri, chanpos, e->e, e->facility.subcmds,
                                        e->facility.subcall);
@@ -6626,6 +6971,8 @@ static void *pri_dchannel(void *vpri)
 #endif /* defined(HAVE_PRI_CALL_WAITING) */
                                sig_pri_lock_private(pri->pvts[chanpos]);
 
+                               callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
 #if defined(HAVE_PRI_CALL_WAITING)
                                if (pri->pvts[chanpos]->is_call_waiting) {
                                        pri->pvts[chanpos]->is_call_waiting = 0;
@@ -6687,6 +7034,9 @@ static void *pri_dchannel(void *vpri)
                                }
 
                                sig_pri_lock_private(pri->pvts[chanpos]);
+
+                               callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
                                sig_pri_handle_subcmds(pri, chanpos, e->e, e->connect_ack.subcmds,
                                        e->connect_ack.call);
                                sig_pri_open_media(pri->pvts[chanpos]);
@@ -6711,6 +7061,9 @@ static void *pri_dchannel(void *vpri)
                                        break;
                                }
                                sig_pri_lock_private(pri->pvts[chanpos]);
+
+                               callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
                                sig_pri_handle_subcmds(pri, chanpos, e->e, e->hangup.subcmds,
                                        e->hangup.call);
                                switch (e->hangup.cause) {
@@ -6737,6 +7090,10 @@ static void *pri_dchannel(void *vpri)
                                                break;
                                        }
                                        if (pri->pvts[chanpos]->owner) {
+                                               snprintf(cause_str, sizeof(cause_str), "PRI PRI_EVENT_HANGUP (%d)", e->hangup.cause);
+                                               pri_queue_pvt_cause_data(pri, chanpos, cause_str, e->hangup.cause);
+                                       }
+                                       if (pri->pvts[chanpos]->owner) {
                                                int do_hangup = 0;
 
                                                /* Queue a BUSY instead of a hangup if our cause is appropriate */
@@ -6775,17 +7132,7 @@ static void *pri_dchannel(void *vpri)
                                                }
 
                                                if (do_hangup) {
-#if defined(HAVE_PRI_AOC_EVENTS)
-                                                       if (detect_aoc_e_subcmd(e->hangup.subcmds)) {
-                                                               /* If a AOC-E msg was sent during the release, we must use a
-                                                                * AST_CONTROL_HANGUP frame to guarantee that frame gets read before hangup */
-                                                               pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
-                                                       } else {
-                                                               ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
-                                                       }
-#else
-                                                       ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
-#endif /* defined(HAVE_PRI_AOC_EVENTS) */
+                                                       sig_pri_queue_hangup(pri, chanpos);
                                                }
                                        } else {
                                                /*
@@ -6803,9 +7150,9 @@ static void *pri_dchannel(void *vpri)
                                        pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
                                        pri->pvts[chanpos]->call = NULL;
                                }
-#if defined(FORCE_RESTART_UNAVAIL_CHANS)
                                if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL
                                        && pri->sig != SIG_BRI_PTMP && !pri->resetting
+                                       && pri->force_restart_unavailable_chans
                                        && pri->pvts[chanpos]->resetting == SIG_PRI_RESET_IDLE) {
                                        ast_verb(3,
                                                "Span %d: Forcing restart of channel %d/%d since channel reported in use\n",
@@ -6814,7 +7161,6 @@ static void *pri_dchannel(void *vpri)
                                        pri->pvts[chanpos]->resetting = SIG_PRI_RESET_ACTIVE;
                                        pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
                                }
-#endif /* defined(FORCE_RESTART_UNAVAIL_CHANS) */
                                if (e->hangup.aoc_units > -1)
                                        ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
                                                pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
@@ -6853,6 +7199,9 @@ static void *pri_dchannel(void *vpri)
                                        break;
                                }
                                sig_pri_lock_private(pri->pvts[chanpos]);
+
+                               callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
                                sig_pri_handle_subcmds(pri, chanpos, e->e, e->hangup.subcmds,
                                        e->hangup.call);
 #if defined(HAVE_PRI_CALL_HOLD)
@@ -6861,7 +7210,7 @@ static void *pri_dchannel(void *vpri)
                                        /* We are to transfer the call instead of simply hanging up. */
                                        sig_pri_unlock_private(pri->pvts[chanpos]);
                                        if (!sig_pri_attempt_transfer(pri, e->hangup.call_held, 1,
-                                               e->hangup.call_active, 0, NULL, NULL)) {
+                                               e->hangup.call_active, 0, NULL)) {
                                                break;
                                        }
                                        sig_pri_lock_private(pri->pvts[chanpos]);
@@ -6886,6 +7235,10 @@ static void *pri_dchannel(void *vpri)
                                        break;
                                }
                                if (pri->pvts[chanpos]->owner) {
+                                       snprintf(cause_str, sizeof(cause_str), "PRI PRI_EVENT_HANGUP_REQ (%d)", e->hangup.cause);
+                                       pri_queue_pvt_cause_data(pri, chanpos, cause_str, e->hangup.cause);
+                               }
+                               if (pri->pvts[chanpos]->owner) {
                                        int do_hangup = 0;
 
                                        ast_channel_hangupcause_set(pri->pvts[chanpos]->owner, e->hangup.cause);
@@ -6926,19 +7279,14 @@ static void *pri_dchannel(void *vpri)
 #if defined(HAVE_PRI_AOC_EVENTS)
                                                if (!pri->pvts[chanpos]->holding_aoce
                                                        && pri->aoce_delayhangup
-                                                       && ast_bridged_channel(pri->pvts[chanpos]->owner)) {
+                                                       && ast_channel_is_bridged(pri->pvts[chanpos]->owner)) {
                                                        sig_pri_send_aoce_termination_request(pri, chanpos,
                                                                pri_get_timer(pri->pri, PRI_TIMER_T305) / 2);
-                                               } else if (detect_aoc_e_subcmd(e->hangup.subcmds)) {
-                                                       /* If a AOC-E msg was sent during the Disconnect, we must use a AST_CONTROL_HANGUP frame
-                                                        * to guarantee that frame gets read before hangup */
-                                                       pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
-                                               } else {
-                                                       ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
-                                               }
-#else
-                                               ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
+                                               } else
 #endif /* defined(HAVE_PRI_AOC_EVENTS) */
+                                               {
+                                                       sig_pri_queue_hangup(pri, chanpos);
+                                               }
                                        }
                                        ast_verb(3, "Span %d: Channel %d/%d got hangup request, cause %d\n",
                                                pri->span, pri->pvts[chanpos]->logicalspan,
@@ -6951,9 +7299,9 @@ static void *pri_dchannel(void *vpri)
                                        pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
                                        pri->pvts[chanpos]->call = NULL;
                                }
-#if defined(FORCE_RESTART_UNAVAIL_CHANS)
                                if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL
                                        && pri->sig != SIG_BRI_PTMP && !pri->resetting
+                                       && pri->force_restart_unavailable_chans
                                        && pri->pvts[chanpos]->resetting == SIG_PRI_RESET_IDLE) {
                                        ast_verb(3,
                                                "Span %d: Forcing restart of channel %d/%d since channel reported in use\n",
@@ -6962,7 +7310,6 @@ static void *pri_dchannel(void *vpri)
                                        pri->pvts[chanpos]->resetting = SIG_PRI_RESET_ACTIVE;
                                        pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
                                }
-#endif /* defined(FORCE_RESTART_UNAVAIL_CHANS) */
 
 #ifdef SUPPORT_USERUSER
                                if (!ast_strlen_zero(e->hangup.useruserinfo)) {
@@ -6992,6 +7339,9 @@ static void *pri_dchannel(void *vpri)
                                        break;
                                }
                                sig_pri_lock_private(pri->pvts[chanpos]);
+
+                               callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
                                pri->pvts[chanpos]->call = NULL;
                                if (pri->pvts[chanpos]->owner) {
                                        ast_verb(3, "Span %d: Channel %d/%d got hangup ACK\n", pri->span,
@@ -7095,6 +7445,9 @@ static void *pri_dchannel(void *vpri)
                                        break;
                                }
                                sig_pri_lock_private(pri->pvts[chanpos]);
+
+                               callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
                                sig_pri_handle_subcmds(pri, chanpos, e->e, e->setup_ack.subcmds,
                                        e->setup_ack.call);
                                if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_OVERLAP) {
@@ -7112,7 +7465,30 @@ static void *pri_dchannel(void *vpri)
                                if (!pri->pvts[chanpos]->progress
                                        && (pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)
                                        && !pri->pvts[chanpos]->digital
-                                       && !pri->pvts[chanpos]->no_b_channel) {
+                                       && !pri->pvts[chanpos]->no_b_channel
+#if defined(HAVE_PRI_SETUP_ACK_INBAND)
+                                       /*
+                                        * We only care about PRI_PROG_INBAND_AVAILABLE to open the
+                                        * voice path.
+                                        *
+                                        * We explicitly DO NOT want to check PRI_PROG_CALL_NOT_E2E_ISDN
+                                        * because it will mess up ISDN to SIP interoperability for
+                                        * the ALERTING message.
+                                        *
+                                        * Q.931 Section 5.1.3 says that in scenarios with overlap
+                                        * dialing where no called digits are received and the tone
+                                        * option requires dialtone, the switch MAY send an inband
+                                        * progress indication ie to indicate dialtone presence in
+                                        * the SETUP ACKNOWLEDGE.  Therefore, if we did not send any
+                                        * digits with the SETUP then we must assume that dialtone
+                                        * is present and open the voice path.  Fortunately when
+                                        * interoperating with SIP, we should be sending digits.
+                                        */
+                                       && ((e->setup_ack.progressmask & PRI_PROG_INBAND_AVAILABLE)
+                                               || pri->inband_on_setup_ack
+                                               || pri->pvts[chanpos]->no_dialed_digits)
+#endif /* defined(HAVE_PRI_SETUP_ACK_INBAND) */
+                                       ) {
                                        /*
                                         * Call has a channel.
                                         * Indicate for overlap dialing that dialtone may be present.
@@ -7155,6 +7531,9 @@ static void *pri_dchannel(void *vpri)
                                }
 #endif /* !defined(HAVE_PRI_CALL_HOLD) */
                                sig_pri_lock_private(pri->pvts[chanpos]);
+
+                               callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
+
 #if defined(HAVE_PRI_CALL_HOLD)
                                sig_pri_handle_subcmds(pri, chanpos, e->e, e->notify.subcmds,
                                        e->notify.call);
@@ -7164,12 +7543,12 @@ static void *pri_dchannel(void *vpri)
                                switch (e->notify.info) {
                                case PRI_NOTIFY_REMOTE_HOLD:
                                        if (!pri->discardremoteholdretrieval) {
-                                               pri_queue_control(pri, chanpos, AST_CONTROL_HOLD);
+                                               sig_pri_queue_hold(pri, chanpos);
                                        }
                                        break;
                                case PRI_NOTIFY_REMOTE_RETRIEVAL:
                                        if (!pri->discardremoteholdretrieval) {
-                                               pri_queue_control(pri, chanpos, AST_CONTROL_UNHOLD);
+                                               sig_pri_queue_unhold(pri, chanpos);
                                        }
                                        break;
                                }
@@ -7221,6 +7600,11 @@ static void *pri_dchannel(void *vpri)
                                        pri->span, pri_event2str(e->e), e->e);
                                break;
                        }
+
+                       /* If a callid was set, we need to remove it from thread storage. */
+                       if (callid) {
+                               ast_callid_threadassoc_remove();
+                       }
                }
                ast_mutex_unlock(&pri->lock);
        }
@@ -7324,6 +7708,20 @@ int sig_pri_hangup(struct sig_pri_chan *p, struct ast_channel *ast)
                }
 #endif /* defined(SUPPORT_USERUSER) */
 
+#if defined(HAVE_PRI_TRANSFER)
+               if (p->xfer_data) {
+                       /*
+                        * The transferrer call leg is disconnecting.  It must mean that
+                        * the transfer was successful and the core is disconnecting the
+                        * call legs involved.
+                        *
+                        * The transfer protocol response message must go out before the
+                        * call leg is disconnected.
+                        */
+                       sig_pri_transfer_rsp(p->xfer_data, 1);
+               }
+#endif /* defined(HAVE_PRI_TRANSFER) */
+
 #if defined(HAVE_PRI_AOC_EVENTS)
                if (p->holding_aoce) {
                        pri_aoc_e_send(p->pri->pri, p->call, &p->aoc_e);
@@ -7352,6 +7750,9 @@ int sig_pri_hangup(struct sig_pri_chan *p, struct ast_channel *ast)
                        pri_hangup(p->pri->pri, p->call, icause);
                }
        }
+#if defined(HAVE_PRI_TRANSFER)
+       p->xfer_data = NULL;
+#endif /* defined(HAVE_PRI_TRANSFER) */
 #if defined(HAVE_PRI_AOC_EVENTS)
        p->aoc_s_request_invoke_id_valid = 0;
        p->holding_aoce = 0;
@@ -7491,10 +7892,11 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, const char *rd
        );
        struct ast_flags opts;
        char *opt_args[OPT_ARG_ARRAY_SIZE];
+       struct ast_party_id connected_id = ast_channel_connected_effective_id(ast);
 
        ast_debug(1, "CALLER NAME: %s NUM: %s\n",
-               S_COR(ast_channel_connected(ast)->id.name.valid, ast_channel_connected(ast)->id.name.str, ""),
-               S_COR(ast_channel_connected(ast)->id.number.valid, ast_channel_connected(ast)->id.number.str, ""));
+               S_COR(connected_id.name.valid, connected_id.name.str, ""),
+               S_COR(connected_id.number.valid, connected_id.number.str, ""));
 
        if (!p->pri) {
                ast_log(LOG_ERROR, "Could not find pri on channel %d\n", p->channel);
@@ -7550,14 +7952,14 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, const char *rd
        l = NULL;
        n = NULL;
        if (!p->hidecallerid) {
-               if (ast_channel_connected(ast)->id.number.valid) {
+               if (connected_id.number.valid) {
                        /* If we get to the end of this loop without breaking, there's no
                         * calleridnum.  This is done instead of testing for "unknown" or
                         * the thousands of other ways that the calleridnum could be
                         * invalid. */
-                       for (l = ast_channel_connected(ast)->id.number.str; l && *l; l++) {
+                       for (l = connected_id.number.str; l && *l; l++) {
                                if (strchr("0123456789", *l)) {
-                                       l = ast_channel_connected(ast)->id.number.str;
+                                       l = connected_id.number.str;
                                        break;
                                }
                        }
@@ -7565,7 +7967,7 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, const char *rd
                        l = NULL;
                }
                if (!p->hidecalleridname) {
-                       n = ast_channel_connected(ast)->id.name.valid ? ast_channel_connected(ast)->id.name.str : NULL;
+                       n = connected_id.name.valid ? connected_id.name.str : NULL;
                }
        }
 
@@ -7630,7 +8032,7 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, const char *rd
        if (p->pri->facilityenable)
                pri_facility_enable(p->pri->pri);
 
-       ast_verb(3, "Requested transfer capability: 0x%.2x - %s\n", ast_channel_transfercapability(ast), ast_transfercapability2str(ast_channel_transfercapability(ast)));
+       ast_verb(3, "Requested transfer capability: 0x%02hx - %s\n", ast_channel_transfercapability(ast), ast_transfercapability2str(ast_channel_transfercapability(ast)));
        dp_strip = 0;
        pridialplan = p->pri->dialplan - 1;
        if (pridialplan == -2 || pridialplan == -3) { /* compute dynamically */
@@ -7713,7 +8115,12 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, const char *rd
        if (!keypad || !ast_strlen_zero(c + p->stripmsd + dp_strip))
 #endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
        {
-               pri_sr_set_called(sr, c + p->stripmsd + dp_strip, pridialplan, s ? 1 : 0);
+               char *called = c + p->stripmsd + dp_strip;
+
+               pri_sr_set_called(sr, called, pridialplan, s ? 1 : 0);
+#if defined(HAVE_PRI_SETUP_ACK_INBAND)
+               p->no_dialed_digits = !called[0];
+#endif /* defined(HAVE_PRI_SETUP_ACK_INBAND) */
        }
 
 #if defined(HAVE_PRI_SUBADDR)
@@ -7781,7 +8188,7 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, const char *rd
                }
        } else if (prilocaldialplan == -1) {
                /* Use the numbering plan passed in. */
-               prilocaldialplan = ast_channel_connected(ast)->id.number.plan;
+               prilocaldialplan = connected_id.number.plan;
        }
        if (l != NULL) {
                while (*l > '9' && *l != '*' && *l != '#') {
@@ -7840,14 +8247,14 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, const char *rd
                }
        }
        pri_sr_set_caller(sr, l ? (l + ldp_strip) : NULL, n, prilocaldialplan,
-               p->use_callingpres ? ast_channel_connected(ast)->id.number.presentation : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE));
+               p->use_callingpres ? connected_id.number.presentation : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE));
 
 #if defined(HAVE_PRI_SUBADDR)
-       if (ast_channel_connected(ast)->id.subaddress.valid) {
+       if (connected_id.subaddress.valid) {
                struct pri_party_subaddress subaddress;
 
                memset(&subaddress, 0, sizeof(subaddress));
-               sig_pri_party_subaddress_from_ast(&subaddress, &ast_channel_connected(ast)->id.subaddress);
+               sig_pri_party_subaddress_from_ast(&subaddress, &connected_id.subaddress);
                pri_sr_set_caller_subaddress(sr, &subaddress);
        }
 #endif /* defined(HAVE_PRI_SUBADDR) */
@@ -7963,11 +8370,7 @@ int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condi
                        p->call_level = SIG_PRI_CALL_LEVEL_PROCEEDING;
                        if (p->pri && p->pri->pri) {
                                pri_grab(p, p->pri);
-                               pri_proceeding(p->pri->pri,p->call, PVT_TO_CHANNEL(p),
-                                       p->no_b_channel || p->digital ? 0 : 1);
-                               if (!p->no_b_channel && !p->digital) {
-                                       sig_pri_set_dialing(p, 0);
-                               }
+                               pri_proceeding(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 0);
                                pri_rel(p->pri);
                        }
                }
@@ -8078,6 +8481,7 @@ int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condi
                        int dialplan;
                        int prefix_strip;
                        int colp_allowed = 0;
+                       struct ast_party_id connected_id = ast_channel_connected_effective_id(chan);
 
                        pri_grab(p, p->pri);
 
@@ -8106,7 +8510,7 @@ int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condi
                        }
 
                        memset(&connected, 0, sizeof(connected));
-                       sig_pri_party_id_from_ast(&connected.id, &ast_channel_connected(chan)->id);
+                       sig_pri_party_id_from_ast(&connected.id, &connected_id);
 
                        /* Determine the connected line numbering plan to actually use. */
                        switch (p->pri->cpndialplan) {
@@ -8177,16 +8581,18 @@ int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condi
                                        if (p->pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_E) {
                                                sig_pri_aoc_e_from_ast(p, decoded);
                                        }
-                                       /* if hangup was delayed for this AOC-E msg, waiting_for_aoc
+                                       /*
+                                        * If hangup was delayed for this AOC-E msg, waiting_for_aoc
                                         * will be set.  A hangup is already occuring via a timeout during
                                         * this delay.  Instead of waiting for that timeout to occur, go ahead
-                                        * and initiate the softhangup since the delay is no longer necessary */
+                                        * and initiate the hangup since the delay is no longer necessary.
+                                        */
                                        if (p->waiting_for_aoce) {
                                                p->waiting_for_aoce = 0;
                                                ast_debug(1,
                                                        "Received final AOC-E msg, continue with hangup on %s\n",
                                                        ast_channel_name(chan));
-                                               ast_softhangup_nolock(chan, AST_SOFTHANGUP_DEV);
+                                               ast_queue_hangup(chan);
                                        }
                                        break;
                                case AST_AOC_REQUEST:
@@ -8389,7 +8795,7 @@ int sig_pri_digit_begin(struct sig_pri_chan *pvt, struct ast_channel *ast, char
                }
                if (pvt->call_level < SIG_PRI_CALL_LEVEL_CONNECT) {
                        ast_log(LOG_WARNING,
-                               "Span %d: Digit '%c' may be ignored by peer. (Call level:%d(%s))\n",
+                               "Span %d: Digit '%c' may be ignored by peer. (Call level:%u(%s))\n",
                                pvt->pri->span, digit, pvt->call_level,
                                sig_pri_call_level2str(pvt->call_level));
                }
@@ -8418,8 +8824,8 @@ void sig_pri_dial_complete(struct sig_pri_chan *pvt, struct ast_channel *ast)
                {
                        struct ast_frame f = {AST_FRAME_CONTROL, };
 
-                       if (pvt->calls->queue_control) {
-                               pvt->calls->queue_control(pvt->chan_pvt, AST_CONTROL_ANSWER);
+                       if (sig_pri_callbacks.queue_control) {
+                               sig_pri_callbacks.queue_control(pvt->chan_pvt, AST_CONTROL_ANSWER);
                        }
 
                        f.subclass.integer = AST_CONTROL_ANSWER;
@@ -8439,25 +8845,25 @@ void sig_pri_dial_complete(struct sig_pri_chan *pvt, struct ast_channel *ast)
  *
  * \param pri PRI span control structure.
  * \param vm_number Voicemail controlling number (NULL if not present).
- * \param mbox_number Mailbox number
- * \param mbox_context Mailbox context
+ * \param vm_box Voicemail mailbox number
+ * \param mbox_id Mailbox id
  * \param num_messages Number of messages waiting.
  *
  * \return Nothing
  */
-static void sig_pri_send_mwi_indication(struct sig_pri_span *pri, const char *vm_number, const char *mbox_number, const char *mbox_context, int num_messages)
+static void sig_pri_send_mwi_indication(struct sig_pri_span *pri, const char *vm_number, const char *vm_box, const char *mbox_id, int num_messages)
 {
        struct pri_party_id voicemail;
        struct pri_party_id mailbox;
 
-       ast_debug(1, "Send MWI indication for %s@%s vm_number:%s num_messages:%d\n",
-               mbox_number, mbox_context, S_OR(vm_number, "<not-present>"), num_messages);
+       ast_debug(1, "Send MWI indication for %s(%s) vm_number:%s num_messages:%d\n",
+               vm_box, mbox_id, S_OR(vm_number, "<not-present>"), num_messages);
 
        memset(&mailbox, 0, sizeof(mailbox));
        mailbox.number.valid = 1;
        mailbox.number.presentation = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
        mailbox.number.plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_UNKNOWN;
-       ast_copy_string(mailbox.number.str, mbox_number, sizeof(mailbox.number.str));
+       ast_copy_string(mailbox.number.str, vm_box, sizeof(mailbox.number.str));
 
        memset(&voicemail, 0, sizeof(voicemail));
        voicemail.number.valid = 1;
@@ -8484,39 +8890,35 @@ static void sig_pri_send_mwi_indication(struct sig_pri_span *pri, const char *vm
  * \brief MWI subscription event callback.
  * \since 1.8
  *
- * \param event the event being passed to the subscriber
- * \param userdata the data provider in the call to ast_event_subscribe()
+ * \param userdata the data provider in the call to stasis_subscribe()
+ * \param sub the subscription to which the message was delivered for this callback
+ * \param topic the topic on which the message was published
+ * \param msg the message being passed to the subscriber
  *
  * \return Nothing
  */
-static void sig_pri_mwi_event_cb(const struct ast_event *event, void *userdata)
+static void sig_pri_mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 {
        struct sig_pri_span *pri = userdata;
-       const char *mbox_context;
-       const char *mbox_number;
-       int num_messages;
        int idx;
+       struct ast_mwi_state *mwi_state;
 
-       mbox_number = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
-       if (ast_strlen_zero(mbox_number)) {
+       if (ast_mwi_state_type() != stasis_message_type(msg)) {
                return;
        }
-       mbox_context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
-       if (ast_strlen_zero(mbox_context)) {
-               return;
-       }
-       num_messages = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
+
+       mwi_state = stasis_message_data(msg);
 
        for (idx = 0; idx < ARRAY_LEN(pri->mbox); ++idx) {
                if (!pri->mbox[idx].sub) {
                        /* Mailbox slot is empty */
                        continue;
                }
-               if (!strcmp(pri->mbox[idx].number, mbox_number)
-                       && !strcmp(pri->mbox[idx].context, mbox_context)) {
+
+               if (!strcmp(pri->mbox[idx].uniqueid, mwi_state->uniqueid)) {
                        /* Found the mailbox. */
-                       sig_pri_send_mwi_indication(pri, pri->mbox[idx].vm_number, mbox_number,
-                               mbox_context, num_messages);
+                       sig_pri_send_mwi_indication(pri, pri->mbox[idx].vm_number,
+                               pri->mbox[idx].vm_box, pri->mbox[idx].uniqueid, mwi_state->new_msgs);
                        break;
                }
        }
@@ -8536,27 +8938,25 @@ static void sig_pri_mwi_event_cb(const struct ast_event *event, void *userdata)
 static void sig_pri_mwi_cache_update(struct sig_pri_span *pri)
 {
        int idx;
-       int num_messages;
-       struct ast_event *event;
+       struct ast_mwi_state *mwi_state;
 
        for (idx = 0; idx < ARRAY_LEN(pri->mbox); ++idx) {
+               RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
                if (!pri->mbox[idx].sub) {
                        /* Mailbox slot is empty */
                        continue;
                }
 
-               event = ast_event_get_cached(AST_EVENT_MWI,
-                       AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, pri->mbox[idx].number,
-                       AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, pri->mbox[idx].context,
-                       AST_EVENT_IE_END);
-               if (!event) {
+               msg = stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(),
+                       pri->mbox[idx].uniqueid);
+               if (!msg) {
                        /* No cached event for this mailbox. */
                        continue;
                }
-               num_messages = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
-               sig_pri_send_mwi_indication(pri, pri->mbox[idx].vm_number, pri->mbox[idx].number,
-                       pri->mbox[idx].context, num_messages);
-               ast_event_destroy(event);
+
+               mwi_state = stasis_message_data(msg);
+               sig_pri_send_mwi_indication(pri, pri->mbox[idx].vm_number, pri->mbox[idx].vm_box,
+                       pri->mbox[idx].uniqueid, mwi_state->new_msgs);
        }
 }
 #endif /* defined(HAVE_PRI_MWI) */
@@ -8578,7 +8978,7 @@ void sig_pri_stop_pri(struct sig_pri_span *pri)
 #if defined(HAVE_PRI_MWI)
        for (idx = 0; idx < ARRAY_LEN(pri->mbox); ++idx) {
                if (pri->mbox[idx].sub) {
-                       pri->mbox[idx].sub = ast_event_unsubscribe(pri->mbox[idx].sub);
+                       pri->mbox[idx].sub = stasis_unsubscribe_and_join(pri->mbox[idx].sub);
                }
        }
 #endif /* defined(HAVE_PRI_MWI) */
@@ -8641,14 +9041,13 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
 #if defined(HAVE_PRI_MWI)
        char *saveptr;
        char *prev_vm_number;
-       struct ast_str *mwi_description = ast_str_alloca(64);
 #endif /* defined(HAVE_PRI_MWI) */
 
 #if defined(HAVE_PRI_MWI)
        /* Prepare the mbox[] for use. */
        for (i = 0; i < ARRAY_LEN(pri->mbox); ++i) {
                if (pri->mbox[i].sub) {
-                       pri->mbox[i].sub = ast_event_unsubscribe(pri->mbox[i].sub);
+                       pri->mbox[i].sub = stasis_unsubscribe(pri->mbox[i].sub);
                }
        }
 #endif /* defined(HAVE_PRI_MWI) */
@@ -8681,53 +9080,61 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
        }
 
        /*
-        * Split the mwi_mailboxes configuration string into the mbox[]:
-        * mailbox_number[@context]{,mailbox_number[@context]}
+        * Split the mwi_vm_boxes configuration string into the mbox[].vm_box:
+        * vm_box{,vm_box}
         */
-       saveptr = pri->mwi_mailboxes;
+       saveptr = pri->mwi_vm_boxes;
        for (i = 0; i < ARRAY_LEN(pri->mbox); ++i) {
-               char *mbox_number;
-               char *mbox_context;
+               char *vm_box;
 
-               mbox_number = strsep(&saveptr, ",");
-               if (!mbox_number) {
-                       /* No more defined mailboxes. */
-                       break;
+               vm_box = strsep(&saveptr, ",");
+               if (vm_box) {
+                       vm_box = ast_strip(vm_box);
+                       if (ast_strlen_zero(vm_box)) {
+                               vm_box = NULL;
+                       }
                }
-               /* Split the mailbox_number and context */
-               mbox_context = strchr(mbox_number, '@');
-               if (mbox_context) {
-                       *mbox_context++ = '\0';
-                       mbox_context = ast_strip(mbox_context);
+               pri->mbox[i].vm_box = vm_box;
+       }
+
+       /*
+        * Split the mwi_mailboxes configuration string into the mbox[]:
+        * vm_mailbox{,vm_mailbox}
+        */
+       saveptr = pri->mwi_mailboxes;
+       for (i = 0; i < ARRAY_LEN(pri->mbox); ++i) {
+               char *mbox_id;
+               struct stasis_topic *mailbox_specific_topic;
+
+               mbox_id = strsep(&saveptr, ",");
+               if (mbox_id) {
+                       mbox_id = ast_strip(mbox_id);
+                       if (ast_strlen_zero(mbox_id)) {
+                               mbox_id = NULL;
+                       }
                }
-               mbox_number = ast_strip(mbox_number);
-               if (ast_strlen_zero(mbox_number)) {
-                       /* There is no mailbox number.  Skip it. */
+               pri->mbox[i].uniqueid = mbox_id;
+               if (!pri->mbox[i].vm_box || !mbox_id) {
+                       /* The mailbox position is disabled. */
+                       ast_debug(1, "%s span %d MWI position %d disabled.  vm_box:%s mbox_id:%s.\n",
+                               sig_pri_cc_type_name, pri->span, i,
+                               pri->mbox[i].vm_box ?: "<missing>",
+                               mbox_id ?: "<missing>");
                        continue;
                }
-               if (ast_strlen_zero(mbox_context)) {
-                       /* There was no context so use the default. */
-                       mbox_context = "default";
-               }
-
-               /* Fill the mbox[] element. */
-               pri->mbox[i].number = mbox_number;
-               pri->mbox[i].context = mbox_context;
-               ast_str_set(&mwi_description, -1, "%s span %d[%d] MWI mailbox %s@%s",
-                       sig_pri_cc_type_name, pri->span, i, mbox_number, mbox_context);
-               pri->mbox[i].sub = ast_event_subscribe(AST_EVENT_MWI, sig_pri_mwi_event_cb,
-                       ast_str_buffer(mwi_description), pri,
-                       AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mbox_number,
-                       AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, mbox_context,
-                       AST_EVENT_IE_END);
+
+               mailbox_specific_topic = ast_mwi_topic(mbox_id);
+               if (mailbox_specific_topic) {
+                       pri->mbox[i].sub = stasis_subscribe_pool(mailbox_specific_topic, sig_pri_mwi_event_cb, pri);
+               }
                if (!pri->mbox[i].sub) {
-                       ast_log(LOG_ERROR, "%s span %d could not subscribe to MWI events for %s@%s.",
-                               sig_pri_cc_type_name, pri->span, mbox_number, mbox_context);
+                       ast_log(LOG_ERROR, "%s span %d could not subscribe to MWI events for %s(%s).\n",
+                               sig_pri_cc_type_name, pri->span, pri->mbox[i].vm_box, mbox_id);
                }
 #if defined(HAVE_PRI_MWI_V2)
                if (ast_strlen_zero(pri->mbox[i].vm_number)) {
-                       ast_log(LOG_WARNING, "%s span %d MWI voicemail number for %s@%s is empty.\n",
-                               sig_pri_cc_type_name, pri->span, mbox_number, mbox_context);
+                       ast_log(LOG_WARNING, "%s span %d MWI voicemail number for %s(%s) is empty.\n",
+                               sig_pri_cc_type_name, pri->span, pri->mbox[i].vm_box, mbox_id);
                }
 #endif /* defined(HAVE_PRI_MWI_V2) */
        }
@@ -8856,7 +9263,7 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
  *
  * \param p Channel private pointer.
  * \param noalarm Non-zero if not in alarm mode.
- * 
+ *
  * \note Assumes the sig_pri_lock_private(p) is already obtained.
  *
  * \return Nothing
@@ -8892,7 +9299,7 @@ int sig_pri_is_alarm_ignored(struct sig_pri_span *pri)
        return pri->layer1_ignored;
 }
 
-struct sig_pri_chan *sig_pri_chan_new(void *pvt_data, struct sig_pri_callback *callback, struct sig_pri_span *pri, int logicalspan, int channo, int trunkgroup)
+struct sig_pri_chan *sig_pri_chan_new(void *pvt_data, struct sig_pri_span *pri, int logicalspan, int channo, int trunkgroup)
 {
        struct sig_pri_chan *p;
 
@@ -8904,7 +9311,6 @@ struct sig_pri_chan *sig_pri_chan_new(void *pvt_data, struct sig_pri_callback *c
        p->prioffset = channo;
        p->mastertrunkgroup = trunkgroup;
 
-       p->calls = callback;
        p->chan_pvt = pvt_data;
 
        p->pri = pri;
@@ -9015,7 +9421,7 @@ void sig_pri_cli_show_span(int fd, int *dchannels, struct sig_pri_span *pri)
                        info_str = pri_dump_info_str(pri->pri);
                        if (info_str) {
                                ast_cli(fd, "%s", info_str);
-                               free(info_str);
+                               ast_std_free(info_str);
                        }
 #else
                        pri_dump_info(pri->pri);
@@ -9716,6 +10122,12 @@ void sig_pri_cc_monitor_destructor(void *monitor_pvt)
  */
 int sig_pri_load(const char *cc_type_name)
 {
+#if defined(HAVE_PRI_MCID)
+       if (STASIS_MESSAGE_TYPE_INIT(mcid_type)) {
+               return -1;
+       }
+#endif /* defined(HAVE_PRI_MCID) */
+
 #if defined(HAVE_PRI_CCSS)
        sig_pri_cc_type_name = cc_type_name;
        sig_pri_cc_monitors = ao2_container_alloc(37, sig_pri_cc_monitor_instance_hash_fn,
@@ -9741,6 +10153,10 @@ void sig_pri_unload(void)
                sig_pri_cc_monitors = NULL;
        }
 #endif /* defined(HAVE_PRI_CCSS) */
+
+#if defined(HAVE_PRI_MCID)
+       STASIS_MESSAGE_TYPE_CLEANUP(mcid_type);
+#endif /* defined(HAVE_PRI_MCID) */
 }
 
 #endif /* HAVE_PRI */