INFO/Record request configurable to use dynamic features
[asterisk/asterisk.git] / channels / chan_sip.c
index 47e3fe7..99fb9b0 100644 (file)
  *       channel variable in the dialplan.
  * get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req)
  *     - As above, if we have a SIPS: uri in the refer-to header
- *     - Does not check transport in refer_to uri.
+ *     - Does not check transport in refer_to uri.
  */
 
 /*** MODULEINFO
@@ -276,6 +276,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/xml.h"
 #include "sip/include/dialog.h"
 #include "sip/include/dialplan_functions.h"
+#include "sip/include/security_events.h"
 
 
 /*** DOCUMENTATION
@@ -340,7 +341,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
        </application>
        <function name="SIP_HEADER" language="en_US">
                <synopsis>
-                       Gets the specified SIP header.
+                       Gets the specified SIP header from an incoming INVITE message.
                </synopsis>
                <syntax>
                        <parameter name="name" required="true" />
@@ -352,6 +353,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>Since there are several headers (such as Via) which can occur multiple
                        times, SIP_HEADER takes an optional second argument to specify which header with
                        that name to retrieve. Headers start at offset <literal>1</literal>.</para>
+                       <para>Please observe that contents of the SDP (an attachment to the 
+                       SIP request) can't be accessed with this function.</para>
                </description>
        </function>
        <function name="SIPPEER" language="en_US">
@@ -363,7 +366,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <parameter name="item">
                                <enumlist>
                                        <enum name="ip">
-                                               <para>(default) The ip address.</para>
+                                               <para>(default) The IP address.</para>
                                        </enum>
                                        <enum name="port">
                                                <para>The port number.</para>
@@ -399,7 +402,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                                <para>Status (if qualify=yes).</para>
                                        </enum>
                                        <enum name="regexten">
-                                               <para>Registration extension.</para>
+                                               <para>Extension activated at registration.</para>
                                        </enum>
                                        <enum name="limit">
                                                <para>Call limit (call-limit).</para>
@@ -417,7 +420,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                                <para>Account code for this peer.</para>
                                        </enum>
                                        <enum name="useragent">
-                                               <para>Current user agent id for peer.</para>
+                                               <para>Current user agent header used by peer.</para>
                                        </enum>
                                        <enum name="maxforwards">
                                                <para>The value used for SIP loop prevention in outbound requests</para>
@@ -447,13 +450,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                                <para>The source IP address of the peer.</para>
                                        </enum>
                                        <enum name="from">
-                                               <para>The URI from the <literal>From:</literal> header.</para>
+                                               <para>The SIP URI from the <literal>From:</literal> header.</para>
                                        </enum>
                                        <enum name="uri">
-                                               <para>The URI from the <literal>Contact:</literal> header.</para>
+                                               <para>The SIP URI from the <literal>Contact:</literal> header.</para>
                                        </enum>
                                        <enum name="useragent">
-                                               <para>The useragent.</para>
+                                               <para>The Useragent header used by the peer.</para>
                                        </enum>
                                        <enum name="peername">
                                                <para>The name of the peer.</para>
@@ -490,8 +493,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                </syntax>
                <description>
                        <para>Lists SIP peers in text format with details on current status.
-                       Peerlist will follow as separate events, followed by a final event called
-                       PeerlistComplete.</para>
+                       <literal>Peerlist</literal> will follow as separate events, followed by a final event called
+                       <literal>PeerlistComplete</literal>.</para>
                </description>
        </manager>
        <manager name="SIPshowpeer" language="en_US">
@@ -531,7 +534,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                </syntax>
                <description>
                        <para>Lists all registration requests and status. Registrations will follow as separate
-                       events. followed by a final event called RegistrationsComplete.</para>
+                       events followed by a final event called <literal>RegistrationsComplete</literal>.</para>
                </description>
        </manager>
        <manager name="SIPnotify" language="en_US">
@@ -551,7 +554,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                <description>
                        <para>Sends a SIP Notify event.</para>
                        <para>All parameters for this event must be specified in the body of this request
-                       via multiple Variable: name=value sequences.</para>
+                       via multiple <literal>Variable: name=value</literal> sequences.</para>
                </description>
        </manager>
  ***/
@@ -692,6 +695,7 @@ static char default_parkinglot[AST_MAX_CONTEXT];   /*!< Parkinglot */
 static char default_engine[256];                   /*!< Default RTP engine */
 static int default_maxcallbitrate;                 /*!< Maximum bitrate for call */
 static struct ast_codec_pref default_prefs;        /*!< Default codec prefs */
+static char default_zone[MAX_TONEZONE_COUNTRY];        /*!< Default tone zone for channels created from the SIP driver */
 static unsigned int default_transports;            /*!< Default Transports (enum sip_transport) that are acceptable */
 static unsigned int default_primary_transport;     /*!< Default primary Transport (enum sip_transport) for outbound connections to devices */
 /*@}*/
@@ -746,6 +750,8 @@ static enum st_refresher global_st_refresher; /*!< Session-Timer refresher
 static int global_min_se;                     /*!< Lowest threshold for session refresh interval  */
 static int global_max_se;                     /*!< Highest threshold for session refresh interval */
 
+static int global_store_sip_cause;    /*!< Whether the MASTER_CHANNEL(HASH(SIP_CAUSE,[chan_name])) var should be set */
+
 static int global_dynamic_exclude_static = 0; /*!< Exclude static peers from contact registrations */
 /*@}*/
 
@@ -1072,21 +1078,24 @@ static void destroy_escs(void)
        }
 }
 
-/*! \brief
+/*!
+ * \details
  * Here we implement the container for dialogs which are in the
  * dialog_needdestroy state to iterate only through the dialogs
  * unlink them instead of iterate through all dialogs
  */
 struct ao2_container *dialogs_needdestroy;
 
-/*! \brief
+/*!
+ * \details
  * Here we implement the container for dialogs which have rtp
  * traffic and rtptimeout, rtpholdtimeout or rtpkeepalive
  * set. We use this container instead the whole dialog list.
  */
 struct ao2_container *dialogs_rtpcheck;
 
-/*! \brief
+/*!
+ * \details
  * Here we implement the container for dialogs (sip_pvt), defining
  * generic wrapper functions to ease the transition from the current
  * implementation (a single linked list) to a different container.
@@ -1176,7 +1185,7 @@ static struct ast_sockaddr media_address; /*!< External RTP IP address if we are
 static char externhost[MAXHOSTNAMELEN];   /*!< External host name */
 static time_t externexpire;             /*!< Expiration counter for re-resolving external host name in dynamic DNS */
 static int externrefresh = 10;          /*!< Refresh timer for DNS-based external address (dyndns) */
-static uint16_t externtcpport;          /*!< external tcp port */ 
+static uint16_t externtcpport;          /*!< external tcp port */
 static uint16_t externtlsport;          /*!< external tls port */
 
 /*! \brief  List of local networks
@@ -1267,7 +1276,7 @@ static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittyp
 static void copy_request(struct sip_request *dst, const struct sip_request *src);
 static void receive_message(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e);
 static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char **name, char **number, int set_call_forward);
-static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *event, int cache_only);
+static int sip_send_mwi_to_peer(struct sip_peer *peer, int cache_only);
 
 /* Misc dialog routines */
 static int __sip_autodestruct(const void *data);
@@ -1283,7 +1292,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
 static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag);
 static void check_pendings(struct sip_pvt *p);
 static void *sip_park_thread(void *stuff);
-static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno, char *parkexten);
+static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno, const char *park_exten, const char *park_context);
 
 static void *sip_pickup_thread(void *stuff);
 static int sip_pickup(struct ast_channel *chan);
@@ -1335,14 +1344,16 @@ static void add_realm_authentication(struct sip_auth_container **credentials, co
 static struct sip_auth *find_realm_authentication(struct sip_auth_container *credentials, const char *realm);
 
 /*--- Misc functions */
-static void check_rtp_timeout(struct sip_pvt *dialog, time_t t);
+static int check_rtp_timeout(struct sip_pvt *dialog, time_t t);
 static int reload_config(enum channelreloadreason reason);
+static void add_diversion_header(struct sip_request *req, struct sip_pvt *pvt);
 static int expire_register(const void *data);
 static void *do_monitor(void *data);
 static int restart_monitor(void);
 static void peer_mailboxes_to_str(struct ast_str **mailbox_str, struct sip_peer *peer);
 static struct ast_variable *copy_vars(struct ast_variable *src);
 static int dialog_find_multiple(void *obj, void *arg, int flags);
+static struct ast_channel *sip_pvt_lock_full(struct sip_pvt *pvt);
 /* static int sip_addrcmp(char *name, struct sockaddr_in *sin);        Support for peer matching */
 static int sip_refer_allocate(struct sip_pvt *p);
 static int sip_notify_allocate(struct sip_pvt *p);
@@ -1373,6 +1384,7 @@ static void  print_group(int fd, ast_group_t group, int crlf);
 static const char *dtmfmode2str(int mode) attribute_const;
 static int str2dtmfmode(const char *str) attribute_unused;
 static const char *insecure2str(int mode) attribute_const;
+static const char *allowoverlap2str(int mode) attribute_const;
 static void cleanup_stale_contexts(char *new, char *old);
 static void print_codec_to_cli(int fd, struct ast_codec_pref *pref);
 static const char *domain_mode_to_text(const enum domain_mode mode);
@@ -1428,7 +1440,6 @@ static void sip_destroy_peer_fn(void *peer);
 static void set_peer_defaults(struct sip_peer *peer);
 static struct sip_peer *temp_peer(const char *name);
 static void register_peer_exten(struct sip_peer *peer, int onoff);
-static struct sip_peer *find_peer(const char *peer, struct ast_sockaddr *addr, int realtime, int forcenamematch, int devstate_only, int transport);
 static int sip_poke_peer_s(const void *data);
 static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_request *req);
 static void reg_source_db(struct sip_peer *peer);
@@ -1441,7 +1452,7 @@ static void set_socket_transport(struct sip_socket *socket, int transport);
 static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *username, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms);
 static void update_peer(struct sip_peer *p, int expire);
 static struct ast_variable *get_insecure_variable_from_config(struct ast_config *config);
-static const char *get_name_from_variable(struct ast_variable *var, const char *newpeername);
+static const char *get_name_from_variable(const struct ast_variable *var);
 static struct sip_peer *realtime_peer(const char *peername, struct ast_sockaddr *sin, int devstate_only, int which_objects);
 static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 
@@ -1465,7 +1476,6 @@ static int find_sip_method(const char *msg);
 static unsigned int parse_allowed_methods(struct sip_request *req);
 static unsigned int set_pvt_allowed_methods(struct sip_pvt *pvt, struct sip_request *req);
 static int parse_request(struct sip_request *req);
-static const char *get_header(const struct sip_request *req, const char *name);
 static const char *referstatus2str(enum referstatus rstatus) attribute_pure;
 static int method_match(enum sipmethod id, const char *name);
 static void parse_copy(struct sip_request *dst, const struct sip_request *src);
@@ -1482,7 +1492,7 @@ static void check_via(struct sip_pvt *p, struct sip_request *req);
 static int get_rpid(struct sip_pvt *p, struct sip_request *oreq);
 static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason);
 static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id);
-static int get_msg_text(char *buf, int len, struct sip_request *req, int addnewline);
+static int get_msg_text(char *buf, int len, struct sip_request *req);
 static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout);
 static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen);
 static void update_redirecting(struct sip_pvt *p, const void *data, size_t datalen);
@@ -1508,6 +1518,7 @@ static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer);
 static int create_addr(struct sip_pvt *dialog, const char *opeer, struct ast_sockaddr *addr, int newdialog, struct ast_sockaddr *remote_address);
 static char *generate_random_string(char *buf, size_t size);
 static void build_callid_pvt(struct sip_pvt *pvt);
+static void change_callid_pvt(struct sip_pvt *pvt, const char *callid);
 static void build_callid_registry(struct sip_registry *reg, const struct ast_sockaddr *ourip, const char *fromdomain);
 static void make_our_tag(char *tagbuf, size_t len);
 static int add_header(struct sip_request *req, const char *var, const char *value);
@@ -1622,6 +1633,7 @@ struct ast_channel_tech sip_tech = {
  */
 struct ast_channel_tech sip_tech_info;
 
+/*------- CC Support -------- */
 static int sip_cc_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan);
 static int sip_cc_agent_start_offer_timer(struct ast_cc_agent *agent);
 static int sip_cc_agent_stop_offer_timer(struct ast_cc_agent *agent);
@@ -2058,7 +2070,7 @@ static void sip_cc_monitor_destructor(void *private_data)
 
 static int sip_get_cc_information(struct sip_request *req, char *subscribe_uri, size_t size, enum ast_cc_service_type *service)
 {
-       char *call_info = ast_strdupa(get_header(req, "Call-Info"));
+       char *call_info = ast_strdupa(sip_get_header(req, "Call-Info"));
        char *uri;
        char *purpose;
        char *service_str;
@@ -2302,18 +2314,18 @@ static const char *sip_reason_code_to_str(enum AST_REDIRECTING_REASON code)
        else if (!(peer->transports & tmpl->socket.type)) {\
                ast_log(LOG_ERROR, \
                        "'%s' is not a valid transport for '%s'. we only use '%s'! ending call.\n", \
-                       get_transport(tmpl->socket.type), peer->name, get_transport_list(peer->transports) \
+                       sip_get_transport(tmpl->socket.type), peer->name, get_transport_list(peer->transports) \
                        ); \
                ret = 1; \
        } else if (peer->socket.type & SIP_TRANSPORT_TLS) { \
                ast_log(LOG_WARNING, \
                        "peer '%s' HAS NOT USED (OR SWITCHED TO) TLS in favor of '%s' (but this was allowed in sip.conf)!\n", \
-                       peer->name, get_transport(tmpl->socket.type) \
+                       peer->name, sip_get_transport(tmpl->socket.type) \
                ); \
        } else { \
                ast_debug(1, \
                        "peer '%s' has contacted us over %s even though we prefer %s.\n", \
-                       peer->name, get_transport(tmpl->socket.type), get_transport(peer->socket.type) \
+                       peer->name, sip_get_transport(tmpl->socket.type), sip_get_transport(peer->socket.type) \
                ); \
        }\
        (ret); \
@@ -2689,7 +2701,7 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
                        copy_request(&reqcpy, &req);
                        parse_request(&reqcpy);
                        /* In order to know how much to read, we need the content-length header */
-                       if (sscanf(get_header(&reqcpy, "Content-Length"), "%30d", &cl)) {
+                       if (sscanf(sip_get_header(&reqcpy, "Content-Length"), "%30d", &cl)) {
                                while (cl > 0) {
                                        size_t bytes_read;
                                        if (!tcptls_session->client && !authenticated ) {
@@ -2801,14 +2813,7 @@ cleanup:
 
        if (tcptls_session) {
                ast_mutex_lock(&tcptls_session->lock);
-               if (tcptls_session->f) {
-                       fclose(tcptls_session->f);
-                       tcptls_session->f = NULL;
-               }
-               if (tcptls_session->fd != -1) {
-                       close(tcptls_session->fd);
-                       tcptls_session->fd = -1;
-               }
+               ast_tcptls_close_session_file(tcptls_session);
                tcptls_session->parent = NULL;
                ast_mutex_unlock(&tcptls_session->lock);
 
@@ -2819,8 +2824,8 @@ cleanup:
 }
 
 #ifdef REF_DEBUG
-#define ref_peer(arg1,arg2) _ref_peer((arg1),(arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define unref_peer(arg1,arg2) _unref_peer((arg1),(arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define sip_ref_peer(arg1,arg2) _ref_peer((arg1),(arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define sip_unref_peer(arg1,arg2) _unref_peer((arg1),(arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
 static struct sip_peer *_ref_peer(struct sip_peer *peer, char *tag, char *file, int line, const char *func)
 {
        if (peer)
@@ -2842,13 +2847,13 @@ static struct sip_peer *_unref_peer(struct sip_peer *peer, char *tag, char *file
  * By handling them this way, we don't have to declare the
  * destructor on each call, which removes the chance of errors.
  */
-static void *unref_peer(struct sip_peer *peer, char *tag)
+void *sip_unref_peer(struct sip_peer *peer, char *tag)
 {
        ao2_t_ref(peer, -1, tag);
        return NULL;
 }
 
-static struct sip_peer *ref_peer(struct sip_peer *peer, char *tag)
+struct sip_peer *sip_ref_peer(struct sip_peer *peer, char *tag)
 {
        ao2_t_ref(peer, 1, tag);
        return peer;
@@ -2859,11 +2864,11 @@ static void peer_sched_cleanup(struct sip_peer *peer)
 {
        if (peer->pokeexpire != -1) {
                AST_SCHED_DEL_UNREF(sched, peer->pokeexpire,
-                               unref_peer(peer, "removing poke peer ref"));
+                               sip_unref_peer(peer, "removing poke peer ref"));
        }
        if (peer->expire != -1) {
                AST_SCHED_DEL_UNREF(sched, peer->expire,
-                               unref_peer(peer, "remove register expire ref"));
+                               sip_unref_peer(peer, "remove register expire ref"));
        }
 }
 
@@ -2940,15 +2945,6 @@ static void ref_proxy(struct sip_pvt *pvt, struct sip_proxy *proxy)
        }
 }
 
- /*!
- * \brief Unlink a dialog from the dialogs_checkrtp container
- */
-static void *dialog_unlink_rtpcheck(struct sip_pvt *dialog)
-{
-       ao2_t_unlink(dialogs_rtpcheck, dialog, "unlinking dialog_rtpcheck via ao2_unlink");
-       return NULL;
-}
-
 /*!
  * \brief Unlink a dialog from the dialogs container, as well as any other places
  * that it may be currently stored.
@@ -2956,9 +2952,10 @@ static void *dialog_unlink_rtpcheck(struct sip_pvt *dialog)
  * \note A reference to the dialog must be held before calling this function, and this
  * function does not release that reference.
  */
-void *dialog_unlink_all(struct sip_pvt *dialog, int lockowner, int lockdialoglist)
+void dialog_unlink_all(struct sip_pvt *dialog)
 {
        struct sip_pkt *cp;
+       struct ast_channel *owner;
 
        dialog_ref(dialog, "Let's bump the count in the unlink so it doesn't accidentally become dead before we are done");
 
@@ -2967,26 +2964,25 @@ void *dialog_unlink_all(struct sip_pvt *dialog, int lockowner, int lockdialoglis
        ao2_t_unlink(dialogs_rtpcheck, dialog, "unlinking dialog_rtpcheck via ao2_unlink");
 
        /* Unlink us from the owner (channel) if we have one */
-       if (dialog->owner) {
-               if (lockowner) {
-                       ast_channel_lock(dialog->owner);
-               }
-               ast_debug(1, "Detaching from channel %s\n", dialog->owner->name);
-               dialog->owner->tech_pvt = dialog_unref(dialog->owner->tech_pvt, "resetting channel dialog ptr in unlink_all");
-               if (lockowner) {
-                       ast_channel_unlock(dialog->owner);
-               }
+       owner = sip_pvt_lock_full(dialog);
+       if (owner) {
+               ast_debug(1, "Detaching from channel %s\n", owner->name);
+               owner->tech_pvt = dialog_unref(owner->tech_pvt, "resetting channel dialog ptr in unlink_all");
+               ast_channel_unlock(owner);
+               ast_channel_unref(owner);
+               dialog->owner = NULL;
        }
+       sip_pvt_unlock(dialog);
+
        if (dialog->registry) {
                if (dialog->registry->call == dialog) {
                        dialog->registry->call = dialog_unref(dialog->registry->call, "nulling out the registry's call dialog field in unlink_all");
                }
                dialog->registry = registry_unref(dialog->registry, "delete dialog->registry");
        }
-       if (dialog->stateid > -1) {
-               ast_extension_state_del(dialog->stateid, NULL);
-               dialog_unref(dialog, "removing extension_state, should unref the associated dialog ptr that was stored there.");
-               dialog->stateid = -1; /* shouldn't we 'zero' this out? */
+       if (dialog->stateid != -1) {
+               ast_extension_state_del(dialog->stateid, cb_extensionstate);
+               dialog->stateid = -1;
        }
        /* Remove link from peer to subscription of MWI */
        if (dialog->relatedpeer && dialog->relatedpeer->mwipvt == dialog) {
@@ -3030,7 +3026,6 @@ void *dialog_unlink_all(struct sip_pvt *dialog, int lockowner, int lockdialoglis
        }
 
        dialog_unref(dialog, "Let's unbump the count in the unlink so the poor pvt can disappear if it is time");
-       return NULL;
 }
 
 void *registry_unref(struct sip_registry *reg, char *tag)
@@ -3069,15 +3064,15 @@ static inline void pvt_set_needdestroy(struct sip_pvt *pvt, const char *reason)
        if (pvt->final_destruction_scheduled) {
                return; /* This is already scheduled for final destruction, let the scheduler take care of it. */
        }
-       if(pvt->needdestroy != 1) {
+       append_history(pvt, "NeedDestroy", "Setting needdestroy because %s", reason);
+       if (!pvt->needdestroy) {
+               pvt->needdestroy = 1;
                ao2_t_link(dialogs_needdestroy, pvt, "link pvt into dialogs_needdestroy container");
        }
-       append_history(pvt, "NeedDestroy", "Setting needdestroy because %s", reason);
-       pvt->needdestroy = 1;
 }
 
 /*! \brief Initialize the initital request packet in the pvt structure.
-       This packet is used for creating replies and future requests in
+       This packet is used for creating replies and future requests in
        a dialog */
 static void initialize_initreq(struct sip_pvt *p, struct sip_request *req)
 {
@@ -3283,7 +3278,7 @@ static inline const char *get_transport_list(unsigned int transports) {
 }
 
 /*! \brief Return transport as string */
-static inline const char *get_transport(enum sip_transport t)
+const char *sip_get_transport(enum sip_transport t)
 {
        switch (t) {
        case SIP_TRANSPORT_UDP:
@@ -3336,7 +3331,7 @@ static inline const char *get_transport_pvt(struct sip_pvt *p)
                set_socket_transport(&p->socket, p->outboundproxy->transport);
        }
 
-       return get_transport(p->socket.type);
+       return sip_get_transport(p->socket.type);
 }
 
 /*!
@@ -3509,7 +3504,7 @@ static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_socka
        } else if (!ast_sockaddr_is_any(&bindaddr)) {
                ast_sockaddr_copy(us, &bindaddr);
        }
-       ast_debug(3, "Setting SIP_TRANSPORT_%s with address %s\n", get_transport(p->socket.type), ast_sockaddr_stringify(us));
+       ast_debug(3, "Setting SIP_TRANSPORT_%s with address %s\n", sip_get_transport(p->socket.type), ast_sockaddr_stringify(us));
 }
 
 /*! \brief Append to SIP dialog history with arg list  */
@@ -3846,6 +3841,7 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, int seqno, int res
 static int __sip_autodestruct(const void *data)
 {
        struct sip_pvt *p = (struct sip_pvt *)data;
+       struct ast_channel *owner;
 
        /* If this is a subscription, tell the phone that we got a timeout */
        if (p->subscribed && p->subscribed != MWI_NOTIFICATION && p->subscribed != CALL_COMPLETION) {
@@ -3881,17 +3877,12 @@ static int __sip_autodestruct(const void *data)
        /*
         * Lock both the pvt and the channel safely so that we can queue up a frame.
         */
-       sip_pvt_lock(p);
-       while (p->owner && ast_channel_trylock(p->owner)) {
-               sip_pvt_unlock(p);
-               sched_yield();
-               sip_pvt_lock(p);
-       }
-
-       if (p->owner) {
+       owner = sip_pvt_lock_full(p);
+       if (owner) {
                ast_log(LOG_WARNING, "Autodestruct on dialog '%s' with owner in place (Method: %s)\n", p->callid, sip_methods[p->method].text);
-               ast_queue_hangup_with_cause(p->owner, AST_CAUSE_PROTOCOL_ERROR);
-               ast_channel_unlock(p->owner);
+               ast_queue_hangup_with_cause(owner, AST_CAUSE_PROTOCOL_ERROR);
+               ast_channel_unlock(owner);
+               ast_channel_unref(owner);
        } else if (p->refer && !p->alreadygone) {
                ast_debug(3, "Finally hanging up channel after transfer: %s\n", p->callid);
                transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
@@ -3900,7 +3891,9 @@ static int __sip_autodestruct(const void *data)
        } else {
                append_history(p, "AutoDestroy", "%s", p->callid);
                ast_debug(3, "Auto destroying SIP dialog '%s'\n", p->callid);
-               dialog_unlink_all(p, TRUE, TRUE); /* once it's unlinked and unrefd everywhere, it'll be freed automagically */
+               sip_pvt_unlock(p);
+               dialog_unlink_all(p); /* once it's unlinked and unrefd everywhere, it'll be freed automagically */
+               sip_pvt_lock(p);
                /* dialog_unref(p, "unref dialog-- no other matching conditions"); -- unlink all now should finish off the dialog's references and free it. */
                /* sip_destroy(p); */           /* Go ahead and destroy dialog. All attempts to recover is done */
                /* sip_destroy also absorbs the reference */
@@ -4161,7 +4154,7 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmitty
        if (p->do_history) {
                struct sip_request tmp = { .rlPart1 = 0, };
                parse_copy(&tmp, req);
-               append_history(p, reliable ? "TxRespRel" : "TxResp", "%s / %s - %s", tmp.data->str, get_header(&tmp, "CSeq"),
+               append_history(p, reliable ? "TxRespRel" : "TxResp", "%s / %s - %s", tmp.data->str, sip_get_header(&tmp, "CSeq"),
                        (tmp.method == SIP_RESPONSE || tmp.method == SIP_UNKNOWN) ? REQ_OFFSET_TO_STR(&tmp, rlPart2) : sip_methods[tmp.method].text);
                deinit_req(&tmp);
        }
@@ -4209,7 +4202,7 @@ static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittyp
        if (p->do_history) {
                struct sip_request tmp = { .rlPart1 = 0, };
                parse_copy(&tmp, req);
-               append_history(p, reliable ? "TxReqRel" : "TxReq", "%s / %s - %s", tmp.data->str, get_header(&tmp, "CSeq"), sip_methods[tmp.method].text);
+               append_history(p, reliable ? "TxReqRel" : "TxReq", "%s / %s - %s", tmp.data->str, sip_get_header(&tmp, "CSeq"), sip_methods[tmp.method].text);
                deinit_req(&tmp);
        }
        res = (reliable) ?
@@ -4268,8 +4261,8 @@ static int sip_setoption(struct ast_channel *chan, int option, void *data, int d
        struct sip_pvt *p = chan->tech_pvt;
 
         if (!p) {
-               ast_log(LOG_ERROR, "Attempt to Ref a null pointer.  sip private structure is gone!\n");
-               return -1;
+               ast_log(LOG_ERROR, "Attempt to Ref a null pointer.  sip private structure is gone!\n");
+               return -1;
         }
 
        sip_pvt_lock(p);
@@ -4496,7 +4489,6 @@ static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr
        int realtimeregs = ast_check_realtime("sipregs");
 
        tablename = realtimeregs ? "sipregs" : "sippeers";
-       
 
        snprintf(str_lastms, sizeof(str_lastms), "%d", lastms);
        snprintf(regseconds, sizeof(regseconds), "%d", (int)nowtime);   /* Expiration time */
@@ -4512,7 +4504,7 @@ static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr
          *  must also add it to contrib/scripts/asterisk.ldap-schema,
          *  contrib/scripts/asterisk.ldif,
          *  and to configs/res_ldap.conf.sample as described in
-         *  bugs 15156 and 15895 
+         *  bugs 15156 and 15895
          */
        if (fc) {
                ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
@@ -4592,18 +4584,27 @@ static void sip_destroy_peer_fn(void *peer)
 static void sip_destroy_peer(struct sip_peer *peer)
 {
        ast_debug(3, "Destroying SIP peer %s\n", peer->name);
-       if (peer->outboundproxy)
+
+       /*
+        * Remove any mailbox event subscriptions for this peer before
+        * we destroy anything.  An event subscription callback may be
+        * happening right now.
+        */
+       clear_peer_mailboxes(peer);
+
+       if (peer->outboundproxy) {
                ao2_ref(peer->outboundproxy, -1);
-       peer->outboundproxy = NULL;
+               peer->outboundproxy = NULL;
+       }
 
        /* Delete it, it needs to disappear */
        if (peer->call) {
-               dialog_unlink_all(peer->call, TRUE, TRUE);
+               dialog_unlink_all(peer->call);
                peer->call = dialog_unref(peer->call, "peer->call is being unset");
        }
 
        if (peer->mwipvt) {     /* We have an active subscription, delete it */
-               dialog_unlink_all(peer->mwipvt, TRUE, TRUE);
+               dialog_unlink_all(peer->mwipvt);
                peer->mwipvt = dialog_unref(peer->mwipvt, "unreffing peer->mwipvt");
        }
 
@@ -4628,7 +4629,6 @@ static void sip_destroy_peer(struct sip_peer *peer)
        }
        if (peer->dnsmgr)
                ast_dnsmgr_release(peer->dnsmgr);
-       clear_peer_mailboxes(peer);
 
        if (peer->socket.tcptls_session) {
                ao2_ref(peer->socket.tcptls_session, -1);
@@ -4648,7 +4648,7 @@ static void update_peer(struct sip_peer *p, int expire)
        int rtcachefriends = ast_test_flag(&p->flags[1], SIP_PAGE2_RTCACHEFRIENDS);
        if (sip_cfg.peer_rtupdate &&
            (p->is_realtime || rtcachefriends)) {
-               realtime_update_peer(p->name, &p->addr, p->username, rtcachefriends ? p->fullcontact : NULL, p->useragent, expire, p->deprecated_username, p->lastms);
+               realtime_update_peer(p->name, &p->addr, p->username, p->fullcontact, p->useragent, expire, p->deprecated_username, p->lastms);
        }
 }
 
@@ -4669,177 +4669,280 @@ static struct ast_variable *get_insecure_variable_from_config(struct ast_config
        return var;
 }
 
-static const char *get_name_from_variable(struct ast_variable *var, const char *newpeername)
+static struct ast_variable *get_insecure_variable_from_sippeers(const char *column, const char *value)
 {
-       struct ast_variable *tmp;
-       for (tmp = var; tmp; tmp = tmp->next) {
-               if (!newpeername && !strcasecmp(tmp->name, "name"))
-                       newpeername = tmp->value;
+       struct ast_config *peerlist;
+       struct ast_variable *var = NULL;
+       if ((peerlist = ast_load_realtime_multientry("sippeers", column, value, "insecure LIKE", "%port%", SENTINEL))) {
+               if ((var = get_insecure_variable_from_config(peerlist))) {
+                       /* Must clone, because var will get freed along with
+                        * peerlist. */
+                       var = ast_variables_dup(var);
+               }
+               ast_config_destroy(peerlist);
        }
-       return newpeername;
+       return var;
 }
 
-/*! \brief  realtime_peer: Get peer from realtime storage
- * Checks the "sippeers" realtime family from extconfig.conf
- * Checks the "sipregs" realtime family from extconfig.conf if it's configured.
- * This returns a pointer to a peer and because we use build_peer, we can rest
- * assured that the refcount is bumped.
-*/
-static struct sip_peer *realtime_peer(const char *newpeername, struct ast_sockaddr *addr, int devstate_only, int which_objects)
+/* Yes.. the only column that makes sense to pass is "ipaddr", but for
+ * consistency's sake, we require the column name to be passed. As extra
+ * argument, we take a pointer to var. We already got the info, so we better
+ * return it and save the caller a query. If return value is nonzero, then *var
+ * is nonzero too (and the other way around). */
+static struct ast_variable *get_insecure_variable_from_sipregs(const char *column, const char *value, struct ast_variable **var)
 {
-       struct sip_peer *peer;
-       struct ast_variable *var = NULL;
        struct ast_variable *varregs = NULL;
-       struct ast_variable *tmp;
-       struct ast_config *peerlist = NULL;
-       char ipaddr[INET6_ADDRSTRLEN];
-       char portstring[6]; /*up to 5 digits plus null terminator*/
-       int realtimeregs = ast_check_realtime("sipregs");
+       struct ast_config *regs, *peers;
+       char *regscat;
+       const char *regname;
 
-       /* First check on peer name */
-       if (newpeername) {
-               if (realtimeregs)
-                       varregs = ast_load_realtime("sipregs", "name", newpeername, SENTINEL);
-
-               var = ast_load_realtime("sippeers", "name", newpeername, "host", "dynamic", SENTINEL);
-               if (!var && addr) {
-                       var = ast_load_realtime("sippeers", "name", newpeername, "host", ast_sockaddr_stringify_addr(addr), SENTINEL);
-               }
-               if (!var) {
-                       var = ast_load_realtime("sippeers", "name", newpeername, SENTINEL);
-                       /*!\note
-                        * If this one loaded something, then we need to ensure that the host
-                        * field matched.  The only reason why we can't have this as a criteria
-                        * is because we only have the IP address and the host field might be
-                        * set as a name (and the reverse PTR might not match).
-                        */
-                       if (var && addr) {
-                               for (tmp = var; tmp; tmp = tmp->next) {
-                                       if (!strcasecmp(tmp->name, "host")) {
-                                               struct ast_sockaddr *addrs = NULL;
-
-                                               if (ast_sockaddr_resolve(&addrs,
-                                                                        tmp->value,
-                                                                        PARSE_PORT_FORBID,
-                                                                        get_address_family_filter(&bindaddr)) <= 0 ||
-                                                   ast_sockaddr_cmp(&addrs[0], addr)) {
-                                                       /* No match */
-                                                       ast_variables_destroy(var);
-                                                       var = NULL;
+       if (!(regs = ast_load_realtime_multientry("sipregs", column, value, SENTINEL))) {
+               return NULL;
+       }
+
+       /* Load *all* peers that are probably insecure=port */
+       if (!(peers = ast_load_realtime_multientry("sippeers", "insecure LIKE", "%port%", SENTINEL))) {
+               ast_config_destroy(regs);
+               return NULL;
+       }
+
+       /* Loop over the sipregs that match IP address and attempt to find an
+        * insecure=port match to it in sippeers. */
+       regscat = NULL;
+       while ((regscat = ast_category_browse(regs, regscat)) && (regname = ast_variable_retrieve(regs, regscat, "name"))) {
+               char *peerscat;
+               const char *peername;
+
+               peerscat = NULL;
+               while ((peerscat = ast_category_browse(peers, peerscat)) && (peername = ast_variable_retrieve(peers, peerscat, "name"))) {
+                       if (!strcasecmp(regname, peername)) {
+                               /* Ensure that it really is insecure=port and
+                                * not something else. */
+                               const char *insecure = ast_variable_retrieve(peers, peerscat, "insecure");
+                               struct ast_flags flags = {0};
+                               set_insecure_flags(&flags, insecure, -1);
+                               if (ast_test_flag(&flags, SIP_INSECURE_PORT)) {
+                                       /* ENOMEM checks till the bitter end. */
+                                       if ((varregs = ast_variables_dup(ast_category_root(regs, regscat)))) {
+                                               if (!(*var = ast_variables_dup(ast_category_root(peers, peerscat)))) {
+                                                       ast_variables_destroy(varregs);
+                                                       varregs = NULL;
                                                }
-                                               ast_free(addrs);
-                                               break;
                                        }
+                                       goto done;
                                }
                        }
                }
        }
 
-       if (!var && addr) {     /* Then check on IP address for dynamic peers */
-               ast_copy_string(ipaddr, ast_sockaddr_stringify_addr(addr), sizeof(ipaddr));
-               ast_copy_string(portstring, ast_sockaddr_stringify_port(addr), sizeof(portstring));
-               var = ast_load_realtime("sippeers", "host", ipaddr, "port", portstring, SENTINEL);      /* First check for fixed IP hosts */
-               if (var) {
-                       if (realtimeregs) {
-                               newpeername = get_name_from_variable(var, newpeername);
-                               varregs = ast_load_realtime("sipregs", "name", newpeername, SENTINEL);
+done:
+       ast_config_destroy(regs);
+       ast_config_destroy(peers);
+       return varregs;
+}
+
+static const char *get_name_from_variable(const struct ast_variable *var)
+{
+       /* Don't expect this to return non-NULL. Both NULL and empty
+        * values can cause the option to get removed from the variable
+        * list. This is called on ast_variables gotten from both
+        * ast_load_realtime and ast_load_realtime_multientry.
+        * - ast_load_realtime removes options with empty values
+        * - ast_load_realtime_multientry does not!
+        * For consistent behaviour, we check for the empty name and
+        * return NULL instead. */
+       const struct ast_variable *tmp;
+       for (tmp = var; tmp; tmp = tmp->next) {
+               if (!strcasecmp(tmp->name, "name")) {
+                       if (!ast_strlen_zero(tmp->value)) {
+                               return tmp->value;
                        }
-               } else {
-                       if (realtimeregs)
-                               varregs = ast_load_realtime("sipregs", "ipaddr", ipaddr, "port", portstring, SENTINEL); /* Then check for registered hosts */
-                       else
-                               var = ast_load_realtime("sippeers", "ipaddr", ipaddr, "port", portstring, SENTINEL); /* Then check for registered hosts */
-                       if (varregs) {
-                               newpeername = get_name_from_variable(varregs, newpeername);
-                               var = ast_load_realtime("sippeers", "name", newpeername, SENTINEL);
-                       }
-               }
-               if (!var) { /*We couldn't match on ipaddress and port, so we need to check if port is insecure*/
-                       peerlist = ast_load_realtime_multientry("sippeers", "host", ipaddr, SENTINEL);
-                       if (peerlist) {
-                               var = get_insecure_variable_from_config(peerlist);
-                               if(var) {
-                                       if (realtimeregs) {
-                                               newpeername = get_name_from_variable(var, newpeername);
-                                               varregs = ast_load_realtime("sipregs", "name", newpeername, SENTINEL);
-                                       }
-                               } else { /*var wasn't found in the list of "hosts", so try "ipaddr"*/
-                                       peerlist = NULL;
-                                       peerlist = ast_load_realtime_multientry("sippeers", "ipaddr", ipaddr, SENTINEL);
-                                       if(peerlist) {
-                                               var = get_insecure_variable_from_config(peerlist);
-                                               if(var) {
-                                                       if (realtimeregs) {
-                                                               newpeername = get_name_from_variable(var, newpeername);
-                                                               varregs = ast_load_realtime("sipregs", "name", newpeername, SENTINEL);
-                                                       }
-                                               }
-                                       }
-                               }
-                       } else {
-                               if (realtimeregs) {
-                                       peerlist = ast_load_realtime_multientry("sipregs", "ipaddr", ipaddr, SENTINEL);
-                                       if (peerlist) {
-                                               varregs = get_insecure_variable_from_config(peerlist);
-                                               if (varregs) {
-                                                       newpeername = get_name_from_variable(varregs, newpeername);
-                                                       var = ast_load_realtime("sippeers", "name", newpeername, SENTINEL);
-                                               }
-                                       }
-                               } else {
-                                       peerlist = ast_load_realtime_multientry("sippeers", "ipaddr", ipaddr, SENTINEL);
-                                       if (peerlist) {
-                                               var = get_insecure_variable_from_config(peerlist);
-                                               if (var) {
-                                                       newpeername = get_name_from_variable(var, newpeername);
-                                                       varregs = ast_load_realtime("sipregs", "name", newpeername, SENTINEL);
-                                               }
+                       break;
+               }
+       }
+       return NULL;
+}
+
+/* If varregs is NULL, we don't use sipregs.
+ * Using empty if-bodies instead of goto's while avoiding unnecessary indents */
+static int realtime_peer_by_name(const char *const *name, struct ast_sockaddr *addr, const char *ipaddr, struct ast_variable **var, struct ast_variable **varregs)
+{
+       /* Peer by name and host=dynamic */
+       if ((*var = ast_load_realtime("sippeers", "name", *name, "host", "dynamic", SENTINEL))) {
+               ;
+       /* Peer by name and host=IP */
+       } else if (addr && !(*var = ast_load_realtime("sippeers", "name", *name, "host", ipaddr, SENTINEL))) {
+               ;
+       /* Peer by name and host=HOSTNAME */
+       } else if ((*var = ast_load_realtime("sippeers", "name", *name, SENTINEL))) {
+               /*!\note
+                * If this one loaded something, then we need to ensure that the host
+                * field matched.  The only reason why we can't have this as a criteria
+                * is because we only have the IP address and the host field might be
+                * set as a name (and the reverse PTR might not match).
+                */
+               if (addr) {
+                       struct ast_variable *tmp;
+                       for (tmp = *var; tmp; tmp = tmp->next) {
+                               if (!strcasecmp(tmp->name, "host")) {
+                                       struct ast_sockaddr *addrs = NULL;
+
+                                       if (ast_sockaddr_resolve(&addrs,
+                                                                tmp->value,
+                                                                PARSE_PORT_FORBID,
+                                                                get_address_family_filter(&bindaddr)) <= 0 ||
+                                                                ast_sockaddr_cmp(&addrs[0], addr)) {
+                                               /* No match */
+                                               ast_variables_destroy(*var);
+                                               *var = NULL;
                                        }
+                                       ast_free(addrs);
+                                       break;
                                }
                        }
                }
        }
 
-       if (!var) {
-               if (peerlist)
-                       ast_config_destroy(peerlist);
-               return NULL;
+       /* Did we find anything? */
+       if (*var) {
+               if (varregs) {
+                       *varregs = ast_load_realtime("sipregs", "name", *name, SENTINEL);
+               }
+               return 1;
        }
+       return 0;
+}
 
-       for (tmp = var; tmp; tmp = tmp->next) {
-               if (!strcasecmp(tmp->name, "type") && (!strcasecmp(tmp->value, "peer") && which_objects == FINDUSERS)) {
-                       if (peerlist) {
-                               ast_config_destroy(peerlist);
-                       } else {
-                               ast_variables_destroy(var);
-                               ast_variables_destroy(varregs);
-                       }
-                       return NULL;
-               } else if (!newpeername && !strcasecmp(tmp->name, "name")) {
-                       newpeername = tmp->value;
+/* Another little helper function for backwards compatibility: this
+ * checks/fetches the sippeer that belongs to the sipreg. If none is
+ * found, we free the sipreg and return false. This way we can do the
+ * check inside the if-condition below. In the old code, not finding
+ * the sippeer also had it continue look for another match, so we do
+ * the same. */
+static struct ast_variable *realtime_peer_get_sippeer_helper(const char **name, struct ast_variable **varregs) {
+       struct ast_variable *var = NULL;
+       const char *old_name = *name;
+       *name = get_name_from_variable(*varregs);
+       if (!*name || !(var = ast_load_realtime("sippeers", "name", *name, SENTINEL))) {
+               if (!*name) {
+                       ast_log(LOG_WARNING, "Found sipreg but it has no name\n");
                }
+               ast_variables_destroy(*varregs);
+               *varregs = NULL;
+               *name = old_name;
        }
+       return var;
+}
 
-       if (!newpeername) {     /* Did not find peer in realtime */
-               ast_log(LOG_WARNING, "Cannot Determine peer name ip=%s\n", ipaddr);
-               if(peerlist)
-                       ast_config_destroy(peerlist);
-               else
-                       ast_variables_destroy(var);
+/* If varregs is NULL, we don't use sipregs. If we return true, then *name is
+ * set. Using empty if-bodies instead of goto's while avoiding unnecessary
+ * indents. */
+static int realtime_peer_by_addr(const char **name, struct ast_sockaddr *addr, const char *ipaddr, struct ast_variable **var, struct ast_variable **varregs)
+{
+       char portstring[6]; /* up to 5 digits plus null terminator */
+       ast_copy_string(portstring, ast_sockaddr_stringify_port(addr), sizeof(portstring));
+
+       /* We're not finding this peer by this name anymore. Reset it. */
+       *name = NULL;
+
+       /* First check for fixed IP hosts */
+       if ((*var = ast_load_realtime("sippeers", "host", ipaddr, "port", portstring, SENTINEL))) {
+               ;
+       /* Check for registered hosts (in sipregs) */
+       } else if (varregs && (*varregs = ast_load_realtime("sipregs", "ipaddr", ipaddr, "port", portstring, SENTINEL)) &&
+                       (*var = realtime_peer_get_sippeer_helper(name, varregs))) {
+               ;
+       /* Check for registered hosts (in sippeers) */
+       } else if (!varregs && (*var = ast_load_realtime("sippeers", "ipaddr", ipaddr, "port", portstring, SENTINEL))) {
+               ;
+       /* We couldn't match on ipaddress and port, so we need to check if port is insecure */
+       } else if ((*var = get_insecure_variable_from_sippeers("host", ipaddr))) {
+               ;
+       /* Same as above, but try the IP address field (in sipregs)
+        * Observe that it fetches the name/var at the same time, without the
+        * realtime_peer_get_sippeer_helper. Also note that it is quite inefficient.
+        * Avoid sipregs if possible. */
+       } else if (varregs && (*varregs = get_insecure_variable_from_sipregs("ipaddr", ipaddr, var))) {
+               ;
+       /* Same as above, but try the IP address field (in sippeers) */
+       } else if (!varregs && (*var = get_insecure_variable_from_sippeers("ipaddr", ipaddr))) {
+               ;
+       }
+
+       /* Nothing found? */
+       if (!*var) {
+               return 0;
+       }
+
+       /* Check peer name. It must not be empty. There may exist a
+        * different match that does have a name, but it's too late for
+        * that now. */
+       if (!*name && !(*name = get_name_from_variable(*var))) {
+               ast_log(LOG_WARNING, "Found peer for IP %s but it has no name\n", ipaddr);
+               ast_variables_destroy(*var);
+               *var = NULL;
+               if (varregs && *varregs) {
+                       ast_variables_destroy(*varregs);
+                       *varregs = NULL;
+               }
+               return 0;
+       }
+
+       /* Make sure varregs is populated if var is. The inverse,
+        * ensuring that var is set when varregs is, is taken
+        * care of by realtime_peer_get_sippeer_helper(). */
+       if (varregs && !*varregs) {
+               *varregs = ast_load_realtime("sipregs", "name", *name, SENTINEL);
+       }
+       return 1;
+}
+
+/*! \brief  realtime_peer: Get peer from realtime storage
+ * Checks the "sippeers" realtime family from extconfig.conf
+ * Checks the "sipregs" realtime family from extconfig.conf if it's configured.
+ * This returns a pointer to a peer and because we use build_peer, we can rest
+ * assured that the refcount is bumped.
+ * 
+ * \note This is never called with both newpeername and addr at the same time.
+ * If you do, be prepared to get a peer with a different name than newpeername.
+ */
+static struct sip_peer *realtime_peer(const char *newpeername, struct ast_sockaddr *addr, int devstate_only, int which_objects)
+{
+       struct sip_peer *peer = NULL;
+       struct ast_variable *var = NULL;
+       struct ast_variable *varregs = NULL;
+       char ipaddr[INET6_ADDRSTRLEN];
+       int realtimeregs = ast_check_realtime("sipregs");
+
+       if (addr) {
+               ast_copy_string(ipaddr, ast_sockaddr_stringify_addr(addr), sizeof(ipaddr));
+       } else {
+               ipaddr[0] = '\0';
+       }
+
+       if (newpeername && realtime_peer_by_name(&newpeername, addr, ipaddr, &var, realtimeregs ? &varregs : NULL)) {
+               ;
+       } else if (addr && realtime_peer_by_addr(&newpeername, addr, ipaddr, &var, realtimeregs ? &varregs : NULL)) {
+               ;
+       } else {
                return NULL;
        }
 
+       /* If we're looking for users, don't return peers (although this check
+        * should probably be done in realtime_peer_by_* instead...) */
+       if (which_objects == FINDUSERS) {
+               struct ast_variable *tmp;
+               for (tmp = var; tmp; tmp = tmp->next) {
+                       if (!strcasecmp(tmp->name, "type") && (!strcasecmp(tmp->value, "peer"))) {
+                               goto cleanup;
+                       }
+               }
+       }
 
        /* Peer found in realtime, now build it in memory */
        peer = build_peer(newpeername, var, varregs, TRUE, devstate_only);
        if (!peer) {
-               if(peerlist)
-                       ast_config_destroy(peerlist);
-               else {
-                       ast_variables_destroy(var);
-                       ast_variables_destroy(varregs);
-               }
-               return NULL;
+               goto cleanup;
        }
 
        ast_debug(3, "-REALTIME- loading peer from database to memory. Name: %s. Peer objects: %d\n", peer->name, rpeerobjs);
@@ -4849,9 +4952,9 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct ast_sockad
                ast_copy_flags(&peer->flags[1], &global_flags[1], SIP_PAGE2_RTAUTOCLEAR|SIP_PAGE2_RTCACHEFRIENDS);
                if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTAUTOCLEAR)) {
                        AST_SCHED_REPLACE_UNREF(peer->expire, sched, sip_cfg.rtautoclear * 1000, expire_register, peer,
-                                       unref_peer(_data, "remove registration ref"),
-                                       unref_peer(peer, "remove registration ref"),
-                                       ref_peer(peer, "add registration ref"));
+                                       sip_unref_peer(_data, "remove registration ref"),
+                                       sip_unref_peer(peer, "remove registration ref"),
+                                       sip_ref_peer(peer, "add registration ref"));
                }
                ao2_t_link(peers, peer, "link peer into peers table");
                if (!ast_sockaddr_isnull(&peer->addr)) {
@@ -4859,13 +4962,10 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct ast_sockad
                }
        }
        peer->is_realtime = 1;
-       if (peerlist)
-               ast_config_destroy(peerlist);
-       else {
-               ast_variables_destroy(var);
-               ast_variables_destroy(varregs);
-       }
 
+cleanup:
+       ast_variables_destroy(var);
+       ast_variables_destroy(varregs);
        return peer;
 }
 
@@ -4911,7 +5011,7 @@ static int find_by_name(void *obj, void *arg, void *data, int flags)
  * \note Avoid using this function in new functions if there is a way to avoid it,
  * since it might cause a database lookup.
  */
-static struct sip_peer *find_peer(const char *peer, struct ast_sockaddr *addr, int realtime, int which_objects, int devstate_only, int transport)
+struct sip_peer *sip_find_peer(const char *peer, struct ast_sockaddr *addr, int realtime, int which_objects, int devstate_only, int transport)
 {
        struct sip_peer *p = NULL;
        struct sip_peer tmp_peer;
@@ -4939,13 +5039,13 @@ static struct sip_peer *find_peer(const char *peer, struct ast_sockaddr *addr, i
                        switch (which_objects) {
                        case FINDUSERS:
                                if (!(p->type & SIP_TYPE_USER)) {
-                                       unref_peer(p, "Wrong type of realtime SIP endpoint");
+                                       sip_unref_peer(p, "Wrong type of realtime SIP endpoint");
                                        return NULL;
                                }
                                break;
                        case FINDPEERS:
                                if (!(p->type & SIP_TYPE_PEER)) {
-                                       unref_peer(p, "Wrong type of realtime SIP endpoint");
+                                       sip_unref_peer(p, "Wrong type of realtime SIP endpoint");
                                        return NULL;
                                }
                                break;
@@ -5009,13 +5109,13 @@ static void change_t38_state(struct sip_pvt *p, int state)
                parameters = p->t38.their_parms;
                parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl);
                parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
-               ast_udptl_set_tag(p->udptl, "SIP/%s", p->username);
+               ast_udptl_set_tag(p->udptl, "%s", chan->name);
                break;
        case T38_ENABLED:
                parameters = p->t38.their_parms;
                parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl);
                parameters.request_response = AST_T38_NEGOTIATED;
-               ast_udptl_set_tag(p->udptl, "SIP/%s", p->username);
+               ast_udptl_set_tag(p->udptl, "%s", chan->name);
                break;
        case T38_REJECTED:
        case T38_DISABLED:
@@ -5084,9 +5184,9 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog)
                if (!(dialog->vrtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr_tmp, NULL))) {
                        return -1;
                }
-               ast_rtp_instance_set_timeout(dialog->vrtp, global_rtptimeout);
-               ast_rtp_instance_set_hold_timeout(dialog->vrtp, global_rtpholdtimeout);
-               ast_rtp_instance_set_keepalive(dialog->vrtp, global_rtpholdtimeout);
+               ast_rtp_instance_set_timeout(dialog->vrtp, dialog->rtptimeout);
+               ast_rtp_instance_set_hold_timeout(dialog->vrtp, dialog->rtpholdtimeout);
+               ast_rtp_instance_set_keepalive(dialog->vrtp, dialog->rtpkeepalive);
 
                ast_rtp_instance_set_prop(dialog->vrtp, AST_RTP_PROPERTY_RTCP, 1);
        }
@@ -5095,16 +5195,15 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog)
                if (!(dialog->trtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr_tmp, NULL))) {
                        return -1;
                }
-               ast_rtp_instance_set_timeout(dialog->trtp, global_rtptimeout);
-               ast_rtp_instance_set_hold_timeout(dialog->trtp, global_rtpholdtimeout);
-               ast_rtp_instance_set_keepalive(dialog->trtp, global_rtpholdtimeout);
+               /* Do not timeout text as its not constant*/
+               ast_rtp_instance_set_keepalive(dialog->trtp, dialog->rtpkeepalive);
 
                ast_rtp_instance_set_prop(dialog->trtp, AST_RTP_PROPERTY_RTCP, 1);
        }
 
-       ast_rtp_instance_set_timeout(dialog->rtp, global_rtptimeout);
-       ast_rtp_instance_set_hold_timeout(dialog->rtp, global_rtpholdtimeout);
-       ast_rtp_instance_set_keepalive(dialog->rtp, global_rtpkeepalive);
+       ast_rtp_instance_set_timeout(dialog->rtp, dialog->rtptimeout);
+       ast_rtp_instance_set_hold_timeout(dialog->rtp, dialog->rtpholdtimeout);
+       ast_rtp_instance_set_keepalive(dialog->rtp, dialog->rtpkeepalive);
 
        ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_RTCP, 1);
        ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
@@ -5165,6 +5264,9 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
 
        ast_string_field_set(dialog, engine, peer->engine);
 
+       dialog->rtptimeout = peer->rtptimeout;
+       dialog->rtpholdtimeout = peer->rtpholdtimeout;
+       dialog->rtpkeepalive = peer->rtpkeepalive;
        if (dialog_initialize_rtp(dialog)) {
                return -1;
        }
@@ -5172,23 +5274,10 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
        if (dialog->rtp) { /* Audio */
                ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
                ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
-               ast_rtp_instance_set_timeout(dialog->rtp, peer->rtptimeout);
-               ast_rtp_instance_set_hold_timeout(dialog->rtp, peer->rtpholdtimeout);
-               ast_rtp_instance_set_keepalive(dialog->rtp, peer->rtpkeepalive);
                /* Set Frame packetization */
                ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(dialog->rtp), dialog->rtp, &dialog->prefs);
                dialog->autoframing = peer->autoframing;
        }
-       if (dialog->vrtp) { /* Video */
-               ast_rtp_instance_set_timeout(dialog->vrtp, peer->rtptimeout);
-               ast_rtp_instance_set_hold_timeout(dialog->vrtp, peer->rtpholdtimeout);
-               ast_rtp_instance_set_keepalive(dialog->vrtp, peer->rtpkeepalive);
-       }
-       if (dialog->trtp) { /* Realtime text */
-               ast_rtp_instance_set_timeout(dialog->trtp, peer->rtptimeout);
-               ast_rtp_instance_set_hold_timeout(dialog->trtp, peer->rtpholdtimeout);
-               ast_rtp_instance_set_keepalive(dialog->trtp, peer->rtpkeepalive);
-       }
 
        /* XXX TODO: get fields directly from peer only as they are needed using dialog->relatedpeer */
        ast_string_field_set(dialog, peername, peer->name);
@@ -5213,9 +5302,9 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
        ref_proxy(dialog, obproxy_get(dialog, peer));
        dialog->callgroup = peer->callgroup;
        dialog->pickupgroup = peer->pickupgroup;
+       ast_copy_string(dialog->zone, peer->zone, sizeof(dialog->zone));
        dialog->allowtransfer = peer->allowtransfer;
        dialog->jointnoncodeccapability = dialog->noncodeccapability;
-       dialog->rtptimeout = peer->rtptimeout;
 
        /* Update dialog authorization credentials */
        ao2_lock(peer);
@@ -5239,15 +5328,20 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
        if (!ast_strlen_zero(peer->fromdomain)) {
                ast_string_field_set(dialog, fromdomain, peer->fromdomain);
                if (!dialog->initreq.headers) {
-                       char *c;
+                       char *new_callid;
                        char *tmpcall = ast_strdupa(dialog->callid);
                        /* this sure looks to me like we are going to change the callid on this dialog!! */
-                       c = strchr(tmpcall, '@');
-                       if (c) {
-                               *c = '\0';
-                               ao2_t_unlink(dialogs, dialog, "About to change the callid -- remove the old name");
-                               ast_string_field_build(dialog, callid, "%s@%s", tmpcall, peer->fromdomain);
-                               ao2_t_link(dialogs, dialog, "New dialog callid -- inserted back into table");
+                       new_callid = strchr(tmpcall, '@');
+                       if (new_callid) {
+                               int callid_size;
+
+                               *new_callid = '\0';
+
+                               /* Change the dialog callid. */
+                               callid_size = strlen(tmpcall) + strlen(peer->fromdomain) + 2;
+                               new_callid = alloca(callid_size);
+                               snprintf(new_callid, callid_size, "%s@%s", tmpcall, peer->fromdomain);
+                               change_callid_pvt(dialog, new_callid);
                        }
                }
        }
@@ -5314,7 +5408,7 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct ast_soc
 
        dialog->timer_t1 = global_t1; /* Default SIP retransmission timer T1 (RFC 3261) */
        dialog->timer_b = global_timer_b; /* Default SIP transaction timer B (RFC 3261) */
-       peer = find_peer(peername, NULL, TRUE, FINDPEERS, FALSE, 0);
+       peer = sip_find_peer(peername, NULL, TRUE, FINDPEERS, FALSE, 0);
 
        if (peer) {
                int res;
@@ -5325,13 +5419,22 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct ast_soc
                if (!ast_sockaddr_isnull(remote_address)) {
                        ast_sockaddr_copy(&dialog->sa, remote_address);
                }
-               dialog->relatedpeer = ref_peer(peer, "create_addr: setting dialog's relatedpeer pointer");
-               unref_peer(peer, "create_addr: unref peer from find_peer hashtab lookup");
+               dialog->relatedpeer = sip_ref_peer(peer, "create_addr: setting dialog's relatedpeer pointer");
+               sip_unref_peer(peer, "create_addr: unref peer from sip_find_peer hashtab lookup");
                return res;
-       }
-
-       if (dialog_initialize_rtp(dialog)) {
+       } else if (ast_check_digits(peername)) {
+               /* Although an IPv4 hostname *could* be represented as a 32-bit integer, it is uncommon and
+                * it makes dialing SIP/${EXTEN} for a peer that isn't defined resolve to an IP that is
+                * almost certainly not intended. It is much better to just reject purely numeric hostnames */
+               ast_log(LOG_WARNING, "Purely numeric hostname (%s), and not a peer--rejecting!\n", peername);
                return -1;
+       } else {
+               dialog->rtptimeout = global_rtptimeout;
+               dialog->rtpholdtimeout = global_rtpholdtimeout;
+               dialog->rtpkeepalive = global_rtpkeepalive;
+               if (dialog_initialize_rtp(dialog)) {
+                       return -1;
+               }
        }
 
        ast_string_field_set(dialog, tohost, hostport.host);
@@ -5366,6 +5469,7 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct ast_soc
 
                if (ast_sockaddr_resolve_first(&dialog->sa, hostn, 0)) {
                        ast_log(LOG_WARNING, "No such host: %s\n", peername);
+                       return -1;
                }
 
                if (srv_ret > 0) {
@@ -5593,7 +5697,7 @@ static void sip_registry_destroy(struct sip_registry *reg)
                   we don't get reentered trying to grab the registry lock */
                reg->call->registry = registry_unref(reg->call->registry, "destroy reg->call->registry");
                ast_debug(3, "Destroying active SIP dialog for registry %s@%s\n", reg->username, reg->hostname);
-               dialog_unlink_all(reg->call, TRUE, TRUE);
+               dialog_unlink_all(reg->call);
                reg->call = dialog_unref(reg->call, "unref reg->call");
                /* reg->call = sip_destroy(reg->call); */
        }
@@ -5662,7 +5766,7 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
                p->relatedpeer->call = dialog_unref(p->relatedpeer->call, "unset the relatedpeer->call field in tandem with relatedpeer field itself");
        
        if (p->relatedpeer)
-               p->relatedpeer = unref_peer(p->relatedpeer,"unsetting a dialog relatedpeer field in sip_destroy");
+               p->relatedpeer = sip_unref_peer(p->relatedpeer,"unsetting a dialog relatedpeer field in sip_destroy");
        
        if (p->registry) {
                if (p->registry->call == p)
@@ -5803,7 +5907,7 @@ static int update_call_counter(struct sip_pvt *fup, int event)
 
        /* Check the list of devices */
        if (fup->relatedpeer) {
-               p = ref_peer(fup->relatedpeer, "ref related peer for update_call_counter");
+               p = sip_ref_peer(fup->relatedpeer, "ref related peer for update_call_counter");
                inuse = &p->inUse;
                call_limit = &p->call_limit;
                inringing = &p->inRinging;
@@ -5871,7 +5975,7 @@ static int update_call_counter(struct sip_pvt *fup, int event)
                if (*call_limit > 0 ) {
                        if (*inuse >= *call_limit) {
                                ast_log(LOG_NOTICE, "Call %s %s '%s' rejected due to usage limit of %d\n", outgoing ? "to" : "from", "peer", name, *call_limit);
-                               unref_peer(p, "update_call_counter: unref peer p, call limit exceeded");
+                               sip_unref_peer(p, "update_call_counter: unref peer p, call limit exceeded");
                                return -1;
                        }
                }
@@ -5921,7 +6025,7 @@ static int update_call_counter(struct sip_pvt *fup, int event)
 
        if (p) {
                ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", p->name);
-               unref_peer(p, "update_call_counter: unref_peer from call counter");
+               sip_unref_peer(p, "update_call_counter: sip_unref_peer from call counter");
        }
        return 0;
 }
@@ -6151,7 +6255,6 @@ static int sip_hangup(struct ast_channel *ast)
                ast_debug(4, "SIP Transfer: Not hanging up right now... Rescheduling hangup for %s.\n", p->callid);
                sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
                ast_clear_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER);        /* Really hang up next time */
-               p->needdestroy = 0;
                p->owner->tech_pvt = dialog_unref(p->owner->tech_pvt, "unref p->owner->tech_pvt");
                sip_pvt_lock(p);
                p->owner = NULL;  /* Owner will be gone after we return, so take it away */
@@ -6725,6 +6828,28 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
                }
                res = -1;
                break;
+       case AST_CONTROL_INCOMPLETE:
+               if (ast->_state != AST_STATE_UP) {
+                       switch (ast_test_flag(&p->flags[1], SIP_PAGE2_ALLOWOVERLAP)) {
+                       case SIP_PAGE2_ALLOWOVERLAP_YES:
+                               transmit_response_reliable(p, "484 Address Incomplete", &p->initreq);
+                               p->invitestate = INV_COMPLETED;
+                               sip_alreadygone(p);
+                               ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
+                               break;
+                       case SIP_PAGE2_ALLOWOVERLAP_DTMF:
+                               /* Just wait for inband DTMF digits */
+                               break;
+                       default:
+                               /* it actually means no support for overlap */
+                               transmit_response_reliable(p, "404 Not Found", &p->initreq);
+                               p->invitestate = INV_COMPLETED;
+                               sip_alreadygone(p);
+                               ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
+                               break;
+                       }
+               }
+               break;
        case AST_CONTROL_PROCEEDING:
                if ((ast->_state != AST_STATE_UP) &&
                    !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
@@ -6817,6 +6942,8 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
                        ast_aoc_destroy_decoded(decoded);
                }
                break;
+       case AST_CONTROL_UPDATE_RTP_PEER: /* Absorb this since it is handled by the bridge */
+               break;
        case -1:
                res = -1;
                break;
@@ -6829,11 +6956,17 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
        return res;
 }
 
-/*! \brief Initiate a call in the SIP channel
-       called from sip_request_call (calls from the pbx ) for outbound channels
-       and from handle_request_invite for inbound channels
-       
-*/
+/*!
+ * \brief Initiate a call in the SIP channel
+ *
+ * \note called from sip_request_call (calls from the pbx ) for
+ * outbound channels and from handle_request_invite for inbound
+ * channels
+ *
+ * \pre i is locked
+ *
+ * \return New ast_channel locked.
+ */
 static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *title, const char *linkedid)
 {
        struct ast_channel *tmp;
@@ -6843,7 +6976,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
        int needvideo = 0;
        int needtext = 0;
        char buf[SIPBUFSIZE];
-       char *decoded_exten;
+       char *exten;
 
        {
                const char *my_name;    /* pick a good name */
@@ -6981,6 +7114,11 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
        if (!ast_strlen_zero(i->language)) {
                ast_string_field_set(tmp, language, i->language);
        }
+       if (!ast_strlen_zero(i->zone)) {
+               if (!(tmp->zone = ast_get_indication_zone(i->zone))) {
+                       ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", i->zone);
+               } 
+       }
        i->owner = tmp;
        ast_module_ref(ast_module_info->self);
        ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
@@ -6988,14 +7126,15 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
         * we should decode the uri before storing it in the channel, but leave it encoded in the sip_pvt
         * structure so that there aren't issues when forming URI's
         */
-       if (ast_exists_extension(NULL, i->context, i->exten, 1, i->cid_num)) {
-               /* encoded in dialplan, so keep extension encoded */
-               ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
-       } else {
-               decoded_exten = ast_strdupa(i->exten);
-               ast_uri_decode(decoded_exten, ast_uri_sip_user);
-               ast_copy_string(tmp->exten, decoded_exten, sizeof(tmp->exten));
+       exten = ast_strdupa(i->exten);
+       sip_pvt_unlock(i);
+       ast_channel_unlock(tmp);
+       if (!ast_exists_extension(NULL, i->context, i->exten, 1, i->cid_num)) {
+               ast_uri_decode(exten, ast_uri_sip_user);
        }
+       ast_channel_lock(tmp);
+       sip_pvt_lock(i);
+       ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
 
        /* Don't use ast_set_callerid() here because it will
         * generate an unnecessary NewCallerID event  */
@@ -7032,15 +7171,6 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
                pbx_builtin_setvar_helper(tmp, v->name, ast_get_encoded_str(v->value, valuebuf, sizeof(valuebuf)));
        }
 
-       ast_channel_unlock(tmp); /* ast_hangup requires the channel to be unlocked */
-
-       if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
-               ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
-               tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
-               ast_hangup(tmp);
-               tmp = NULL;
-       }
-
        if (i->do_history) {
                append_history(i, "NewChan", "Channel %s - from %s", tmp->name, i->callid);
        }
@@ -7201,14 +7331,14 @@ static const char *__get_header(const struct sip_request *req, const char *name,
                }
        }
 
-       /* Don't return NULL, so get_header is always a valid pointer */
+       /* Don't return NULL, so sip_get_header is always a valid pointer */
        return "";
 }
 
 /*! \brief Get header from SIP request
        \return Always return something, so don't check for NULL because it won't happen :-)
 */
-static const char *get_header(const struct sip_request *req, const char *name)
+const char *sip_get_header(const struct sip_request *req, const char *name)
 {
        int start = 0;
        return __get_header(req, name, &start);
@@ -7241,16 +7371,23 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
        case 4:
                f = ast_rtp_instance_read(p->trtp, 0);  /* RTP Text */
                if (sipdebug_text) {
+                       struct ast_str *out = ast_str_create(f->datalen * 4 + 6);
                        int i;
                        unsigned char* arr = f->data.ptr;
-                       for (i=0; i < f->datalen; i++) {
-                               ast_verbose("%c", (arr[i] > ' ' && arr[i] < '}') ? arr[i] : '.');
-                       }
-                       ast_verbose(" -> ");
-                       for (i=0; i < f->datalen; i++) {
-                               ast_verbose("%02X ", arr[i]);
-                       }
-                       ast_verbose("\n");
+                       do {
+                               if (!out) {
+                                       break;
+                               }
+                               for (i = 0; i < f->datalen; i++) {
+                                       ast_str_append(&out, 0, "%c", (arr[i] > ' ' && arr[i] < '}') ? arr[i] : '.');
+                               }
+                               ast_str_append(&out, 0, " -> ");
+                               for (i = 0; i < f->datalen; i++) {
+                                       ast_str_append(&out, 0, "%02X ", arr[i]);
+                               }
+                               ast_verb(0, "%s\n", ast_str_buffer(out));
+                               ast_free(out);
+                       } while (0);
                }
                break;
        case 5:
@@ -7333,7 +7470,7 @@ static struct ast_frame *sip_read(struct ast_channel *ast)
                                S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, NULL))) {
                                ast_channel_lock(ast);
                                sip_pvt_lock(p);
-                               ast_verbose(VERBOSE_PREFIX_2 "Redirecting '%s' to fax extension due to CNG detection\n", ast->name);
+                               ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n", ast->name);
                                pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
                                if (ast_async_goto(ast, target_context, "fax", 1)) {
                                        ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
@@ -7384,15 +7521,68 @@ static char *generate_uri(struct sip_pvt *pvt, char *buf, size_t size)
        return buf;
 }
 
-/*! \brief Build SIP Call-ID value for a non-REGISTER transaction */
+/*!
+ * \brief Build SIP Call-ID value for a non-REGISTER transaction
+ *
+ * \note The passed in pvt must not be in a dialogs container
+ * since this function changes the hash key used by the
+ * container.
+ */
 static void build_callid_pvt(struct sip_pvt *pvt)
 {
        char buf[33];
-
        const char *host = S_OR(pvt->fromdomain, ast_sockaddr_stringify_remote(&pvt->ourip));
-       
+
        ast_string_field_build(pvt, callid, "%s@%s", generate_random_string(buf, sizeof(buf)), host);
+}
+
+/*! \brief Unlink the given object from the container and return TRUE if it was in the container. */
+#define CONTAINER_UNLINK(container, obj, tag)                                                          \
+       ({                                                                                                                                              \
+               int found = 0;                                                                                                          \
+               typeof((obj)) __removed_obj;                                                                            \
+               __removed_obj = ao2_t_callback((container),                                                     \
+                       OBJ_UNLINK | OBJ_POINTER, ao2_match_by_addr, (obj), (tag));             \
+               if (__removed_obj) {                                                                                            \
+                       ao2_ref(__removed_obj, -1);                                                                             \
+                       found = 1;                                                                                                              \
+               }                                                                                                                                       \
+               found;                                                                                                                          \
+       })
 
+/*!
+ * \internal
+ * \brief Safely change the callid of the given SIP dialog.
+ *
+ * \param pvt SIP private structure to change callid
+ * \param callid Specified new callid to use.  NULL if generate new callid.
+ *
+ * \return Nothing
+ */
+static void change_callid_pvt(struct sip_pvt *pvt, const char *callid)
+{
+       int in_dialog_container;
+       int in_rtp_container;
+
+       ao2_lock(dialogs);
+       ao2_lock(dialogs_rtpcheck);
+       in_dialog_container = CONTAINER_UNLINK(dialogs, pvt,
+               "About to change the callid -- remove the old name");
+       in_rtp_container = CONTAINER_UNLINK(dialogs_rtpcheck, pvt,
+               "About to change the callid -- remove the old name");
+       if (callid) {
+               ast_string_field_set(pvt, callid, callid);
+       } else {
+               build_callid_pvt(pvt);
+       }
+       if (in_dialog_container) {
+               ao2_t_link(dialogs, pvt, "New dialog callid -- inserted back into table");
+       }
+       if (in_rtp_container) {
+               ao2_t_link(dialogs_rtpcheck, pvt, "New dialog callid -- inserted back into table");
+       }
+       ao2_unlock(dialogs_rtpcheck);
+       ao2_unlock(dialogs);
 }
 
 /*! \brief Build SIP Call-ID value for a REGISTER transaction */
@@ -7473,11 +7663,11 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
         * some information about it in the dialog. */
        if (req) {
                struct sip_via *via;
-               const char *cseq = get_header(req, "Cseq");
+               const char *cseq = sip_get_header(req, "Cseq");
                unsigned int seqno;
 
                /* get branch parameter from initial Request that started this dialog */
-               via = parse_via(get_header(req, "Via"));
+               via = parse_via(sip_get_header(req, "Via"));
                if (via) {
                        /* only store the branch if it begins with the magic prefix "z9hG4bK", otherwise
                         * it is not useful to us to have it */
@@ -7513,6 +7703,7 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
        p->session_modify = TRUE;
        p->stimer = NULL;
        p->prefs = default_prefs;               /* Set default codecs for this call */
+       ast_copy_string(p->zone, default_zone, sizeof(p->zone));
        p->maxforwards = sip_cfg.default_max_forwards;
 
        if (intended_method != SIP_OPTIONS) {   /* Peerpoke has it's own system */
@@ -7614,7 +7805,7 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
  */
 static int process_via(struct sip_pvt *p, const struct sip_request *req)
 {
-       struct sip_via *via = parse_via(get_header(req, "Via"));
+       struct sip_via *via = parse_via(sip_get_header(req, "Via"));
 
        if (!via) {
                ast_log(LOG_ERROR, "error processing via header\n");
@@ -7867,7 +8058,7 @@ static void forked_invite_init(struct sip_request *req, const char *new_theirtag
  * \note This function will never let you down.
  * \note This function will run around and desert you.
  *
- * \pre vpt is not locked
+ * \pre pvt is not locked
  * \post pvt is locked
  * \post pvt->owner is locked and its reference count is increased (if pvt->owner is not NULL)
  *
@@ -7931,14 +8122,14 @@ static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *a
 {
        char totag[128];
        char fromtag[128];
-       const char *callid = get_header(req, "Call-ID");
-       const char *from = get_header(req, "From");
-       const char *to = get_header(req, "To");
-       const char *cseq = get_header(req, "Cseq");
+       const char *callid = sip_get_header(req, "Call-ID");
+       const char *from = sip_get_header(req, "From");
+       const char *to = sip_get_header(req, "To");
+       const char *cseq = sip_get_header(req, "Cseq");
        struct sip_pvt *sip_pvt_ptr;
        unsigned int seqno;
        /* Call-ID, to, from and Cseq are required by RFC 3261. (Max-forwards and via too - ignored now) */
-       /* get_header always returns non-NULL so we must use ast_strlen_zero() */
+       /* sip_get_header always returns non-NULL so we must use ast_strlen_zero() */
        if (ast_strlen_zero(callid) || ast_strlen_zero(to) ||
                        ast_strlen_zero(from) || ast_strlen_zero(cseq) ||
                        (sscanf(cseq, "%30u", &seqno) != 1)) {
@@ -8011,14 +8202,14 @@ static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *a
                args.seqno = seqno;
                /* get via header information. */
                args.ruri = REQ_OFFSET_TO_STR(req, rlPart2);
-               via = parse_via(get_header(req, "Via"));
+               via = parse_via(sip_get_header(req, "Via"));
                if (via) {
                        args.viasentby = via->sent_by;
                        args.viabranch = via->branch;
                }
                /* determine if this is a Request with authentication credentials. */
-               if (!ast_strlen_zero(get_header(req, "Authorization")) ||
-                       !ast_strlen_zero(get_header(req, "Proxy-Authorization"))) {
+               if (!ast_strlen_zero(sip_get_header(req, "Authorization")) ||
+                       !ast_strlen_zero(sip_get_header(req, "Proxy-Authorization"))) {
                        args.authentication_present = 1;
                }
                /* if it is a response, get the response code */
@@ -8266,7 +8457,7 @@ static void mark_parsed_methods(unsigned int *methods, char *methods_str)
  */
 static unsigned int parse_allowed_methods(struct sip_request *req)
 {
-       char *allow = ast_strdupa(get_header(req, "Allow"));
+       char *allow = ast_strdupa(sip_get_header(req, "Allow"));
        unsigned int allowed_methods = SIP_UNKNOWN;
 
        if (ast_strlen_zero(allow)) {
@@ -8274,7 +8465,7 @@ static unsigned int parse_allowed_methods(struct sip_request *req)
                 * place the phone's allowed methods in an Allow header. Instead, they place the
                 * allowed methods in a methods= parameter in the Contact header.
                 */
-               char *contact = ast_strdupa(get_header(req, "Contact"));
+               char *contact = ast_strdupa(sip_get_header(req, "Contact"));
                char *methods = strstr(contact, ";methods=");
 
                if (ast_strlen_zero(methods)) {
@@ -8479,7 +8670,7 @@ static int find_sdp(struct sip_request *req)
        int found_application_sdp = FALSE;
        int found_end_of_headers = FALSE;
 
-       content_length = get_header(req, "Content-Length");
+       content_length = sip_get_header(req, "Content-Length");
 
        if (!ast_strlen_zero(content_length)) {
                if (sscanf(content_length, "%30u", &x) != 1) {
@@ -8493,7 +8684,7 @@ static int find_sdp(struct sip_request *req)
                        return 0;
        }
 
-       content_type = get_header(req, "Content-Type");
+       content_type = sip_get_header(req, "Content-Type");
 
        /* if the body contains only SDP, this is easy */
        if (!strncasecmp(content_type, "application/sdp", 15)) {
@@ -8647,6 +8838,17 @@ static int get_ip_and_port_from_sdp(struct sip_request *req, const enum media_ty
        return 0;
 }
 
+/*! \internal
+ * \brief Returns whether or not the address is null or ANY / unspecified (0.0.0.0 or ::)
+ * \retval TRUE if the address is null or any
+ * \retval FALSE if the address it not null or any
+ * \note In some circumstances, calls should be placed on hold if either of these conditions exist.
+ */
+static int sockaddr_is_null_or_any(const struct ast_sockaddr *addr)
+{
+       return ast_sockaddr_isnull(addr) || ast_sockaddr_is_any(addr);
+}
+
 /*! \brief Process SIP SDP offer, select formats and activate RTP channels
        If offer is rejected, we will not change any properties of the call
        Return 0 on success, a negative value on errors.
@@ -8825,9 +9027,13 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                ast_log(LOG_WARNING, "unknown SDP media protocol in offer: %s\n", protocol);
                                continue;
                        }
+                       if (p->offered_media[SDP_AUDIO].order_offered) {
+                               ast_log(LOG_WARNING, "Multiple audio streams are not supported\n");
+                               res = -3;
+                               goto process_sdp_cleanup;
+                       }
                        audio = TRUE;
-                       p->offered_media[SDP_AUDIO].offered = TRUE;
-                       numberofmediastreams++;
+                       p->offered_media[SDP_AUDIO].order_offered = ++numberofmediastreams;
                        portno = x;
 
                        /* Scan through the RTP payload types specified in a "m=" line: */
@@ -8853,10 +9059,14 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                ast_log(LOG_WARNING, "unknown SDP media protocol in offer: %s\n", protocol);
                                continue;
                        }
+                       if (p->offered_media[SDP_VIDEO].order_offered) {
+                               ast_log(LOG_WARNING, "Multiple video streams are not supported\n");
+                               res = -3;
+                               goto process_sdp_cleanup;
+                       }
                        video = TRUE;
                        p->novideo = FALSE;
-                       p->offered_media[SDP_VIDEO].offered = TRUE;
-                       numberofmediastreams++;
+                       p->offered_media[SDP_VIDEO].order_offered = ++numberofmediastreams;
                        vportno = x;
 
                        /* Scan through the RTP payload types specified in a "m=" line: */
@@ -8875,10 +9085,14 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                /* Search for text media definition */
                } else if ((sscanf(m, "text %30u/%30u RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0 && x) ||
                           (sscanf(m, "text %30u RTP/AVP %n", &x, &len) == 1 && len > 0 && x)) {
+                       if (p->offered_media[SDP_TEXT].order_offered) {
+                               ast_log(LOG_WARNING, "Multiple text streams are not supported\n");
+                               res = -3;
+                               goto process_sdp_cleanup;
+                       }
                        text = TRUE;
                        p->notext = FALSE;
-                       p->offered_media[SDP_TEXT].offered = TRUE;
-                       numberofmediastreams++;
+                       p->offered_media[SDP_TEXT].order_offered = ++numberofmediastreams;
                        tportno = x;
 
                        /* Scan through the RTP payload types specified in a "m=" line: */
@@ -8897,12 +9111,16 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                /* Search for image media definition */
                } else if (p->udptl && ((sscanf(m, "image %30u udptl t38%n", &x, &len) == 1 && len > 0 && x) ||
                                        (sscanf(m, "image %30u UDPTL t38%n", &x, &len) == 1 && len > 0 && x) )) {
+                       if (p->offered_media[SDP_IMAGE].order_offered) {
+                               ast_log(LOG_WARNING, "Multiple T.38 streams are not supported\n");
+                               res = -3;
+                               goto process_sdp_cleanup;
+                       }
                        image = TRUE;
                        if (debug)
                                ast_verbose("Got T.38 offer in SDP in dialog %s\n", p->callid);
-                       p->offered_media[SDP_IMAGE].offered = TRUE;
+                       p->offered_media[SDP_IMAGE].order_offered = ++numberofmediastreams;
                        udptlportno = x;
-                       numberofmediastreams++;
 
                        if (p->t38.state != T38_ENABLED) {
                                memset(&p->t38.their_parms, 0, sizeof(p->t38.their_parms));
@@ -9005,13 +9223,6 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                goto process_sdp_cleanup;
        }
 
-       if (numberofmediastreams > 3) {
-               /* We have too many fax, audio and/or video and/or text media streams, fail this offer */
-               ast_log(LOG_WARNING, "Faling due to too many media streams\n");
-               res = -3;
-               goto process_sdp_cleanup;
-       }
-
        if (secure_audio && !(p->srtp && (ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK)))) {
                ast_log(LOG_WARNING, "Can't provide secure audio requested in SDP offer\n");
                res = -4;
@@ -9056,7 +9267,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
        ast_format_cap_append(newpeercapability, tpeercapability);
 
        ast_format_cap_joint_copy(p->caps, newpeercapability, newjointcapability);
-       if (ast_format_cap_is_empty(newjointcapability) && (portno != -1)) {
+       if (ast_format_cap_is_empty(newjointcapability) && udptlportno == -1) {
                ast_log(LOG_NOTICE, "No compatible codecs, not accepting this offer!\n");
                /* Do NOT Change current setting */
                res = -1;
@@ -9087,6 +9298,20 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                            ast_rtp_lookup_mime_multiple2(s3, NULL, newnoncodeccapability, 0, 0));
        }
 
+       if (portno != -1 || vportno != -1 || tportno != -1) {
+               /* We are now ready to change the sip session and p->rtp and p->vrtp with the offered codecs, since
+                  they are acceptable */
+               ast_format_cap_copy(p->jointcaps, newjointcapability);                /* Our joint codec profile for this call */
+               ast_format_cap_copy(p->peercaps, newpeercapability);                  /* The other sides capability in latest offer */
+               p->jointnoncodeccapability = newnoncodeccapability;     /* DTMF capabilities */
+       
+               /* respond with single most preferred joint codec, limiting the other side's choice */
+               if (ast_test_flag(&p->flags[1], SIP_PAGE2_PREFERRED_CODEC)) {
+                       ast_codec_choose(&p->prefs, p->jointcaps, 1, &tmp_fmt);
+                       ast_format_cap_set(p->jointcaps, &tmp_fmt);
+               }
+       }
+
        /* Setup audio address and port */
        if (p->rtp) {
                if (portno > 0) {
@@ -9096,18 +9321,11 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                ast_verbose("Peer audio RTP is at port %s\n",
                                            ast_sockaddr_stringify(sa));
                        }
-                       /* We are now ready to change the sip session and p->rtp and p->vrtp with the offered codecs, since
-                          they are acceptable */
-                       ast_format_cap_copy(p->jointcaps, newjointcapability);                /* Our joint codec profile for this call */
-                       ast_format_cap_copy(p->peercaps, newpeercapability);                  /* The other sides capability in latest offer */
-                       p->jointnoncodeccapability = newnoncodeccapability;     /* DTMF capabilities */
-
-                       if (ast_test_flag(&p->flags[1], SIP_PAGE2_PREFERRED_CODEC)) { /* respond with single most preferred joint codec, limiting the other side's choice */
-                               ast_codec_choose(&p->prefs, p->jointcaps, 1, &tmp_fmt);
-                               ast_format_cap_set(p->jointcaps, &tmp_fmt);
-                       }
 
                        ast_rtp_codecs_payloads_copy(&newaudiortp, ast_rtp_instance_get_codecs(p->rtp), p->rtp);
+                       /* Ensure RTCP is enabled since it may be inactive
+                          if we're coming back from a T.38 session */
+                       ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 1);
 
                        if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO) {
                                ast_clear_flag(&p->flags[0], SIP_DTMF);
@@ -9124,6 +9342,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                } else if (udptlportno > 0) {
                        if (debug)
                                ast_verbose("Got T.38 Re-invite without audio. Keeping RTP active during T.38 session.\n");
+                       /* Silence RTCP while audio RTP is inactive */
+                       ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 0);
                } else {
                        ast_rtp_instance_stop(p->rtp);
                        if (debug)
@@ -9205,7 +9425,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                                ast_channel_unlock(p->owner);
                                                if (ast_exists_extension(p->owner, target_context, "fax", 1,
                                                        S_COR(p->owner->caller.id.number.valid, p->owner->caller.id.number.str, NULL))) {
-                                                       ast_verbose(VERBOSE_PREFIX_2 "Redirecting '%s' to fax extension due to peer T.38 re-INVITE\n", p->owner->name);
+                                                       ast_verb(2, "Redirecting '%s' to fax extension due to peer T.38 re-INVITE\n", p->owner->name);
                                                        pbx_builtin_setvar_helper(p->owner, "FAXEXTEN", p->owner->exten);
                                                        if (ast_async_goto(p->owner, target_context, "fax", 1)) {
                                                                ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", p->owner->name, target_context);
@@ -9219,6 +9439,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                }
                        }
                } else {
+                       change_t38_state(p, T38_DISABLED);
                        ast_udptl_stop(p->udptl);
                        if (debug)
                                ast_debug(1, "Peer doesn't provide T.38 UDPTL\n");
@@ -9263,7 +9484,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                /* Activate a re-invite */
                ast_queue_frame(p->owner, &ast_null_frame);
                change_hold_state(p, req, FALSE, sendonly);
-       } else if ((ast_sockaddr_isnull(sa) && ast_sockaddr_isnull(vsa) && ast_sockaddr_isnull(tsa) && ast_sockaddr_isnull(isa)) || (sendonly && sendonly != -1)) {
+       } else if ((sockaddr_is_null_or_any(sa) && sockaddr_is_null_or_any(vsa) && sockaddr_is_null_or_any(tsa) && sockaddr_is_null_or_any(isa)) || (sendonly && sendonly != -1)) {
                ast_queue_control_data(p->owner, AST_CONTROL_HOLD,
                                       S_OR(p->mohsuggest, NULL),
                                       !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
@@ -9792,7 +10013,7 @@ static int add_content(struct sip_request *req, const char *line)
 /*! \brief Copy one header field from one request to another */
 static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field)
 {
-       const char *tmp = get_header(orig, field);
+       const char *tmp = sip_get_header(orig, field);
 
        if (!ast_strlen_zero(tmp)) /* Add what we're responding to */
                return add_header(req, field, tmp);
@@ -10126,7 +10347,7 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg
        if (msg[0] == '1' || msg[0] == '2')
                copy_all_header(resp, req, "Record-Route");
        copy_header(resp, req, "From");
-       ot = get_header(req, "To");
+       ot = sip_get_header(req, "To");
        if (!strcasestr(ot, "tag=") && strncmp(msg, "100", 3)) {
                /* Add the proper tag if we don't have it already.  If they have specified
                   their tag, use it.  Otherwise, use our own tag */
@@ -10249,7 +10470,7 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, in
        else {
                char *n;
                /* We have no URI, use To: or From:  header as URI (depending on direction) */
-               ast_copy_string(stripped, get_header(orig, is_outbound ? "To" : "From"),
+               ast_copy_string(stripped, sip_get_header(orig, is_outbound ? "To" : "From"),
                                sizeof(stripped));
                n = get_in_brackets(stripped);
                c = remove_uri_parameters(n);
@@ -10265,8 +10486,8 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, in
        }
        add_header_max_forwards(p, req);
 
-       ot = get_header(orig, "To");
-       of = get_header(orig, "From");
+       ot = sip_get_header(orig, "To");
+       of = sip_get_header(orig, "From");
 
        /* Add tag *unless* this is a CANCEL, in which case we need to send it exactly
           as our original request, including tag (or presumably lack thereof) */
@@ -10330,8 +10551,8 @@ static int __transmit_response(struct sip_pvt *p, const char *msg, const struct
        struct sip_request resp;
        int seqno = 0;
 
-       if (reliable && (sscanf(get_header(req, "CSeq"), "%30d ", &seqno) != 1)) {
-               ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", get_header(req, "CSeq"));
+       if (reliable && (sscanf(sip_get_header(req, "CSeq"), "%30d ", &seqno) != 1)) {
+               ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", sip_get_header(req, "CSeq"));
                return -1;
        }
        respprep(&resp, p, msg, req);
@@ -10346,6 +10567,11 @@ static int __transmit_response(struct sip_pvt *p, const char *msg, const struct
                add_cc_call_info_to_response(p, &resp);
        }
 
+       /* If we are sending a 302 Redirect we can add a diversion header if the redirect information is set */
+       if (!strncmp(msg, "302", 3)) {
+               add_diversion_header(&resp, p);
+       }
+
        /* If we are cancelling an incoming invite for some reason, add information
                about the reason why we are doing this in clear text */
        if (p->method == SIP_INVITE && msg[0] != '1') {
@@ -10559,8 +10785,8 @@ static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const
        char tmp[512];
        int seqno = 0;
 
-       if (reliable && (sscanf(get_header(req, "CSeq"), "%30d ", &seqno) != 1)) {
-               ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", get_header(req, "CSeq"));
+       if (reliable && (sscanf(sip_get_header(req, "CSeq"), "%30d ", &seqno) != 1)) {
+               ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", sip_get_header(req, "CSeq"));
                return -1;
        }
        /* Choose Realm */
@@ -10640,14 +10866,14 @@ static void get_realm(struct sip_pvt *p, const struct sip_request *req)
            !AST_LIST_EMPTY(&domain_list))
        {
                /* Check From header first */
-               if (!get_domain(get_header(req, "From"), domain, sizeof(domain))) {
+               if (!get_domain(sip_get_header(req, "From"), domain, sizeof(domain))) {
                        if (check_sip_domain(domain, NULL, 0)) {
                                ast_string_field_set(p, realm, domain);
                                return;
                        }
                }
                /* Check To header */
-               if (!get_domain(get_header(req, "To"), domain, sizeof(domain))) {
+               if (!get_domain(sip_get_header(req, "To"), domain, sizeof(domain))) {
                        if (check_sip_domain(domain, NULL, 0)) {
                                ast_string_field_set(p, realm, domain);
                                return;
@@ -10691,14 +10917,20 @@ static int add_digit(struct sip_request *req, char digit, unsigned int duration,
        int event;
        if (mode) {
                /* Application/dtmf short version used by some implementations */
-               if (digit == '*')
+               if ('0' <= digit && digit <= '9') {
+                       event = digit - '0';
+               } else if (digit == '*') {
                        event = 10;
-               else if (digit == '#')
+               } else if (digit == '#') {
                        event = 11;
-               else if ((digit >= 'A') && (digit <= 'D'))
+               } else if ('A' <= digit && digit <= 'D') {
                        event = 12 + digit - 'A';
-               else
-                       event = atoi(&digit);
+               } else if ('a' <= digit && digit <= 'd') {
+                       event = 12 + digit - 'a';
+               } else {
+                       /* Unknown digit */
+                       event = 0;
+               }
                snprintf(tmp, sizeof(tmp), "%d\r\n", event);
                add_header(req, "Content-Type", "application/dtmf");
                add_content(req, tmp);
@@ -11094,14 +11326,25 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo, int needtext
        }
 }
 
-static void get_crypto_attrib(struct sip_srtp *srtp, const char **a_crypto)
+static void get_crypto_attrib(struct sip_pvt *p, struct sip_srtp *srtp, const char **a_crypto)
 {
+       int taglen = 80;
+
        /* Set encryption properties */
        if (srtp) {
                if (!srtp->crypto) {
                        srtp->crypto = sdp_crypto_setup();
                }
-               if (srtp->crypto && (sdp_crypto_offer(srtp->crypto) >= 0)) {
+
+               /* set the key length based on INVITE or settings */
+               if (ast_test_flag(srtp, SRTP_CRYPTO_TAG_80)) {
+                       taglen = 80;
+               } else if (ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TAG_32) ||
+                   ast_test_flag(srtp, SRTP_CRYPTO_TAG_32)) {
+                       taglen = 32;
+               }
+
+               if (srtp->crypto && (sdp_crypto_offer(srtp->crypto, taglen) >= 0)) {
                        *a_crypto = sdp_crypto_attrib(srtp->crypto);
                }
 
@@ -11263,13 +11506,13 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
                        needaudio = TRUE;
 
                if (debug) {
-                       ast_verbose("Audio is at %s\n", ast_sockaddr_stringify_port(&p->ourip));
+                       ast_verbose("Audio is at %s\n", ast_sockaddr_stringify_port(&addr));
                }
 
                /* Ok, we need video. Let's add what we need for video and set codecs.
                   Video is handled differently than audio since we can not transcode. */
                if (needvideo) {
-                       get_crypto_attrib(p->vsrtp, &v_a_crypto);
+                       get_crypto_attrib(p, p->vsrtp, &v_a_crypto);
                        ast_str_append(&m_video, 0, "m=video %d RTP/%s", ast_sockaddr_port(&vdest),
                                v_a_crypto ? "SAVP" : "AVP");
 
@@ -11277,7 +11520,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
                        if (p->maxcallbitrate)
                                snprintf(bandwidth, sizeof(bandwidth), "b=CT:%d\r\n", p->maxcallbitrate);
                        if (debug) {
-                               ast_verbose("Video is at %s\n", ast_sockaddr_stringify(&p->ourip));
+                               ast_verbose("Video is at %s\n", ast_sockaddr_stringify(&vdest));
                        }
                }
 
@@ -11286,11 +11529,11 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
                if (needtext) {
                        if (sipdebug_text)
                                ast_verbose("Lets set up the text sdp\n");
-                       get_crypto_attrib(p->tsrtp, &t_a_crypto);
+                       get_crypto_attrib(p, p->tsrtp, &t_a_crypto);
                        ast_str_append(&m_text, 0, "m=text %d RTP/%s", ast_sockaddr_port(&tdest),
                                t_a_crypto ? "SAVP" : "AVP");
                        if (debug) {  /* XXX should I use tdest below ? */
-                               ast_verbose("Text is at %s\n", ast_sockaddr_stringify(&p->ourip));
+                               ast_verbose("Text is at %s\n", ast_sockaddr_stringify(&taddr));
                        }
                }
 
@@ -11299,7 +11542,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
                /* We break with the "recommendation" and send our IP, in order that our
                   peer doesn't have to ast_gethostbyname() us */
 
-               get_crypto_attrib(p->srtp, &a_crypto);
+               get_crypto_attrib(p, p->srtp, &a_crypto);
                ast_str_append(&m_audio, 0, "m=audio %d RTP/%s", ast_sockaddr_port(&dest),
                        a_crypto ? "SAVP" : "AVP");
 
@@ -11463,55 +11706,107 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
        add_content(resp, owner);
        add_content(resp, subject);
        add_content(resp, connection);
-       if (needvideo)          /* only if video response is appropriate */
+       /* only if video response is appropriate */
+       if (needvideo) {
                add_content(resp, bandwidth);
-       add_content(resp, session_time);
-       if (needaudio) {
-               add_content(resp, m_audio->str);
-               add_content(resp, a_audio->str);
-               add_content(resp, hold);
-               if (a_crypto) {
-                       add_content(resp, a_crypto);
-               }
-       } else if (p->offered_media[SDP_AUDIO].offered) {
-               snprintf(dummy_answer, sizeof(dummy_answer), "m=audio 0 RTP/AVP %s\r\n", p->offered_media[SDP_AUDIO].codecs);
-               add_content(resp, dummy_answer);
-       }
-       if (needvideo) { /* only if video response is appropriate */
-               add_content(resp, m_video->str);
-               add_content(resp, a_video->str);
-               add_content(resp, hold);        /* Repeat hold for the video stream */
-               if (v_a_crypto) {
-                       add_content(resp, v_a_crypto);
-               }
-       } else if (p->offered_media[SDP_VIDEO].offered) {
-               snprintf(dummy_answer, sizeof(dummy_answer), "m=video 0 RTP/AVP %s\r\n", p->offered_media[SDP_VIDEO].codecs);
-               add_content(resp, dummy_answer);
-       }
-       if (needtext) { /* only if text response is appropriate */
-               add_content(resp, m_text->str);
-               add_content(resp, a_text->str);
-               add_content(resp, hold);        /* Repeat hold for the text stream */
-               if (t_a_crypto) {
-                       add_content(resp, t_a_crypto);
-               }
-       } else if (p->offered_media[SDP_TEXT].offered) {
-               snprintf(dummy_answer, sizeof(dummy_answer), "m=text 0 RTP/AVP %s\r\n", p->offered_media[SDP_TEXT].codecs);
-               add_content(resp, dummy_answer);
-       }
-       if (add_t38) {
-               add_content(resp, m_modem->str);
-               add_content(resp, a_modem->str);
-       } else if (p->offered_media[SDP_IMAGE].offered) {
-               add_content(resp, "m=image 0 udptl t38\r\n");
+       }
+       add_content(resp, session_time);
+       /* if this is a response to an invite, order our offers properly */
+       if (p->offered_media[SDP_AUDIO].order_offered ||
+               p->offered_media[SDP_VIDEO].order_offered ||
+               p->offered_media[SDP_TEXT].order_offered ||
+               p->offered_media[SDP_IMAGE].order_offered) {
+               int i;
+               /* we have up to 3 streams as limited by process_sdp */
+               for (i = 1; i <= 3; i++) {
+                       if (p->offered_media[SDP_AUDIO].order_offered == i) {
+                               if (needaudio) {
+                                       add_content(resp, m_audio->str);
+                                       add_content(resp, a_audio->str);
+                                       add_content(resp, hold);
+                                       if (a_crypto) {
+                                               add_content(resp, a_crypto);
+                                       }
+                               } else {
+                                       snprintf(dummy_answer, sizeof(dummy_answer), "m=audio 0 RTP/AVP %s\r\n", p->offered_media[SDP_AUDIO].codecs);
+                                       add_content(resp, dummy_answer);
+                               }
+                       } else if (p->offered_media[SDP_VIDEO].order_offered == i) {
+                               if (needvideo) { /* only if video response is appropriate */
+                                       add_content(resp, m_video->str);
+                                       add_content(resp, a_video->str);
+                                       add_content(resp, hold);        /* Repeat hold for the video stream */
+                                       if (v_a_crypto) {
+                                               add_content(resp, v_a_crypto);
+                                       }
+                               } else {
+                                       snprintf(dummy_answer, sizeof(dummy_answer), "m=video 0 RTP/AVP %s\r\n", p->offered_media[SDP_VIDEO].codecs);
+                                       add_content(resp, dummy_answer);
+                               }
+                       } else if (p->offered_media[SDP_TEXT].order_offered == i) {
+                               if (needtext) { /* only if text response is appropriate */
+                                       add_content(resp, m_text->str);
+                                       add_content(resp, a_text->str);
+                                       add_content(resp, hold);        /* Repeat hold for the text stream */
+                                       if (t_a_crypto) {
+                                               add_content(resp, t_a_crypto);
+                                       }
+                               } else {
+                                       snprintf(dummy_answer, sizeof(dummy_answer), "m=text 0 RTP/AVP %s\r\n", p->offered_media[SDP_TEXT].codecs);
+                                       add_content(resp, dummy_answer);
+                               }
+                       } else if (p->offered_media[SDP_IMAGE].order_offered == i) {
+                               if (add_t38) {
+                                       add_content(resp, m_modem->str);
+                                       add_content(resp, a_modem->str);
+                               } else {
+                                       add_content(resp, "m=image 0 udptl t38\r\n");
+                               }
+                       }
+               }
+       } else {
+               /* generate new SDP from scratch, no offers */
+               if (needaudio) {
+                       add_content(resp, m_audio->str);
+                       add_content(resp, a_audio->str);
+                       add_content(resp, hold);
+                       if (a_crypto) {
+                               add_content(resp, a_crypto);
+                       }
+               }
+               if (needvideo) { /* only if video response is appropriate */
+                       add_content(resp, m_video->str);
+                       add_content(resp, a_video->str);
+                       add_content(resp, hold);        /* Repeat hold for the video stream */
+                       if (v_a_crypto) {
+                               add_content(resp, v_a_crypto);
+                       }
+               }
+               if (needtext) { /* only if text response is appropriate */
+                       add_content(resp, m_text->str);
+                       add_content(resp, a_text->str);
+                       add_content(resp, hold);        /* Repeat hold for the text stream */
+                       if (t_a_crypto) {
+                               add_content(resp, t_a_crypto);
+                       }
+               }
+               if (add_t38) {
+                       add_content(resp, m_modem->str);
+                       add_content(resp, a_modem->str);
+               }
        }
 
        /* Update lastrtprx when we send our SDP */
        p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
 
-       /* we unlink this dialog and link again into the dialogs_rtpcheck container to doesnt add it twice */
+       /*
+        * We unlink this dialog and link again into the
+        * dialogs_rtpcheck container so its not in there twice.
+        */
+       ao2_lock(dialogs_rtpcheck);
        ao2_t_unlink(dialogs_rtpcheck, p, "unlink pvt into dialogs_rtpcheck container");
        ao2_t_link(dialogs_rtpcheck, p, "link pvt into dialogs_rtpcheck container");
+       ao2_unlock(dialogs_rtpcheck);
 
        ast_debug(3, "Done building SDP. Settling with this capability: %s\n", ast_getformatname_multiple(buf, SIPBUFSIZE, tmpcap));
 
@@ -11528,8 +11823,8 @@ static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct s
        struct sip_request resp;
        int seqno;
 
-       if (sscanf(get_header(req, "CSeq"), "%30d ", &seqno) != 1) {
-               ast_log(LOG_WARNING, "Unable to get seqno from '%s'\n", get_header(req, "CSeq"));
+       if (sscanf(sip_get_header(req, "CSeq"), "%30d ", &seqno) != 1) {
+               ast_log(LOG_WARNING, "Unable to get seqno from '%s'\n", sip_get_header(req, "CSeq"));
                return -1;
        }
        respprep(&resp, p, msg, req);
@@ -11609,8 +11904,8 @@ static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const
 {
        struct sip_request resp;
        int seqno;
-       if (sscanf(get_header(req, "CSeq"), "%30d ", &seqno) != 1) {
-               ast_log(LOG_WARNING, "Unable to get seqno from '%s'\n", get_header(req, "CSeq"));
+       if (sscanf(sip_get_header(req, "CSeq"), "%30d ", &seqno) != 1) {
+               ast_log(LOG_WARNING, "Unable to get seqno from '%s'\n", sip_get_header(req, "CSeq"));
                return -1;
        }
        respprep(&resp, p, msg, req);
@@ -11753,7 +12048,7 @@ static void extract_uri(struct sip_pvt *p, struct sip_request *req)
        char stripped[SIPBUFSIZE];
        char *c;
 
-       ast_copy_string(stripped, get_header(req, "Contact"), sizeof(stripped));
+       ast_copy_string(stripped, sip_get_header(req, "Contact"), sizeof(stripped));
        c = get_in_brackets(stripped);
        /* Cut the URI at the at sign after the @, not in the username part */
        c = remove_uri_parameters(c);
@@ -11775,7 +12070,7 @@ static void build_contact(struct sip_pvt *p)
        } else {
                ast_string_field_build(p, our_contact, "<sip:%s%s%s;transport=%s>", user,
                        ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify_remote(&p->ourip),
-                       get_transport(p->socket.type));
+                       sip_get_transport(p->socket.type));
        }
 }
 
@@ -11792,6 +12087,8 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
        const char *d = NULL;   /* domain in from header */
        const char *urioptions = "";
        int ourport;
+       int cid_has_name = 1;
+       int cid_has_num = 1;
 
        if (ast_test_flag(&p->flags[0], SIP_USEREQPHONE)) {
                const char *s = p->username;    /* being a string field, cannot be NULL */
@@ -11838,10 +12135,15 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
                l = p->mwi_from;
        }
 
-       if (ast_strlen_zero(l))
+       if (ast_strlen_zero(l)) {
+               cid_has_num = 0;
                l = default_callerid;
-       if (ast_strlen_zero(n))
+       }
+       if (ast_strlen_zero(n)) {
+               cid_has_name = 0;
                n = l;
+       }
+
        /* Allow user to be overridden */
        if (!ast_strlen_zero(p->fromuser))
                l = p->fromuser;
@@ -11862,10 +12164,20 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
        }
 
        ourport = (p->fromdomainport) ? p->fromdomainport : ast_sockaddr_port(&p->ourip);
+
+       /* If a caller id name was specified, add a display name. */
+       if (cid_has_name || !cid_has_num) {
+               snprintf(from, sizeof(from), "\"%s\" ", n);
+       } else {
+               from[0] = '\0';
+       }
+
        if (!sip_standard_port(p->socket.type, ourport)) {
-               snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s:%d>;tag=%s", n, l, d, ourport, p->tag);
+               size_t offset = strlen(from);
+               snprintf(&from[offset], sizeof(from) - offset, "<sip:%s@%s:%d>;tag=%s", l, d, ourport, p->tag);
        } else {
-               snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s>;tag=%s", n, l, d, p->tag);
+               size_t offset = strlen(from);
+               snprintf(&from[offset], sizeof(from) - offset, "<sip:%s@%s>;tag=%s", l, d, p->tag);
        }
 
        if (!ast_strlen_zero(explicit_uri)) {
@@ -12004,7 +12316,7 @@ static int transmit_publish(struct sip_epa_entry *epa_entry, enum sip_publish_ty
 
        if (create_addr(pvt, epa_entry->destination, NULL, TRUE, NULL)) {
                sip_pvt_unlock(pvt);
-               dialog_unlink_all(pvt, TRUE, TRUE);
+               dialog_unlink_all(pvt);
                dialog_unref(pvt, "create_addr failed in transmit_publish. Unref dialog");
                return -1;
        }
@@ -12246,7 +12558,7 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi)
        
        /* Setup the destination of our subscription */
        if (create_addr(mwi->call, mwi->hostname, &mwi->us, 0, NULL)) {
-               dialog_unlink_all(mwi->call, TRUE, TRUE);
+               dialog_unlink_all(mwi->call);
                mwi->call = dialog_unref(mwi->call, "unref dialog after unlink_all");
                return 0;
        }
@@ -12279,7 +12591,10 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi)
        ast_sip_ouraddrfor(&mwi->call->sa, &mwi->call->ourip, mwi->call);
        build_contact(mwi->call);
        build_via(mwi->call);
-       build_callid_pvt(mwi->call);
+
+       /* Change the dialog callid. */
+       change_callid_pvt(mwi->call, NULL);
+
        ast_set_flag(&mwi->call->flags[0], SIP_OUTGOING);
        
        /* Associate the call with us */
@@ -12529,7 +12844,7 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full, int tim
 
        subscriptiontype = find_subscription_type(p->subscribed);
 
-       ast_copy_string(from, get_header(&p->initreq, "From"), sizeof(from));
+       ast_copy_string(from, sip_get_header(&p->initreq, "From"), sizeof(from));
        c = get_in_brackets(from);
        if (strncasecmp(c, "sip:", 4) && strncasecmp(c, "sips:", 5)) {
                ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", c);
@@ -12538,7 +12853,7 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full, int tim
 
        mfrom = remove_uri_parameters(c);
 
-       ast_copy_string(to, get_header(&p->initreq, "To"), sizeof(to));
+       ast_copy_string(to, sip_get_header(&p->initreq, "To"), sizeof(to));
        c = get_in_brackets(to);
        if (strncasecmp(c, "sip:", 4) && strncasecmp(c, "sips:", 5)) {
                ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", c);
@@ -12623,13 +12938,13 @@ static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs,
                if (p->socket.type == SIP_TRANSPORT_UDP) {
                        ast_str_append(&out, 0, "Message-Account: sip:%s@%s:%d\r\n", exten, domain, ourport);
                } else {
-                       ast_str_append(&out, 0, "Message-Account: sip:%s@%s:%d;transport=%s\r\n", exten, domain, ourport, get_transport(p->socket.type));
+                       ast_str_append(&out, 0, "Message-Account: sip:%s@%s:%d;transport=%s\r\n", exten, domain, ourport, sip_get_transport(p->socket.type));
                }
        } else {
                if (p->socket.type == SIP_TRANSPORT_UDP) {
                        ast_str_append(&out, 0, "Message-Account: sip:%s@%s\r\n", exten, domain);
                } else {
-                       ast_str_append(&out, 0, "Message-Account: sip:%s@%s;transport=%s\r\n", exten, domain, get_transport(p->socket.type));
+                       ast_str_append(&out, 0, "Message-Account: sip:%s@%s;transport=%s\r\n", exten, domain, sip_get_transport(p->socket.type));
                }
        }
        /* Cisco has a bug in the SIP stack where it can't accept the
@@ -12701,7 +13016,7 @@ static int manager_sipnotify(struct mansession *s, const struct message *m)
 
        if (create_addr(p, channame, NULL, 0, NULL)) {
                /* Maybe they're not registered, etc. */
-               dialog_unlink_all(p, TRUE, TRUE);
+               dialog_unlink_all(p);
                dialog_unref(p, "unref dialog inside for loop" );
                /* sip_destroy(p); */
                astman_send_error(s, m, "Could not create address");
@@ -12727,9 +13042,9 @@ static int manager_sipnotify(struct mansession *s, const struct message *m)
                }
        }
 
-       dialog_ref(p, "bump the count of p, which transmit_sip_request will decrement.");
        sip_scheddestroy(p, SIP_TRANS_TIMEOUT);
        transmit_invite(p, SIP_NOTIFY, 0, 2, NULL);
+       dialog_unref(p, "bump down the count of p since we're done with it.");
 
        astman_send_ack(s, m, "Notify Sent");
        ast_variables_destroy(vars);
@@ -12784,7 +13099,7 @@ static void update_connectedline(struct sip_pvt *p, const void *data, size_t dat
                        ast_set_flag(&p->flags[0], SIP_OUTGOING);
                        p->invitestate = INV_CALLING;
                        send_request(p, &req, XMIT_CRITICAL, p->ocseq);
-               } else if (is_method_allowed(&p->allowed_methods, SIP_UPDATE)) {
+               } else if ((is_method_allowed(&p->allowed_methods, SIP_UPDATE)) && (!ast_strlen_zero(p->okcontacturi))) { 
                        reqprep(&req, p, SIP_UPDATE, 0, 1);
                        add_rpid(&req, p);
                        add_header(&req, "X-Asterisk-rpid-update", "Yes");
@@ -12897,8 +13212,17 @@ static int sip_reg_timeout(const void *data)
        }
 
        if (r->dnsmgr) {
+               struct sip_peer *peer;
                /* If the registration has timed out, maybe the IP changed.  Force a refresh. */
                ast_dnsmgr_refresh(r->dnsmgr);
+               /* If we are resolving a peer, we have to make sure the refreshed address gets copied */
+               if ((peer = sip_find_peer(r->hostname, NULL, TRUE, FINDPEERS, FALSE, 0))) {
+                       ast_sockaddr_copy(&peer->addr, &r->us);
+                       if (r->portno) {
+                               ast_sockaddr_set_port(&peer->addr, r->portno);
+                       }
+                       peer = sip_unref_peer(peer, "unref after sip_find_peer");
+               }
        }
 
        /* If the initial tranmission failed, we may not have an existing dialog,
@@ -12978,12 +13302,12 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
 
        if (r->dnsmgr == NULL) {
                char transport[MAXHOSTNAMELEN];
-               peer = find_peer(r->hostname, NULL, TRUE, FINDPEERS, FALSE, 0);
-               snprintf(transport, sizeof(transport), "_%s._%s",get_srv_service(r->transport), get_srv_protocol(r->transport)); /* have to use static get_transport function */
+               peer = sip_find_peer(r->hostname, NULL, TRUE, FINDPEERS, FALSE, 0);
+               snprintf(transport, sizeof(transport), "_%s._%s",get_srv_service(r->transport), get_srv_protocol(r->transport)); /* have to use static sip_get_transport function */
                r->us.ss.ss_family = get_address_family_filter(&bindaddr); /* Filter address family */
                ast_dnsmgr_lookup(peer ? peer->tohost : r->hostname, &r->us, &r->dnsmgr, sip_cfg.srvlookup ? transport : NULL);
                if (peer) {
-                       peer = unref_peer(peer, "removing peer ref for dnsmgr_lookup");
+                       peer = sip_unref_peer(peer, "removing peer ref for dnsmgr_lookup");
                }
        }
 
@@ -13017,11 +13341,21 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
                        ast_sockaddr_set_port(&r->us, r->portno);
                }
 
+               /* It is possible that DNS is unavailable at the time the peer is created. Here, if
+                * we've updated the address in the registry, we copy it to the peer so that
+                * create_addr() can copy it to the dialog via create_addr_from_peer */
+               if ((peer = sip_find_peer(r->hostname, NULL, TRUE, FINDPEERS, FALSE, 0))) {
+                       if (ast_sockaddr_isnull(&peer->addr) && !(ast_sockaddr_isnull(&r->us))) {
+                               ast_sockaddr_copy(&peer->addr, &r->us);
+                       }
+                       peer = sip_unref_peer(peer, "unref after sip_find_peer");
+               }
+
                /* Find address to hostname */
                if (create_addr(p, S_OR(r->peername, r->hostname), &r->us, 0, NULL)) {
                        /* we have what we hope is a temporary network error,
                         * probably DNS.  We need to reschedule a registration try */
-                       dialog_unlink_all(p, TRUE, TRUE);
+                       dialog_unlink_all(p);
                        p = dialog_unref(p, "unref dialog after unlink_all");
                        if (r->timeout > -1) {
                                AST_SCHED_REPLACE_UNREF(r->timeout, sched, global_reg_timeout * 1000, sip_reg_timeout, r,
@@ -13268,9 +13602,9 @@ static int transmit_refer(struct sip_pvt *p, const char *dest)
 
        /* Are we transfering an inbound or outbound call ? */
        if (ast_test_flag(&p->flags[0], SIP_OUTGOING))  {
-               of = get_header(&p->initreq, "To");
+               of = sip_get_header(&p->initreq, "To");
        } else {
-               of = get_header(&p->initreq, "From");
+               of = sip_get_header(&p->initreq, "From");
        }
 
        ast_copy_string(from, of, sizeof(from));
@@ -13411,7 +13745,7 @@ static int transmit_request(struct sip_pvt *p, int sipmethod, int seqno, enum xm
 }
 
 /*! \brief return the request and response header for a 401 or 407 code */
-static void auth_headers(enum sip_auth_type code, char **header, char **respheader)
+void sip_auth_headers(enum sip_auth_type code, char **header, char **respheader)
 {
        if (code == WWW_AUTH) {                 /* 401 */
                *header = "WWW-Authenticate";
@@ -13438,7 +13772,7 @@ static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int seqn
                if(!build_reply_digest(p, sipmethod, digest, sizeof(digest))) {
                        char *dummy, *response;
                        enum sip_auth_type code = p->options ? p->options->auth_type : PROXY_AUTH; /* XXX force 407 if unknown */
-                       auth_headers(code, &dummy, &response);
+                       sip_auth_headers(code, &dummy, &response);
                        add_header(&resp, response, digest);
                } else {
                        ast_log(LOG_WARNING, "No authentication available for call %s\n", p->callid);
@@ -13540,7 +13874,7 @@ static int expire_register(const void *data)
         * in order to unlink from the peers_by_ip container correctly */
        memset(&peer->addr, 0, sizeof(peer->addr));
 
-       unref_peer(peer, "removing peer ref for expire_register");
+       sip_unref_peer(peer, "removing peer ref for expire_register");
 
        return 0;
 }
@@ -13555,17 +13889,17 @@ static int sip_poke_peer_s(const void *data)
 
        foundpeer = ao2_find(peers, peer, OBJ_POINTER);
        if (!foundpeer) {
-               unref_peer(peer, "removing poke peer ref");
+               sip_unref_peer(peer, "removing poke peer ref");
                return 0;
        } else if (foundpeer->name != peer->name) {
-               unref_peer(foundpeer, "removing above peer ref");
-               unref_peer(peer, "removing poke peer ref");
+               sip_unref_peer(foundpeer, "removing above peer ref");
+               sip_unref_peer(peer, "removing poke peer ref");
                return 0;
        }
 
-       unref_peer(foundpeer, "removing above peer ref");
+       sip_unref_peer(foundpeer, "removing above peer ref");
        sip_poke_peer(peer, 0);
-       unref_peer(peer, "removing poke peer ref");
+       sip_unref_peer(peer, "removing poke peer ref");
 
        return 0;
 }
@@ -13621,16 +13955,16 @@ static void reg_source_db(struct sip_peer *peer)
        if (sipsock < 0) {
                /* SIP isn't up yet, so schedule a poke only, pretty soon */
                AST_SCHED_REPLACE_UNREF(peer->pokeexpire, sched, ast_random() % 5000 + 1, sip_poke_peer_s, peer,
-                               unref_peer(_data, "removing poke peer ref"),
-                               unref_peer(peer, "removing poke peer ref"),
-                               ref_peer(peer, "adding poke peer ref"));
+                               sip_unref_peer(_data, "removing poke peer ref"),
+                               sip_unref_peer(peer, "removing poke peer ref"),
+                               sip_ref_peer(peer, "adding poke peer ref"));
        } else {
                sip_poke_peer(peer, 0);
        }
        AST_SCHED_REPLACE_UNREF(peer->expire, sched, (expire + 10) * 1000, expire_register, peer,
-                       unref_peer(_data, "remove registration ref"),
-                       unref_peer(peer, "remove registration ref"),
-                       ref_peer(peer, "add registration ref"));
+                       sip_unref_peer(_data, "remove registration ref"),
+                       sip_unref_peer(peer, "remove registration ref"),
+                       sip_ref_peer(peer, "add registration ref"));
        register_peer_exten(peer, TRUE);
 }
 
@@ -13641,7 +13975,7 @@ static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req)
        char *c;
 
        /* Look for brackets */
-       ast_copy_string(contact, get_header(req, "Contact"), sizeof(contact));
+       ast_copy_string(contact, sip_get_header(req, "Contact"), sizeof(contact));
        c = get_in_brackets(contact);
 
        /* Save full contact to call pvt for later bye or re-invite */
@@ -13655,10 +13989,15 @@ static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req)
        return TRUE;            
 }
 
-/*! \brief parse uri in a way that allows semicolon stripping if legacy mode is enabled */
-static int parse_uri_legacy_check(char *uri, const char *scheme, char **user, char **pass, char **domain, char **transport)
+/*! \brief parse uri in a way that allows semicolon stripping if legacy mode is enabled
+ *
+ * \note This calls parse_uri which has the unexpected property that passing more
+ *       arguments results in more splitting. Most common is to leave out the pass
+ *       argument, causing user to contain user:pass if available.
+ */
+static int parse_uri_legacy_check(char *uri, const char *scheme, char **user, char **pass, char **hostport, char **transport)
 {
-       int ret = parse_uri(uri, scheme, user, pass, domain, transport);
+       int ret = parse_uri(uri, scheme, user, pass, hostport, transport);
        if (sip_cfg.legacy_useroption_parsing) { /* if legacy mode is active, strip semis from the user field */
                char *p;
                if ((p = strchr(uri, (int)';'))) {
@@ -13670,7 +14009,7 @@ static int parse_uri_legacy_check(char *uri, const char *scheme, char **user, ch
 
 static int __set_address_from_contact(const char *fullcontact, struct ast_sockaddr *addr, int tcp)
 {
-       char *domain, *transport;
+       char *hostport, *transport;
        char contact_buf[256];
        char *contact;
 
@@ -13685,7 +14024,7 @@ static int __set_address_from_contact(const char *fullcontact, struct ast_sockad
         * We still need to be able to send to the remote agent through the proxy.
         */
 
-       if (parse_uri_legacy_check(contact, "sip:,sips:", &contact, NULL, &domain,
+       if (parse_uri_legacy_check(contact, "sip:,sips:", &contact, NULL, &hostport,
                      &transport)) {
                ast_log(LOG_WARNING, "Invalid contact uri %s (missing sip: or sips:), attempting to use anyway\n", fullcontact);
        }
@@ -13694,19 +14033,19 @@ static int __set_address_from_contact(const char *fullcontact, struct ast_sockad
        /* We should only do this if it's a name, not an IP */
        /* \todo - if there's no PORT number in contact - we are required to check NAPTR/SRV records
                to find transport, port address and hostname. If there's a port number, we have to
-               assume that the domain part is a host name and only look for an A/AAAA record in DNS.
+               assume that the hostport part is a host name and only look for an A/AAAA record in DNS.
        */
 
-       /* If we took in an invalid URI, domain may not have been initialized */
-       /* ast_sockaddr_resolve requires an initialized domain string. */
-       if (ast_strlen_zero(domain)) {
-               ast_log(LOG_WARNING, "Invalid URI: parse_uri failed to acquire domain\n");
+       /* If we took in an invalid URI, hostport may not have been initialized */
+       /* ast_sockaddr_resolve requires an initialized hostport string. */
+       if (ast_strlen_zero(hostport)) {
+               ast_log(LOG_WARNING, "Invalid URI: parse_uri failed to acquire hostport\n");
                return -1;
        }
 
-       if (ast_sockaddr_resolve_first(addr, domain, 0)) {
+       if (ast_sockaddr_resolve_first(addr, hostport, 0)) {
                ast_log(LOG_WARNING, "Invalid host name in Contact: (can't "
-                       "resolve in DNS) : '%s'\n", domain);
+                       "resolve in DNS) : '%s'\n", hostport);
                return -1;
        }
 
@@ -13741,9 +14080,9 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
 {
        char contact[SIPBUFSIZE];
        char data[SIPBUFSIZE];
-       const char *expires = get_header(req, "Expires");
+       const char *expires = sip_get_header(req, "Expires");
        int expire = atoi(expires);
-       char *curi, *domain, *transport;
+       char *curi = NULL, *hostport = NULL, *transport = NULL;
        int transport_type;
        const char *useragent;
        struct ast_sockaddr oldsin, testsa;
@@ -13808,9 +14147,9 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
        } else if (!strcasecmp(curi, "*") || !expire) { /* Unregister this peer */
                /* This means remove all registrations and return OK */
                AST_SCHED_DEL_UNREF(sched, peer->expire,
-                               unref_peer(peer, "remove register expire ref"));
+                               sip_unref_peer(peer, "remove register expire ref"));
                ast_verb(3, "Unregistered SIP '%s'\n", peer->name);
-               expire_register(ref_peer(peer,"add ref for explicit expire_register"));
+               expire_register(sip_ref_peer(peer,"add ref for explicit expire_register"));
                return PARSE_REGISTER_UPDATE;
        }
 
@@ -13821,7 +14160,7 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
        ast_string_field_build(pvt, our_contact, "<%s>", curi);
 
        /* Make sure it's a SIP URL */
-       if (parse_uri_legacy_check(curi, "sip:,sips:", &curi, NULL, &domain, &transport)) {
+       if (ast_strlen_zero(curi) || parse_uri_legacy_check(curi, "sip:,sips:", &curi, NULL, &hostport, &transport)) {
                ast_log(LOG_NOTICE, "Not a valid SIP contact (missing sip:/sips:) trying to use anyway\n");
        }
 
@@ -13849,15 +14188,15 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
                ast_debug(1, "Store REGISTER's Contact header for call routing.\n");
                /* XXX This could block for a long time XXX */
                /*! \todo Check NAPTR/SRV if we have not got a port in the URI */
-               if (ast_sockaddr_resolve_first(&testsa, domain, 0)) {
-                       ast_log(LOG_WARNING, "Invalid domain '%s'\n", domain);
+               if (ast_sockaddr_resolve_first(&testsa, hostport, 0)) {
+                       ast_log(LOG_WARNING, "Invalid hostport '%s'\n", hostport);
                        ast_string_field_set(peer, fullcontact, "");
                        ast_string_field_set(pvt, our_contact, "");
                        return PARSE_REGISTER_FAILED;
                }
 
                /* If we have a port number in the given URI, make sure we do remember to not check for NAPTR/SRV records.
-                  The domain part is actually a host. */
+                  The hostport part is actually a host. */
                peer->portinuri = ast_sockaddr_port(&testsa) ? TRUE : FALSE;
 
                if (!ast_sockaddr_port(&testsa)) {
@@ -13877,7 +14216,7 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
        /* Check that they're allowed to register at this IP */
        if (ast_apply_ha(sip_cfg.contact_ha, &peer->addr) != AST_SENSE_ALLOW ||
                        ast_apply_ha(peer->contactha, &peer->addr) != AST_SENSE_ALLOW) {
-               ast_log(LOG_WARNING, "Domain '%s' disallowed by contact ACL (violating IP %s)\n", domain,
+               ast_log(LOG_WARNING, "Domain '%s' disallowed by contact ACL (violating IP %s)\n", hostport,
                        ast_sockaddr_stringify_addr(&testsa));
                ast_string_field_set(peer, fullcontact, "");
                ast_string_field_set(pvt, our_contact, "");
@@ -13905,7 +14244,7 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
        }
 
        AST_SCHED_DEL_UNREF(sched, peer->expire,
-                       unref_peer(peer, "remove register expire ref"));
+                       sip_unref_peer(peer, "remove register expire ref"));
 
        if (expire > max_expiry) {
                expire = max_expiry;
@@ -13917,9 +14256,9 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
                peer->expire = -1;
        } else {
                peer->expire = ast_sched_add(sched, (expire + 10) * 1000, expire_register,
-                               ref_peer(peer, "add registration ref"));
+                               sip_ref_peer(peer, "add registration ref"));
                if (peer->expire == -1) {
-                       unref_peer(peer, "remote registration ref");
+                       sip_unref_peer(peer, "remote registration ref");
                }
        }
        pvt->expiry = expire;
@@ -13931,15 +14270,15 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
        manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Registered\r\nAddress: %s\r\n", peer->name,  ast_sockaddr_stringify(&peer->addr));
 
        /* Is this a new IP address for us? */
-       if (VERBOSITY_ATLEAST(2) && ast_sockaddr_cmp(&peer->addr, &oldsin)) {
-               ast_verbose(VERBOSE_PREFIX_3 "Registered SIP '%s' at %s\n", peer->name,
-                               ast_sockaddr_stringify(&peer->addr));
+       if (ast_sockaddr_cmp(&peer->addr, &oldsin)) {
+               ast_verb(3, "Registered SIP '%s' at %s\n", peer->name,
+                       ast_sockaddr_stringify(&peer->addr));
        }
        sip_poke_peer(peer, 0);
        register_peer_exten(peer, 1);
-       
+
        /* Save User agent */
-       useragent = get_header(req, "User-Agent");
+       useragent = sip_get_header(req, "User-Agent");
        if (strcasecmp(useragent, peer->useragent)) {
                ast_string_field_set(peer, useragent, useragent);
                ast_verb(4, "Saved useragent \"%s\" for peer %s\n", peer->useragent, peer->name);
@@ -14041,7 +14380,7 @@ static void build_route(struct sip_pvt *p, struct sip_request *req, int backward
        if (!head || (!ast_strlen_zero(head->hop) && strstr(head->hop, ";lr") == NULL) ) {
                /* 2nd append the Contact: if there is one */
                /* Can be multiple Contact headers, comma separated values - we just take the first */
-               contact = get_header(req, "Contact");
+               contact = sip_get_header(req, "Contact");
                if (!ast_strlen_zero(contact)) {
                        ast_debug(2, "build_route: Contact hop: %s\n", contact);
                        /* Look for <: delimited address */
@@ -14092,8 +14431,33 @@ static void set_nonce_randdata(struct sip_pvt *p, int forceupdate)
        }
 }
 
-AST_THREADSTORAGE(check_auth_buf);
-#define CHECK_AUTH_BUF_INITLEN   256
+/*! \brief Takes the digest response and parses it */
+void sip_digest_parser(char *c, struct digestkeys *keys)
+{
+        struct digestkeys *i = i;
+
+        while(c && *(c = ast_skip_blanks(c)) ) { /* lookup for keys */
+                for (i = keys; i->key != NULL; i++) {
+                        const char *separator = ",";    /* default */
+
+                        if (strncasecmp(c, i->key, strlen(i->key)) != 0) {
+                                continue;
+                        }
+                        /* Found. Skip keyword, take text in quotes or up to the separator. */
+                        c += strlen(i->key);
+                        if (*c == '"') { /* in quotes. Skip first and look for last */
+                                c++;
+                                separator = "\"";
+                        }
+                        i->s = c;
+                        strsep(&c, separator);
+                        break;
+                }
+                if (i->key == NULL) { /* not found, jump after space or comma */
+                       strsep(&c, " ,");
+               }
+        }
+}
 
 /*! \brief  Check user authorization from peer definition
        Some actions, like REGISTER and INVITEs from peers require
@@ -14117,11 +14481,7 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *
        int res;
 
        /* table of recognised keywords, and their value in the digest */
-       enum keys { K_RESP, K_URI, K_USER, K_NONCE, K_LAST };
-       struct x {
-               const char *key;
-               const char *s;
-       } *i, keys[] = {
+       struct digestkeys keys[] = {
                [K_RESP] = { "response=", "" },
                [K_URI] = { "uri=", "" },
                [K_USER] = { "username=", "" },
@@ -14130,8 +14490,9 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *
        };
 
        /* Always OK if no secret */
-       if (ast_strlen_zero(secret) && ast_strlen_zero(md5secret))
+       if (ast_strlen_zero(secret) && ast_strlen_zero(md5secret)) {
                return AUTH_SUCCESSFUL;
+       }
 
        /* Always auth with WWW-auth since we're NOT a proxy */
        /* Using proxy-auth in a B2BUA may block proxy authorization in the same transaction */
@@ -14139,11 +14500,11 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *
 
        /*
         * Note the apparent swap of arguments below, compared to other
-        * usages of auth_headers().
+        * usages of sip_auth_headers().
         */
-       auth_headers(WWW_AUTH, &respheader, &reqheader);
+       sip_auth_headers(WWW_AUTH, &respheader, &reqheader);
 
-       authtoken =  get_header(req, reqheader);        
+       authtoken =  sip_get_header(req, reqheader);    
        if (ignore && !ast_strlen_zero(p->randdata) && ast_strlen_zero(authtoken)) {
                /* This is a retransmitted invite/register/etc, don't reconstruct authentication
                   information */
@@ -14182,27 +14543,7 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *
 
        c = buf->str;
 
-       while(c && *(c = ast_skip_blanks(c)) ) { /* lookup for keys */
-               for (i = keys; i->key != NULL; i++) {
-                       const char *separator = ",";    /* default */
-
-                       if (strncasecmp(c, i->key, strlen(i->key)) != 0) {
-                               continue;
-                       }
-                       /* Found. Skip keyword, take text in quotes or up to the separator. */
-                       c += strlen(i->key);
-                       if (*c == '"') { /* in quotes. Skip first and look for last */
-                               c++;
-                               separator = "\"";
-                       }
-                       i->s = c;
-                       strsep(&c, separator);
-                       break;
-               }
-               if (i->key == NULL) { /* not found, jump after space or comma */
-                       strsep(&c, " ,");
-               }
-       }
+       sip_digest_parser(c, keys);
 
        /* Verify that digest username matches  the username we auth as */
        if (strcmp(username, keys[K_USER].s)) {
@@ -14248,7 +14589,7 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *
        if (wrongnonce) {
                if (good_response) {
                        if (sipdebug)
-                               ast_log(LOG_NOTICE, "Correct auth, but based on stale nonce received from '%s'\n", get_header(req, "From"));
+                               ast_log(LOG_NOTICE, "Correct auth, but based on stale nonce received from '%s'\n", sip_get_header(req, "From"));
                        /* We got working auth token, based on stale nonce . */
                        set_nonce_randdata(p, 0);
                        transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, TRUE);
@@ -14256,12 +14597,12 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *
                        /* Everything was wrong, so give the device one more try with a new challenge */
                        if (!req->ignore) {
                                if (sipdebug) {
-                                       ast_log(LOG_NOTICE, "Bad authentication received from '%s'\n", get_header(req, "To"));
+                                       ast_log(LOG_NOTICE, "Bad authentication received from '%s'\n", sip_get_header(req, "To"));
                                }
                                set_nonce_randdata(p, 1);
                        } else {
                                if (sipdebug) {
-                                       ast_log(LOG_NOTICE, "Duplicate authentication received from '%s'\n", get_header(req, "To"));
+                                       ast_log(LOG_NOTICE, "Duplicate authentication received from '%s'\n", sip_get_header(req, "To"));
                                }
                        }
                        transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, FALSE);
@@ -14305,9 +14646,7 @@ static void mwi_event_cb(const struct ast_event *event, void *userdata)
 {
        struct sip_peer *peer = userdata;
 
-       ao2_lock(peer);
-       sip_send_mwi_to_peer(peer, event, 0);
-       ao2_unlock(peer);
+       sip_send_mwi_to_peer(peer, 0);
 }
 
 static void network_change_event_subscribe(void)
@@ -14341,6 +14680,13 @@ static void network_change_event_cb(const struct ast_event *event, void *userdat
        }
 }
 
+static void cb_extensionstate_destroy(int id, void *data)
+{
+       struct sip_pvt *p = data;
+
+       dialog_unref(p, "the extensionstate containing this dialog ptr was destroyed");
+}
+
 /*! \brief Callback for the devicestate notification (SUBSCRIBE) support subsystem
 \note  If you add an "hint" priority to the extension in the dial plan,
        you will get notifications on device state changes */
@@ -14355,7 +14701,6 @@ static int cb_extensionstate(const char *context, const char *exten, enum ast_ex
        case AST_EXTENSION_REMOVED:     /* Extension is gone */
                sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);     /* Delete subscription in 32 secs */
                ast_verb(2, "Extension state: Watcher for hint %s %s. Notify User %s\n", exten, state == AST_EXTENSION_DEACTIVATED ? "deactivated" : "removed", p->username);
-               p->stateid = -1;
                p->subscribed = NONE;
                append_history(p, "Subscribestatus", "%s", state == AST_EXTENSION_REMOVED ? "HintRemoved" : "Deactivated");
                break;
@@ -14409,7 +14754,7 @@ static void transmit_fake_auth_response(struct sip_pvt *p, int sipmethod, struct
                reqheader = "Authorization";
                respheader = "WWW-Authenticate";
        }
-       authtoken = get_header(req, reqheader);
+       authtoken = sip_get_header(req, reqheader);
        if (req->ignore && !ast_strlen_zero(p->randdata) && ast_strlen_zero(authtoken)) {
                /* This is a retransmitted invite/register/etc, don't reconstruct authentication
                 * information */
@@ -14499,6 +14844,18 @@ static char *terminate_uri(char *uri)
        return uri;
 }
 
+/*! \brief Terminate a host:port at the ':'
+ * \param hostport The address of the hostport string
+ *
+ * \note In the case of a bracket-enclosed IPv6 address, the hostport variable
+ * will contain the non-bracketed host as a result of calling this function.
+ */
+static void extract_host_from_hostport(char **hostport)
+{
+       char *dont_care;
+       ast_sockaddr_split_hostport(*hostport, hostport, &dont_care, PARSE_PORT_IGNORE);
+}
+
 /*! \brief Verify registration of user
        - Registration is done in several steps, first a REGISTER without auth
          to get a challenge (nonce) then a second one with auth
@@ -14510,17 +14867,17 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
        enum check_auth_result res = AUTH_NOT_FOUND;
        struct sip_peer *peer;
        char tmp[256];
-       char *name = NULL, *c, *domain = NULL, *dummy = NULL;
+       char *c, *name, *unused_password, *domain;
        char *uri2 = ast_strdupa(uri);
 
        terminate_uri(uri2);
 
-       ast_copy_string(tmp, get_header(req, "To"), sizeof(tmp));
+       ast_copy_string(tmp, sip_get_header(req, "To"), sizeof(tmp));
 
        c = get_in_brackets(tmp);
        c = remove_uri_parameters(c);
 
-       if (parse_uri_legacy_check(c, "sip:,sips:", &name, &dummy, &domain, NULL)) {
+       if (parse_uri_legacy_check(c, "sip:,sips:", &name, &unused_password, &domain, NULL)) {
                ast_log(LOG_NOTICE, "Invalid to address: '%s' from %s (missing sip:) trying to use anyway...\n", c, ast_sockaddr_stringify_addr(addr));
                return -1;
        }
@@ -14528,12 +14885,36 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
        SIP_PEDANTIC_DECODE(name);
        SIP_PEDANTIC_DECODE(domain);
 
-       /*! \todo XXX here too we interpret a missing @domain as a name-only
-        * URI, whereas the RFC says this is a domain-only uri.
-        */
-       if (!ast_strlen_zero(domain) && !AST_LIST_EMPTY(&domain_list)) {
+       extract_host_from_hostport(&domain);
+
+       if (ast_strlen_zero(domain)) {
+               /* <sip:name@[EMPTY]>, never good */
+               transmit_response(p, "404 Not found", &p->initreq);
+               return AUTH_UNKNOWN_DOMAIN;
+       }
+
+       if (ast_strlen_zero(name)) {
+               /* <sip:[EMPTY][@]hostport>, unsure whether valid for
+                * registration. RFC 3261, 10.2 states:
+                * "The To header field and the Request-URI field typically
+                * differ, as the former contains a user name."
+                * But, Asterisk has always treated the domain-only uri as a
+                * username: we allow admins to create accounts described by
+                * domain name. */
+               name = domain;
+       }
+
+       /* This here differs from 1.4 and 1.6: the domain matching ACLs were
+        * skipped if it was a domain-only URI (used as username). Here we treat
+        * <sip:hostport> as <sip:host@hostport> and won't forget to test the
+        * domain ACLs against host. */
+       if (!AST_LIST_EMPTY(&domain_list)) {
                if (!check_sip_domain(domain, NULL, 0)) {
-                       transmit_response(p, "404 Not found (unknown domain)", &p->initreq);
+                       if (sip_cfg.alwaysauthreject) {
+                               transmit_fake_auth_response(p, SIP_REGISTER, &p->initreq, XMIT_UNRELIABLE);
+                       } else {
+                               transmit_response(p, "404 Not found (unknown domain)", &p->initreq);
+                       }
                        return AUTH_UNKNOWN_DOMAIN;
                }
        }
@@ -14542,11 +14923,11 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
        build_contact(p);
        if (req->ignore) {
                /* Expires is a special case, where we only want to load the peer if this isn't a deregistration attempt */
-               const char *expires = get_header(req, "Expires");
+               const char *expires = sip_get_header(req, "Expires");
                int expire = atoi(expires);
 
                if (ast_strlen_zero(expires)) { /* No expires header; look in Contact */
-                       if ((expires = strcasestr(get_header(req, "Contact"), ";expires="))) {
+                       if ((expires = strcasestr(sip_get_header(req, "Contact"), ";expires="))) {
                                expire = atoi(expires + 9);
                        }
                }
@@ -14555,12 +14936,12 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
                        return 0;
                }
        }
-       peer = find_peer(name, NULL, TRUE, FINDPEERS, FALSE, 0);
+       peer = sip_find_peer(name, NULL, TRUE, FINDPEERS, FALSE, 0);
 
        if (!(peer && ast_apply_ha(peer->ha, addr))) {
                /* Peer fails ACL check */
                if (peer) {
-                       unref_peer(peer, "register_verify: unref_peer: from find_peer operation");
+                       sip_unref_peer(peer, "register_verify: sip_unref_peer: from sip_find_peer operation");
                        peer = NULL;
                        res = AUTH_ACL_FAILED;
                } else {
@@ -14575,8 +14956,6 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
                        res = AUTH_PEER_NOT_DYNAMIC;
                } else {
                        ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_NAT_FORCE_RPORT);
-                       if (ast_test_flag(&p->flags[1], SIP_PAGE2_REGISTERTRYING))
-                               transmit_response(p, "100 Trying", req);
                        if (!(res = check_auth(p, req, peer->name, peer->secret, peer->md5secret, SIP_REGISTER, uri2, XMIT_UNRELIABLE, req->ignore))) {
                                if (sip_cancel_destroy(p))
                                        ast_log(LOG_WARNING, "Unable to cancel SIP destruction.  Expect bad things.\n");
@@ -14619,7 +14998,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
                }
                ao2_unlock(peer);
        }
-       if (!peer && sip_cfg.autocreatepeer) {
+       if (!peer && sip_cfg.autocreatepeer != AUTOPEERS_DISABLED) {
                /* Create peer if we have autocreate mode enabled */
                peer = temp_peer(name);
                if (peer) {
@@ -14657,16 +15036,10 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
                        ao2_unlock(peer);
                }
        }
-       if (!peer && sip_cfg.alwaysauthreject) {
-               /* If we found a peer, we transmit a 100 Trying.  Therefore, if we're
-                * trying to avoid leaking information, we MUST also transmit the same
-                * response when we DON'T find a peer. */
-               transmit_response(p, "100 Trying", req);
-               /* Insert a fake delay between the 100 and the subsequent failure. */
-               sched_yield();
-       }
        if (!res) {
-               sip_send_mwi_to_peer(peer, NULL, 0);
+               ao2_unlock(p);
+               sip_send_mwi_to_peer(peer, 0);
+               ao2_lock(p);
                ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
        }
        if (res < 0) {
@@ -14752,7 +15125,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
                }
        }
        if (peer) {
-               unref_peer(peer, "register_verify: unref_peer: tossing stack peer pointer at end of func");
+               sip_unref_peer(peer, "register_verify: sip_unref_peer: tossing stack peer pointer at end of func");
        }
 
        return res;
@@ -14801,7 +15174,7 @@ static int get_pai(struct sip_pvt *p, struct sip_request *req)
        int callingpres = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
        char *start = NULL, *end = NULL, *uri = NULL;
 
-       ast_copy_string(pai, get_header(req, "P-Asserted-Identity"), sizeof(pai));
+       ast_copy_string(pai, sip_get_header(req, "P-Asserted-Identity"), sizeof(pai));
 
        if (ast_strlen_zero(pai)) {
                return 0;
@@ -14853,7 +15226,7 @@ static int get_pai(struct sip_pvt *p, struct sip_request *req)
                return 0;
        }
 
-       ast_copy_string(privacy, get_header(req, "Privacy"), sizeof(privacy));
+       ast_copy_string(privacy, sip_get_header(req, "Privacy"), sizeof(privacy));
        if (!ast_strlen_zero(privacy) && strncmp(privacy, "id", 2)) {
                callingpres = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
        }
@@ -14896,7 +15269,7 @@ static int get_rpid(struct sip_pvt *p, struct sip_request *oreq)
        req = oreq;
        if (!req)
                req = &p->initreq;
-       ast_copy_string(tmp, get_header(req, "Remote-Party-ID"), sizeof(tmp));
+       ast_copy_string(tmp, sip_get_header(req, "Remote-Party-ID"), sizeof(tmp));
        if (ast_strlen_zero(tmp)) {
                return get_pai(p, req);
        }
@@ -14985,7 +15358,7 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, c
 
        req = oreq ? oreq : &p->initreq;
 
-       ast_copy_string(tmp, get_header(req, "Diversion"), sizeof(tmp));
+       ast_copy_string(tmp, sip_get_header(req, "Diversion"), sizeof(tmp));
        if (ast_strlen_zero(tmp))
                return -1;
 
@@ -15077,7 +15450,7 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, c
  */
 static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id)
 {
-       char tmp[256] = "", *uri, *domain, *dummy = NULL;
+       char tmp[256] = "", *uri, *unused_password, *domain;
        char tmpf[256] = "", *from = NULL;
        struct sip_request *req;
        char *decoded_uri;
@@ -15093,13 +15466,16 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re
        
        uri = ast_strdupa(get_in_brackets(tmp));
 
-       if (parse_uri_legacy_check(uri, "sip:,sips:", &uri, &dummy, &domain, NULL)) {
+       if (parse_uri_legacy_check(uri, "sip:,sips:", &uri, &unused_password, &domain, NULL)) {
                ast_log(LOG_WARNING, "Not a SIP header (%s)?\n", uri);
                return SIP_GET_DEST_INVALID_URI;
        }
 
        SIP_PEDANTIC_DECODE(domain);
        SIP_PEDANTIC_DECODE(uri);
+
+       extract_host_from_hostport(&domain);
+
        if (ast_strlen_zero(uri)) {
                /*
                 * Either there really was no extension found or the request
@@ -15115,7 +15491,7 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re
        /* XXX Why is this done in get_destination? Isn't it already done?
           Needs to be checked
         */
-       ast_copy_string(tmpf, get_header(req, "From"), sizeof(tmpf));
+       ast_copy_string(tmpf, sip_get_header(req, "From"), sizeof(tmpf));
        if (!ast_strlen_zero(tmpf)) {
                from = get_in_brackets(tmpf);
                if (parse_uri_legacy_check(from, "sip:,sips:", &from, NULL, &domain, NULL)) {
@@ -15126,6 +15502,8 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re
                SIP_PEDANTIC_DECODE(from);
                SIP_PEDANTIC_DECODE(domain);
 
+               extract_host_from_hostport(&domain);
+
                ast_string_field_set(p, fromdomain, domain);
        }
 
@@ -15175,18 +15553,23 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re
                }
        } else {
                struct ast_cc_agent *agent;
-               int which = 0;
                /* Check the dialplan for the username part of the request URI,
                   the domain will be stored in the SIPDOMAIN variable
                   Return 0 if we have a matching extension */
-               if (ast_exists_extension(NULL, p->context, uri, 1, S_OR(p->cid_num, from)) ||
-                   (ast_exists_extension(NULL, p->context, decoded_uri, 1, S_OR(p->cid_num, from)) && (which = 1)) ||
-                   !strcmp(decoded_uri, ast_pickup_ext())) {
+               if (ast_exists_extension(NULL, p->context, uri, 1, S_OR(p->cid_num, from))) {
                        if (!oreq) {
-                               ast_string_field_set(p, exten, which ? decoded_uri : uri);
+                               ast_string_field_set(p, exten, uri);
+                       }
+                       return SIP_GET_DEST_EXTEN_FOUND;
+               }
+               if (ast_exists_extension(NULL, p->context, decoded_uri, 1, S_OR(p->cid_num, from))
+                       || !strcmp(decoded_uri, ast_pickup_ext())) {
+                       if (!oreq) {
+                               ast_string_field_set(p, exten, decoded_uri);
                        }
                        return SIP_GET_DEST_EXTEN_FOUND;
-               } else if ((agent = find_sip_cc_agent_by_notify_uri(tmp))) {
+               }
+               if ((agent = find_sip_cc_agent_by_notify_uri(tmp))) {
                        struct sip_cc_agent_pvt *agent_pvt = agent->private_data;
                        /* This is a CC recall. We can set p's extension to the exten from
                         * the original INVITE
@@ -15205,11 +15588,12 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re
                }
        }
 
-       /* Return 1 for pickup extension or overlap dialling support (if we support it) */
-       if((ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP) &&
-           ast_canmatch_extension(NULL, p->context, decoded_uri, 1, S_OR(p->cid_num, from))) ||
-           !strncmp(decoded_uri, ast_pickup_ext(), strlen(decoded_uri))) {
-               return SIP_GET_DEST_PICKUP_EXTEN_FOUND;
+       if (ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP)
+               && (ast_canmatch_extension(NULL, p->context, uri, 1, S_OR(p->cid_num, from))
+                       || ast_canmatch_extension(NULL, p->context, decoded_uri, 1, S_OR(p->cid_num, from))
+                       || !strncmp(decoded_uri, ast_pickup_ext(), strlen(decoded_uri)))) {
+               /* Overlap dialing is enabled and we need more digits to match an extension. */
+               return SIP_GET_DEST_EXTEN_MATCHMORE;
        }
 
        return SIP_GET_DEST_EXTEN_NOT_FOUND;
@@ -15329,7 +15713,7 @@ static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoi
                req = &transferer->initreq;
        }
 
-       p_refer_to = get_header(req, "Refer-To");
+       p_refer_to = sip_get_header(req, "Refer-To");
        if (ast_strlen_zero(p_refer_to)) {
                ast_log(LOG_WARNING, "Refer-To Header missing. Skipping transfer.\n");
                return -2;      /* Syntax error */
@@ -15346,7 +15730,7 @@ static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoi
        }
 
        /* Get referred by header if it exists */
-       p_referred_by = get_header(req, "Referred-By");
+       p_referred_by = sip_get_header(req, "Referred-By");
 
        /* Give useful transfer information to the dialplan */
        if (transferer->owner) {
@@ -15526,7 +15910,7 @@ static int get_also_info(struct sip_pvt *p, struct sip_request *oreq)
 
        referdata = p->refer;
 
-       ast_copy_string(tmp, get_header(req, "Also"), sizeof(tmp));
+       ast_copy_string(tmp, sip_get_header(req, "Also"), sizeof(tmp));
        c = get_in_brackets(tmp);
 
        if (parse_uri_legacy_check(c, "sip:,sips:", &c, NULL, &a, NULL)) {
@@ -15584,7 +15968,7 @@ static attribute_unused void check_via_response(struct sip_pvt *p, struct sip_re
        char via[256];
        char *cur, *opts;
 
-       ast_copy_string(via, get_header(req, "Via"), sizeof(via));
+       ast_copy_string(via, sip_get_header(req, "Via"), sizeof(via));
 
        /* Work on the leftmost value of the topmost Via header */
        opts = strchr(via, ',');
@@ -15613,10 +15997,10 @@ static void check_via(struct sip_pvt *p, struct sip_request *req)
 {
        char via[512];
        char *c, *maddr;
-       struct ast_sockaddr tmp;
+       struct ast_sockaddr tmp = { { 0, } };
        uint16_t port;
 
-       ast_copy_string(via, get_header(req, "Via"), sizeof(via));
+       ast_copy_string(via, sip_get_header(req, "Via"), sizeof(via));
 
        /* Work on the leftmost value of the topmost Via header */
        c = strchr(via, ',');
@@ -15683,14 +16067,14 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
                /* For subscribes, match on device name only; for other methods,
                * match on IP address-port of the incoming request.
                */
-               peer = find_peer(of, NULL, TRUE, FINDALLDEVICES, FALSE, 0);
+               peer = sip_find_peer(of, NULL, TRUE, FINDALLDEVICES, FALSE, 0);
        } else {
                /* First find devices based on username (avoid all type=peer's) */
-               peer = find_peer(of, NULL, TRUE, FINDUSERS, FALSE, 0);
+               peer = sip_find_peer(of, NULL, TRUE, FINDUSERS, FALSE, 0);
 
                /* Then find devices based on IP */
                if (!peer) {
-                       peer = find_peer(NULL, &p->recv, TRUE, FINDPEERS, FALSE, p->socket.type);
+                       peer = sip_find_peer(NULL, &p->recv, TRUE, FINDPEERS, FALSE, p->socket.type);
                }
        }
 
@@ -15704,7 +16088,7 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
 
        if (!ast_apply_ha(peer->ha, addr)) {
                ast_debug(2, "Found peer '%s' for '%s', but fails host access\n", peer->name, of);
-               unref_peer(peer, "unref_peer: check_peer_ok: from find_peer call, early return of AUTH_ACL_FAILED");
+               sip_unref_peer(peer, "sip_unref_peer: check_peer_ok: from sip_find_peer call, early return of AUTH_ACL_FAILED");
                return AUTH_ACL_FAILED;
        }
        if (debug)
@@ -15823,6 +16207,7 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
                ast_format_cap_copy(p->caps, peer->caps);
                ast_format_cap_copy(p->jointcaps, peer->caps);
                p->prefs = peer->prefs;
+               ast_copy_string(p->zone, peer->zone, sizeof(p->zone));
                if (peer->maxforwards > 0) {
                        p->maxforwards = peer->maxforwards;
                }
@@ -15842,6 +16227,9 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
                else
                        p->noncodeccapability &= ~AST_RTP_DTMF;
                p->jointnoncodeccapability = p->noncodeccapability;
+               p->rtptimeout = peer->rtptimeout;
+               p->rtpholdtimeout = peer->rtpholdtimeout;
+               p->rtpkeepalive = peer->rtpkeepalive;
                if (!dialog_initialize_rtp(p)) {
                        if (p->rtp) {
                                ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &peer->prefs);
@@ -15851,7 +16239,7 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
                        res = AUTH_RTP_FAILED;
                }
        }
-       unref_peer(peer, "check_peer_ok: unref_peer: tossing temp ptr to peer from find_peer");
+       sip_unref_peer(peer, "check_peer_ok: sip_unref_peer: tossing temp ptr to peer from sip_find_peer");
        return res;
 }
 
@@ -15865,17 +16253,14 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
                                              int sipmethod, const char *uri, enum xmittype reliable,
                                              struct ast_sockaddr *addr, struct sip_peer **authpeer)
 {
-       char from[256] = { 0, };
-       char *dummy = NULL;     /* dummy return value for parse_uri */
-       char *domain = NULL;    /* dummy return value for parse_uri */
-       char *of;
+       char from[256] = "", *of, *name, *unused_password, *domain;
        enum check_auth_result res = AUTH_DONT_KNOW;
        char calleridname[50];
        char *uri2 = ast_strdupa(uri);
 
        terminate_uri(uri2);    /* trim extra stuff */
 
-       ast_copy_string(from, get_header(req, "From"), sizeof(from));
+       ast_copy_string(from, sip_get_header(req, "From"), sizeof(from));
        /* XXX here tries to map the username for invite things */
        memset(calleridname, 0, sizeof(calleridname));
 
@@ -15885,8 +16270,9 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
                return res;
        }
 
-       if (calleridname[0])
+       if (calleridname[0]) {
                ast_string_field_set(p, cid_name, calleridname);
+       }
 
        if (ast_strlen_zero(p->exten)) {
                char *t = uri2;
@@ -15908,30 +16294,36 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
        /* save the URI part of the From header */
        ast_string_field_set(p, from, of);
 
-       /* ignore all fields but name */
-       if (parse_uri_legacy_check(of, "sip:,sips:", &of, &dummy, &domain, NULL)) {
+       if (parse_uri_legacy_check(of, "sip:,sips:", &name, &unused_password, &domain, NULL)) {
                ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
        }
 
-       SIP_PEDANTIC_DECODE(of);
+       SIP_PEDANTIC_DECODE(name);
        SIP_PEDANTIC_DECODE(domain);
 
-       if (ast_strlen_zero(of)) {
-               /* XXX note: the original code considered a missing @host
-                * as a username-only URI. The SIP RFC (19.1.1) says that
-                * this is wrong, and it should be considered as a domain-only URI.
-                * For backward compatibility, we keep this block, but it is
-                * really a mistake and should go away.
-                */
-               of = domain;
+       extract_host_from_hostport(&domain);
+
+       if (ast_strlen_zero(domain)) {
+               /* <sip:name@[EMPTY]>, never good */
+               ast_log(LOG_ERROR, "Empty domain name in FROM header\n");
+               return res;
+       }
+
+       if (ast_strlen_zero(name)) {
+               /* <sip:[EMPTY][@]hostport>. Asterisk 1.4 and 1.6 have always
+                * treated that as a username, so we continue the tradition:
+                * uri is now <sip:host@hostport>. */
+               name = domain;
        } else {
-               char *tmp = ast_strdupa(of);
-               /* We need to be able to handle auth-headers looking like
+               /* Non-empty name, try to get caller id from it */
+               char *tmp = ast_strdupa(name);
+               /* We need to be able to handle from-headers looking like
                        <sip:8164444422;phone-context=+1@1.2.3.4:5060;user=phone;tag=SDadkoa01-gK0c3bdb43>
                */
                tmp = strsep(&tmp, ";");
-               if (global_shrinkcallerid && ast_is_shrinkable_phonenumber(tmp))
+               if (global_shrinkcallerid && ast_is_shrinkable_phonenumber(tmp)) {
                        ast_shrink_phone_number(tmp);
+               }
                ast_string_field_set(p, cid_num, tmp);
        }
 
@@ -15944,35 +16336,40 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
                 * Note2, at the moment we check both fields, though maybe we should
                 * pick one or another depending on the request ? XXX
                 */
-               const char *hdr = get_header(req, "Authorization");
-               if (ast_strlen_zero(hdr))
-                       hdr = get_header(req, "Proxy-Authorization");
+               const char *hdr = sip_get_header(req, "Authorization");
+               if (ast_strlen_zero(hdr)) {
+                       hdr = sip_get_header(req, "Proxy-Authorization");
+               }
 
-               if ( !ast_strlen_zero(hdr) && (hdr = strstr(hdr, "username=\"")) ) {
+               if (!ast_strlen_zero(hdr) && (hdr = strstr(hdr, "username=\""))) {
                        ast_copy_string(from, hdr + strlen("username=\""), sizeof(from));
-                       of = from;
-                       of = strsep(&of, "\"");
+                       name = from;
+                       name = strsep(&name, "\"");
                }
        }
 
-       res = check_peer_ok(p, of, req, sipmethod, addr,
+       res = check_peer_ok(p, name, req, sipmethod, addr,
                        authpeer, reliable, calleridname, uri2);
-       if (res != AUTH_DONT_KNOW)
+       if (res != AUTH_DONT_KNOW) {
                return res;
+       }
 
        /* Finally, apply the guest policy */
        if (sip_cfg.allowguest) {
                get_rpid(p, req);
+               p->rtptimeout = global_rtptimeout;
+               p->rtpholdtimeout = global_rtpholdtimeout;
+               p->rtpkeepalive = global_rtpkeepalive;
                if (!dialog_initialize_rtp(p)) {
                        res = AUTH_SUCCESSFUL;
                } else {
                        res = AUTH_RTP_FAILED;
                }
-       } else if (sip_cfg.alwaysauthreject)
+       } else if (sip_cfg.alwaysauthreject) {
                res = AUTH_FAKE_AUTH; /* reject with fake authorization request */
-       else
+       } else {
                res = AUTH_SECRET_FAILED; /* we don't want any guests, authentication will fail */
-
+       }
 
        if (ast_test_flag(&p->flags[1], SIP_PAGE2_RPORT_PRESENT)) {
                ast_set_flag(&p->flags[0], SIP_NAT_RPORT_PRESENT);
@@ -15989,30 +16386,37 @@ static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod,
        return check_user_full(p, req, sipmethod, uri, reliable, addr, NULL);
 }
 
-/*! \brief  Get text out of a SIP MESSAGE packet */
-static int get_msg_text(char *buf, int len, struct sip_request *req, int addnewline)
+/*! \brief Get message body from a SIP request
+ * \param buf Destination buffer
+ * \param len Destination buffer size
+ * \param req The SIP request
+ *
+ * When parsing the request originally, the lines are split by LF or CRLF.
+ * This function adds a single LF after every line.
+ */
+static int get_msg_text(char *buf, int len, struct sip_request *req)
 {
        int x;
-       int y;
+       int linelen;
 
        buf[0] = '\0';
-       /*XXX isn't strlen(buf) going to always be 0? */
-       y = len - strlen(buf) - 5;
-       if (y < 0)
-               y = 0;
-       for (x = 0; x < req->lines; x++) {
+       --len; /* reserve strncat null */
+       for (x = 0; len && x < req->lines; ++x) {
                const char *line = REQ_OFFSET_TO_STR(req, line[x]);
-               strncat(buf, line, y); /* safe */
-               y -= strlen(line) + 1;
-               if (y < 0)
-                       y = 0;
-               if (y != 0 && addnewline)
+               strncat(buf, line, len); /* safe */
+               linelen = strlen(buf);
+               buf += linelen;
+               len -= linelen;
+               if (len) {
                        strcat(buf, "\n"); /* safe */
+                       ++buf;
+                       --len;
+               }
        }
        return 0;
 }
 
-static int get_msg_text2(struct ast_str **buf, struct sip_request *req, int addnewline)
+static int get_msg_text2(struct ast_str **buf, struct sip_request *req)
 {
        int i, res = 0;
 
@@ -16021,7 +16425,7 @@ static int get_msg_text2(struct ast_str **buf, struct sip_request *req, int addn
        for (i = 0; res >= 0 && i < req->lines; i++) {
                const char *line = REQ_OFFSET_TO_STR(req, line[i]);
 
-               res = ast_str_append(buf, 0, "%s%s", line, addnewline ? "\n" : "");
+               res = ast_str_append(buf, 0, "%s\n", line);
        }
 
        return res < 0 ? -1 : 0;
@@ -16053,8 +16457,10 @@ AST_THREADSTORAGE(sip_msg_buf);
 static void receive_message(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e)
 {
        struct ast_str *buf;
+       char *cbuf;
+       size_t len;
        struct ast_frame f;
-       const char *content_type = get_header(req, "Content-Type");
+       const char *content_type = sip_get_header(req, "Content-Type");
        struct ast_msg *msg;
        int res;
        char *from, *to;
@@ -16074,11 +16480,7 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
                return;
        }
 
-       /* If this is an out of dialog msg, add back newlines, otherwise strip the new lines.
-        * In dialog msg's newlines are stripped to preserve the behavior of how Asterisk has worked
-        * in the past.  If it is found later that new lines can be added into in dialog msgs as well,
-        * then change this. */
-       if (get_msg_text2(&buf, req, p->owner ? FALSE : TRUE)) {
+       if (get_msg_text2(&buf, req)) {
                ast_log(LOG_WARNING, "Unable to retrieve text from %s\n", p->callid);
                transmit_response(p, "202 Accepted", req);
                if (!p->owner)
@@ -16086,6 +16488,18 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
                return;
        }
 
+       /* Strip trailing line feeds from message body. (get_msg_text2 may add
+        * a trailing linefeed and we don't need any at the end) */
+       cbuf = ast_str_buffer(buf);
+       len = ast_str_strlen(buf);
+       while (len > 0) {
+               if (cbuf[--len] != '\n') {
+                       ++len;
+                       break;
+               }
+       }
+       ast_str_truncate(buf, len);
+
        if (p->owner) {
                if (sip_debug_test_pvt(p))
                        ast_verbose("SIP Text message received: '%s'\n", ast_str_buffer(buf));
@@ -16121,10 +16535,10 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
                }
                if (res < 0) { /* Something failed in authentication */
                        if (res == AUTH_FAKE_AUTH) {
-                               ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", get_header(req, "From"));
+                               ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", sip_get_header(req, "From"));
                                transmit_fake_auth_response(p, SIP_OPTIONS, req, XMIT_UNRELIABLE);
                        } else {
-                               ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
+                               ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From"));
                                transmit_response(p, "403 Forbidden", req);
                        }
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
@@ -16140,7 +16554,7 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
                 * it to the right context.
                 */
 
-               peer = find_peer(NULL, &p->recv, TRUE, FINDPEERS, 0, p->socket.type);
+               peer = sip_find_peer(NULL, &p->recv, TRUE, FINDPEERS, 0, p->socket.type);
                if (peer) {
                        /* Only if no auth is required. */
                        if (ast_strlen_zero(peer->secret) && ast_strlen_zero(peer->md5secret)) {
@@ -16150,7 +16564,7 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
                                ast_string_field_set(p, messagecontext, peer->messagecontext);
                        }
                        ast_string_field_set(p, peername, peer->name);
-                       peer = unref_peer(peer, "from find_peer() in receive_message");
+                       peer = sip_unref_peer(peer, "from sip_find_peer() in receive_message");
                }
        }
 
@@ -16174,7 +16588,7 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
        }
 
        to = ast_strdupa(REQ_OFFSET_TO_STR(req, rlPart2));
-       from = ast_strdupa(get_header(req, "From"));
+       from = ast_strdupa(sip_get_header(req, "From"));
 
        res = ast_msg_set_to(msg, "%s", to);
        res |= ast_msg_set_from(msg, "%s", get_in_brackets(from));
@@ -16240,7 +16654,7 @@ static char *sip_show_inuse(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
                if (showall || peer->call_limit)
                        ast_cli(a->fd, FORMAT2, peer->name, iused, ilimits);
                ao2_unlock(peer);
-               unref_peer(peer, "toss iterator pointer");
+               sip_unref_peer(peer, "toss iterator pointer");
        }
        ao2_iterator_destroy(&i);
 
@@ -16301,6 +16715,18 @@ static enum st_refresher str2strefresher(const char *s)
        return map_s_x(strefreshers, s, -1);
 }
 
+/* Autocreatepeer modes */
+static struct _map_x_s autopeermodes[] = {
+        { AUTOPEERS_DISABLED, "Off"},
+        { AUTOPEERS_VOLATILE, "Volatile"},
+        { AUTOPEERS_PERSIST,  "Persisted"},
+        { -1, NULL},
+};
+
+static const char *autocreatepeer2str(enum autocreatepeer_mode r)
+{
+       return map_x_s(autopeermodes, r, "Unknown");
+}
 
 static int peer_status(struct sip_peer *peer, char *status, int statuslen)
 {
@@ -16354,7 +16780,7 @@ static char *sip_show_tcp(struct ast_cli_entry *e, int cmd, struct ast_cli_args
        while ((th = ao2_t_iterator_next(&i, "iterate through tcp threads for 'sip show tcp'"))) {
                ast_cli(a->fd, FORMAT,
                        ast_sockaddr_stringify(&th->tcptls_session->remote_address),
-                       get_transport(th->type),
+                       sip_get_transport(th->type),
                        (th->tcptls_session->client ? "Client" : "Server"));
                ao2_t_ref(th, -1, "decrement ref from iterator");
        }
@@ -16408,13 +16834,13 @@ static char *sip_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
                ao2_lock(user);
                if (!(user->type & SIP_TYPE_USER)) {
                        ao2_unlock(user);
-                       unref_peer(user, "sip show users");
+                       sip_unref_peer(user, "sip show users");
                        continue;
                }
 
                if (havepattern && regexec(&regexbuf, user->name, 0, NULL, 0)) {
                        ao2_unlock(user);
-                       unref_peer(user, "sip show users");
+                       sip_unref_peer(user, "sip show users");
                        continue;
                }
 
@@ -16425,7 +16851,7 @@ static char *sip_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
                        AST_CLI_YESNO(user->ha != NULL),
                        AST_CLI_YESNO(ast_test_flag(&user->flags[0], SIP_NAT_FORCE_RPORT)));
                ao2_unlock(user);
-               unref_peer(user, "sip show users");
+               sip_unref_peer(user, "sip show users");
        }
        ao2_iterator_destroy(&user_iter);
 
@@ -16597,14 +17023,14 @@ static char *_sip_show_peers(int fd, int *total, struct mansession *s, const str
 
                if (!(peer->type & SIP_TYPE_PEER)) {
                        ao2_unlock(peer);
-                       unref_peer(peer, "unref peer because it's actually a user");
+                       sip_unref_peer(peer, "unref peer because it's actually a user");
                        continue;
                }
 
                if (havepattern && regexec(&regexbuf, peer->name, 0, NULL, 0)) {
                        objcount--;
                        ao2_unlock(peer);
-                       unref_peer(peer, "toss iterator peer ptr before continue");
+                       sip_unref_peer(peer, "toss iterator peer ptr before continue");
                        continue;
                }
 
@@ -16624,7 +17050,7 @@ static char *_sip_show_peers(int fd, int *total, struct mansession *s, const str
                ao2_lock(peer);
                if (havepattern && regexec(&regexbuf, peer->name, 0, NULL, 0)) {
                        ao2_unlock(peer);
-                       peer = peerarray[k] = unref_peer(peer, "toss iterator peer ptr before continue");
+                       peer = peerarray[k] = sip_unref_peer(peer, "toss iterator peer ptr before continue");
                        continue;
                }
 
@@ -16696,7 +17122,7 @@ static char *_sip_show_peers(int fd, int *total, struct mansession *s, const str
                        peer->description);
                }
                ao2_unlock(peer);
-               peer = peerarray[k] = unref_peer(peer, "toss iterator peer ptr");
+               peer = peerarray[k] = sip_unref_peer(peer, "toss iterator peer ptr");
        }
        
        if (!s)
@@ -16810,6 +17236,19 @@ static const char *insecure2str(int mode)
        return map_x_s(insecurestr, mode, "<error>");
 }
 
+static const struct _map_x_s allowoverlapstr[] = {
+       { SIP_PAGE2_ALLOWOVERLAP_YES,   "Yes" },
+       { SIP_PAGE2_ALLOWOVERLAP_DTMF,  "DTMF" },
+       { SIP_PAGE2_ALLOWOVERLAP_NO,    "No" },
+       { -1,                           NULL }, /* terminator */
+};
+
+/*! \brief Convert AllowOverlap setting to printable string */
+static const char *allowoverlap2str(int mode)
+{
+       return map_x_s(allowoverlapstr, mode, "<error>");
+}
+
 /*! \brief Destroy disused contexts between reloads
        Only used in reload_config so the code for regcontext doesn't get ugly
 */
@@ -16836,42 +17275,45 @@ static void cleanup_stale_contexts(char *new, char *old)
        }
 }
 
-/*! \brief Check RTP Timeout on dialogs
+/*!
+ * \brief Check RTP Timeout on dialogs
+ *
  * \details This is used with ao2_callback to check rtptimeout
- * rtponholdtimeout and send rtpkeepalive packets
+ * rtponholdtimeout and send rtpkeepalive packets.
+ *
+ * \return CMP_MATCH for items to be unlinked from dialogs_rtpcheck.
  */
 static int dialog_checkrtp_cb(void *dialogobj, void *arg, int flags)
 {
        struct sip_pvt *dialog = dialogobj;
        time_t *t = arg;
+       int match_status;
 
        if (sip_pvt_trylock(dialog)) {
                return 0;
        }
 
        if (dialog->rtp || dialog->vrtp) {
-               check_rtp_timeout(dialog, *t);
+               match_status = check_rtp_timeout(dialog, *t);
        } else {
-               /* Dialog has no active RTP or VRTP. unlink it from the checkrtp container */
-               dialog_unlink_rtpcheck(dialog);
+               /* Dialog has no active RTP or VRTP. unlink it from dialogs_rtpcheck. */
+               match_status = CMP_MATCH;
        }
        sip_pvt_unlock(dialog);
 
-       return 0;
+       return match_status;
 }
 
 /*!
  * \brief Match dialogs that need to be destroyed
  *
  * \details This is used with ao2_callback to unlink/delete all dialogs that
- * are marked needdestroy. It will return CMP_MATCH for candidates, and they
- * will be unlinked.
+ * are marked needdestroy.
  *
  * \todo Re-work this to improve efficiency.  Currently, this function is called
  * on _every_ dialog after processing _every_ incoming SIP/UDP packet, or
  * potentially even more often when the scheduler has entries to run.
  */
-
 static int dialog_needdestroy(void *dialogobj, void *arg, int flags)
 {
        struct sip_pvt *dialog = dialogobj;
@@ -16882,7 +17324,6 @@ static int dialog_needdestroy(void *dialogobj, void *arg, int flags)
                return 0;
        }
 
-
        /* If we have sessions that needs to be destroyed, do it now */
        /* Check if we have outstanding requests not responsed to or an active call
           - if that's the case, wait with destruction */
@@ -16903,7 +17344,7 @@ static int dialog_needdestroy(void *dialogobj, void *arg, int flags)
                sip_pvt_unlock(dialog);
                /* no, the unlink should handle this: dialog_unref(dialog, "needdestroy: one more refcount decrement to allow dialog to be destroyed"); */
                /* the CMP_MATCH will unlink this dialog from the dialog hash table */
-               dialog_unlink_all(dialog, TRUE, FALSE);
+               dialog_unlink_all(dialog);
                return 0; /* the unlink_all should unlink this from the table, so.... no need to return a match */
        }
 
@@ -17004,7 +17445,7 @@ static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli
                        while ((pi = ao2_t_iterator_next(&i, "iterate thru peers table"))) {
                                ao2_lock(pi);
                                if (name && regexec(&regexbuf, pi->name, 0, NULL, 0)) {
-                                       unref_peer(pi, "toss iterator peer ptr before continue");
+                                       sip_unref_peer(pi, "toss iterator peer ptr before continue");
                                        ao2_unlock(pi);
                                        continue;
                                };
@@ -17013,7 +17454,7 @@ static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli
                                        pruned++;
                                }
                                ao2_unlock(pi);
-                               unref_peer(pi, "toss iterator peer ptr");
+                               sip_unref_peer(pi, "toss iterator peer ptr");
                        }
                        ao2_iterator_destroy(&i);
                        if (pruned) {
@@ -17039,7 +17480,7 @@ static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli
                                        }
                                } else
                                        ast_cli(a->fd, "Peer '%s' pruned.\n", name);
-                               unref_peer(peer, "sip_prune_realtime: unref_peer: tossing temp peer ptr");
+                               sip_unref_peer(peer, "sip_prune_realtime: sip_unref_peer: tossing temp peer ptr");
                        } else
                                ast_cli(a->fd, "Peer '%s' not found.\n", name);
                }
@@ -17135,7 +17576,7 @@ static int manager_sip_show_peer(struct mansession *s, const struct message *m)
        a[3] = peer;
 
        _sip_show_peer(1, -1, s, m, 4, a);
-       astman_append(s, "\r\n\r\n" );
+       astman_append(s, "\r\n" );
        return 0;
 }
 
@@ -17166,9 +17607,9 @@ static char *_sip_qualify_peer(int type, int fd, struct mansession *s, const str
                return CLI_SHOWUSAGE;
 
        load_realtime = (argc == 5 && !strcmp(argv[4], "load")) ? TRUE : FALSE;
-       if ((peer = find_peer(argv[3], NULL, load_realtime, FINDPEERS, FALSE, 0))) {
+       if ((peer = sip_find_peer(argv[3], NULL, load_realtime, FINDPEERS, FALSE, 0))) {
                sip_poke_peer(peer, 1);
-               unref_peer(peer, "qualify: done with peer");
+               sip_unref_peer(peer, "qualify: done with peer");
        } else if (type == 0) {
                ast_cli(fd, "Peer '%s' not found\n", argv[3]);
        } else {
@@ -17260,7 +17701,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
                return CLI_SHOWUSAGE;
 
        load_realtime = (argc == 5 && !strcmp(argv[4], "load")) ? TRUE : FALSE;
-       peer = find_peer(argv[3], NULL, load_realtime, FINDPEERS, FALSE, 0);
+       peer = sip_find_peer(argv[3], NULL, load_realtime, FINDPEERS, FALSE, 0);
 
        if (s) {        /* Manager */
                if (peer) {
@@ -17310,8 +17751,11 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
                        ao2_t_ref(credentials, -1, "Unref peer auth for show");
                }
                ast_cli(fd, "  Context      : %s\n", peer->context);
+               ast_cli(fd, "  Record On feature : %s\n", peer->record_on_feature);
+               ast_cli(fd, "  Record Off feature : %s\n", peer->record_off_feature);
                ast_cli(fd, "  Subscr.Cont. : %s\n", S_OR(peer->subscribecontext, "<Not set>") );
                ast_cli(fd, "  Language     : %s\n", peer->language);
+               ast_cli(fd, "  Tonezone     : %s\n", peer->zone[0] != '\0' ? peer->zone : "<Not set>");
                if (!ast_strlen_zero(peer->accountcode))
                        ast_cli(fd, "  Accountcode  : %s\n", peer->accountcode);
                ast_cli(fd, "  AMA flags    : %s\n", ast_cdr_flags2str(peer->amaflags));
@@ -17353,7 +17797,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
                ast_cli(fd, "  Trust RPID   : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_TRUSTRPID)));
                ast_cli(fd, "  Send RPID    : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_SENDRPID)));
                ast_cli(fd, "  Subscriptions: %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE)));
-               ast_cli(fd, "  Overlap dial : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWOVERLAP)));
+               ast_cli(fd, "  Overlap dial : %s\n", allowoverlap2str(ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWOVERLAP)));
                if (peer->outboundproxy)
                        ast_cli(fd, "  Outb. proxy  : %s %s\n", ast_strlen_zero(peer->outboundproxy->name) ? "<not set>" : peer->outboundproxy->name,
                                                        peer->outboundproxy->force ? "(forced)" : "");
@@ -17365,7 +17809,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
                ast_cli(fd, "  ToHost       : %s\n", peer->tohost);
                ast_cli(fd, "  Addr->IP     : %s\n", ast_sockaddr_stringify(&peer->addr));
                ast_cli(fd, "  Defaddr->IP  : %s\n", ast_sockaddr_stringify(&peer->defaddr));
-               ast_cli(fd, "  Prim.Transp. : %s\n", get_transport(peer->socket.type));
+               ast_cli(fd, "  Prim.Transp. : %s\n", sip_get_transport(peer->socket.type));
                ast_cli(fd, "  Allowed.Trsp : %s\n", get_transport_list(peer->transports));
                if (!ast_strlen_zero(sip_cfg.regcontext))
                        ast_cli(fd, "  Reg. exten   : %s\n", peer->regexten);
@@ -17392,7 +17836,6 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
                ast_cli(fd, ")\n");
 
                ast_cli(fd, "  Auto-Framing :  %s \n", AST_CLI_YESNO(peer->autoframing));
-               ast_cli(fd, "  100 on REG   : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_REGISTERTRYING)));
                ast_cli(fd, "  Status       : ");
                peer_status(peer, status, sizeof(status));
                ast_cli(fd, "%s\n", status);
@@ -17414,7 +17857,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
                ast_cli(fd, "  Use Reason   : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_Q850_REASON)));
                ast_cli(fd, "  Encryption   : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_USE_SRTP)));
                ast_cli(fd, "\n");
-               peer = unref_peer(peer, "sip_show_peer: unref_peer: done with peer ptr");
+               peer = sip_unref_peer(peer, "sip_show_peer: sip_unref_peer: done with peer ptr");
        } else  if (peer && type == 1) { /* manager listing */
                char buffer[256];
                struct ast_str *mailbox_str = ast_str_alloca(512);
@@ -17426,6 +17869,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
                astman_append(s, "MD5SecretExist: %s\r\n", ast_strlen_zero(peer->md5secret)?"N":"Y");
                astman_append(s, "Context: %s\r\n", peer->context);
                astman_append(s, "Language: %s\r\n", peer->language);
+               astman_append(s, "ToneZone: %s\r\n", peer->zone[0] != '\0' ? peer->zone : "<Not set>");
                if (!ast_strlen_zero(peer->accountcode))
                        astman_append(s, "Accountcode: %s\r\n", peer->accountcode);
                astman_append(s, "AMAflags: %s\r\n", ast_cdr_flags2str(peer->amaflags));
@@ -17443,7 +17887,6 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
                astman_append(s, "VoiceMailbox: %s\r\n", mailbox_str->str);
                astman_append(s, "TransferMode: %s\r\n", transfermode2str(peer->allowtransfer));
                astman_append(s, "Maxforwards: %d\r\n", peer->maxforwards);
-               astman_append(s, "Maxforwards: %d\r\n", peer->maxforwards);
                astman_append(s, "Call-limit: %d\r\n", peer->call_limit);
                astman_append(s, "Busy-level: %d\r\n", peer->busy_level);
                astman_append(s, "MaxCallBR: %d kbps\r\n", peer->maxcallbitrate);
@@ -17504,10 +17947,10 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
                                astman_append(s, "ChanVariable: %s=%s\r\n", v->name, v->value);
                        }
                }
-               astman_append(s, "SIP-Use-Reason-Header : %s\r\n", (ast_test_flag(&peer->flags[1], SIP_PAGE2_Q850_REASON)) ? "Y" : "N");
-               astman_append(s, "Description : %s\r\n", peer->description);
+               astman_append(s, "SIP-Use-Reason-Header: %s\r\n", (ast_test_flag(&peer->flags[1], SIP_PAGE2_Q850_REASON)) ? "Y" : "N");
+               astman_append(s, "Description: %s\r\n", peer->description);
 
-               peer = unref_peer(peer, "sip_show_peer: unref_peer: done with peer");
+               peer = sip_unref_peer(peer, "sip_show_peer: sip_unref_peer: done with peer");
 
        } else {
                ast_cli(fd, "Peer %s not found.\n", argv[3]);
@@ -17531,7 +17974,7 @@ static char *complete_sip_user(const char *word, int state)
                ao2_lock(user);
                if (!(user->type & SIP_TYPE_USER)) {
                        ao2_unlock(user);
-                       unref_peer(user, "complete sip user");
+                       sip_unref_peer(user, "complete sip user");
                        continue;
                }
                /* locking of the object is not required because only the name and flags are being compared */
@@ -17539,7 +17982,7 @@ static char *complete_sip_user(const char *word, int state)
                        result = ast_strdup(user->name);
                }
                ao2_unlock(user);
-               unref_peer(user, "complete sip user");
+               sip_unref_peer(user, "complete sip user");
                if (result) {
                        break;
                }
@@ -17582,7 +18025,7 @@ static char *sip_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args
        /* Load from realtime storage? */
        load_realtime = (a->argc == 5 && !strcmp(a->argv[4], "load")) ? TRUE : FALSE;
 
-       if ((user = find_peer(a->argv[3], NULL, load_realtime, FINDUSERS, FALSE, 0))) {
+       if ((user = sip_find_peer(a->argv[3], NULL, load_realtime, FINDUSERS, FALSE, 0))) {
                ao2_lock(user);
                ast_cli(a->fd, "\n\n");
                ast_cli(a->fd, "  * Name       : %s\n", user->name);
@@ -17593,6 +18036,7 @@ static char *sip_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args
                if (!ast_strlen_zero(user->accountcode))
                        ast_cli(a->fd, "  Accountcode  : %s\n", user->accountcode);
                ast_cli(a->fd, "  AMA flags    : %s\n", ast_cdr_flags2str(user->amaflags));
+               ast_cli(a->fd, "  Tonezone     : %s\n", user->zone[0] != '\0' ? user->zone : "<Not set>");
                ast_cli(a->fd, "  Transfer mode: %s\n", transfermode2str(user->allowtransfer));
                ast_cli(a->fd, "  MaxCallBR    : %d kbps\n", user->maxcallbitrate);
                ast_cli(a->fd, "  CallingPres  : %s\n", ast_describe_caller_presentation(user->callingpres));
@@ -17623,7 +18067,7 @@ static char *sip_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args
                ast_cli(a->fd, "\n");
 
                ao2_unlock(user);
-               unref_peer(user, "sip show user");
+               sip_unref_peer(user, "sip show user");
        } else {
                ast_cli(a->fd, "User %s not found.\n", a->argv[3]);
                ast_cli(a->fd, "\n");
@@ -17749,16 +18193,16 @@ static char *sip_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
        if (a->argc != 3)
                return CLI_SHOWUSAGE;
        
-       if ((peer = find_peer(a->argv[2], NULL, load_realtime, FINDPEERS, TRUE, 0))) {
+       if ((peer = sip_find_peer(a->argv[2], NULL, load_realtime, FINDPEERS, TRUE, 0))) {
                if (peer->expire > 0) {
                        AST_SCHED_DEL_UNREF(sched, peer->expire,
-                               unref_peer(peer, "remove register expire ref"));
-                       expire_register(ref_peer(peer, "ref for expire_register"));
+                               sip_unref_peer(peer, "remove register expire ref"));
+                       expire_register(sip_ref_peer(peer, "ref for expire_register"));
                        ast_cli(a->fd, "Unregistered peer \'%s\'\n\n", a->argv[2]);
                } else {
                        ast_cli(a->fd, "Peer %s not registered\n", a->argv[2]);
                }
-               unref_peer(peer, "sip_unregister: unref_peer via sip_unregister: done with peer from find_peer call");
+               sip_unref_peer(peer, "sip_unregister: sip_unref_peer via sip_unregister: done with peer from sip_find_peer call");
        } else {
                ast_cli(a->fd, "Peer unknown: \'%s\'. Not unregistered.\n", a->argv[2]);
        }
@@ -17906,11 +18350,11 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
        ast_cli(a->fd, "  Videosupport:           %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_VIDEOSUPPORT)));
        ast_cli(a->fd, "  Textsupport:            %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_TEXTSUPPORT)));
        ast_cli(a->fd, "  Ignore SDP sess. ver.:  %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_IGNORESDPVERSION)));
-       ast_cli(a->fd, "  AutoCreate Peer:        %s\n", AST_CLI_YESNO(sip_cfg.autocreatepeer));
+       ast_cli(a->fd, "  AutoCreate Peer:        %s\n", autocreatepeer2str(sip_cfg.autocreatepeer));
        ast_cli(a->fd, "  Match Auth Username:    %s\n", AST_CLI_YESNO(global_match_auth_username));
        ast_cli(a->fd, "  Allow unknown access:   %s\n", AST_CLI_YESNO(sip_cfg.allowguest));
        ast_cli(a->fd, "  Allow subscriptions:    %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWSUBSCRIBE)));
-       ast_cli(a->fd, "  Allow overlap dialing:  %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP)));
+       ast_cli(a->fd, "  Allow overlap dialing:  %s\n", allowoverlap2str(ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP)));
        ast_cli(a->fd, "  Allow promisc. redir:   %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_PROMISCREDIR)));
        ast_cli(a->fd, "  Enable call counters:   %s\n", AST_CLI_YESNO(global_callcounter));
        ast_cli(a->fd, "  SIP domain support:     %s\n", AST_CLI_YESNO(!AST_LIST_EMPTY(&domain_list)));
@@ -17940,8 +18384,8 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
        ast_cli(a->fd, "  SDP Owner Name:         %s\n", ast_strlen_zero(global_sdpowner) ? "-" : global_sdpowner);
        ast_cli(a->fd, "  Reg. context:           %s\n", S_OR(sip_cfg.regcontext, "(not set)"));
        ast_cli(a->fd, "  Regexten on Qualify:    %s\n", AST_CLI_YESNO(sip_cfg.regextenonqualify));
-       ast_cli(a->fd, "  Trust RPID:             %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_TRUSTRPID)));
-       ast_cli(a->fd, "  Send RPID:              %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_SENDRPID)));
+       ast_cli(a->fd, "  Trust RPID:             %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_TRUSTRPID)));
+       ast_cli(a->fd, "  Send RPID:              %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_SENDRPID)));
        ast_cli(a->fd, "  Legacy userfield parse: %s\n", AST_CLI_YESNO(sip_cfg.legacy_useroption_parsing));
        ast_cli(a->fd, "  Caller ID:              %s\n", default_callerid);
        if ((default_fromdomainport) && (default_fromdomainport != STANDARD_SIP_PORT)) {
@@ -17962,6 +18406,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
                ast_cli(a->fd, "  SIP realtime:           Enabled\n" );
        ast_cli(a->fd, "  Qualify Freq :          %d ms\n", global_qualifyfreq);
        ast_cli(a->fd, "  Q.850 Reason header:    %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_Q850_REASON)));
+       ast_cli(a->fd, "  Store SIP_CAUSE:        %s\n", AST_CLI_YESNO(global_store_sip_cause));
        ast_cli(a->fd, "\nNetwork QoS Settings:\n");
        ast_cli(a->fd, "---------------------------\n");
        ast_cli(a->fd, "  IP ToS SIP:             %s\n", ast_tos2str(global_tos_sip));
@@ -17997,7 +18442,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
                msg = "Enabled using externaddr";
        ast_cli(a->fd, "  SIP address remapping:  %s\n", msg);
        ast_cli(a->fd, "  Externhost:             %s\n", S_OR(externhost, "<none>"));
-       ast_cli(a->fd, "  externaddr:               %s\n", ast_sockaddr_stringify(&externaddr));
+       ast_cli(a->fd, "  Externaddr:             %s\n", ast_sockaddr_stringify(&externaddr));
        ast_cli(a->fd, "  Externrefresh:          %d\n", externrefresh);
        {
                struct ast_ha *d;
@@ -18057,14 +18502,17 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
        ast_cli(a->fd, "\nDefault Settings:\n");
        ast_cli(a->fd, "-----------------\n");
        ast_cli(a->fd, "  Allowed transports:     %s\n", get_transport_list(default_transports));
-       ast_cli(a->fd, "  Outbound transport:     %s\n", get_transport(default_primary_transport));
+       ast_cli(a->fd, "  Outbound transport:     %s\n", sip_get_transport(default_primary_transport));
        ast_cli(a->fd, "  Context:                %s\n", sip_cfg.default_context);
+       ast_cli(a->fd, "  Record on feature:      %s\n", sip_cfg.default_record_on_feature);
+       ast_cli(a->fd, "  Record off feature:     %s\n", sip_cfg.default_record_off_feature);
        ast_cli(a->fd, "  Force rport:            %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_NAT_FORCE_RPORT)));
        ast_cli(a->fd, "  DTMF:                   %s\n", dtmfmode2str(ast_test_flag(&global_flags[0], SIP_DTMF)));
        ast_cli(a->fd, "  Qualify:                %d\n", default_qualify);
        ast_cli(a->fd, "  Use ClientCode:         %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_USECLIENTCODE)));
        ast_cli(a->fd, "  Progress inband:        %s\n", (ast_test_flag(&global_flags[0], SIP_PROG_INBAND) == SIP_PROG_INBAND_NEVER) ? "Never" : (AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_PROG_INBAND) != SIP_PROG_INBAND_NO)));
        ast_cli(a->fd, "  Language:               %s\n", default_language);
+       ast_cli(a->fd, "  Tone zone:              %s\n", default_zone[0] != '\0' ? default_zone : "<Not set>");
        ast_cli(a->fd, "  MOH Interpret:          %s\n", default_mohinterpret);
        ast_cli(a->fd, "  MOH Suggest:            %s\n", default_mohsuggest);
        ast_cli(a->fd, "  Voice Mail Extension:   %s\n", default_vmexten);
@@ -18288,7 +18736,7 @@ static char *complete_sip_peer(const char *word, int state, int flags2)
                                (!flags2 || ast_test_flag(&peer->flags[1], flags2)) &&
                                ++which > state)
                        result = ast_strdup(peer->name);
-               unref_peer(peer, "toss iterator peer ptr before break");
+               sip_unref_peer(peer, "toss iterator peer ptr before break");
                if (result) {
                        break;
                }
@@ -18313,10 +18761,10 @@ static char *complete_sip_registered_peer(const char *word, int state, int flags
                   ++which > state && peer->expire > 0)
                       result = ast_strdup(peer->name);
               if (result) {
-                      unref_peer(peer, "toss iterator peer ptr before break");
+                      sip_unref_peer(peer, "toss iterator peer ptr before break");
                       break;
               }
-              unref_peer(peer, "toss iterator peer ptr");
+              sip_unref_peer(peer, "toss iterator peer ptr");
        }
        ao2_iterator_destroy(&i);
        return result;
@@ -18608,9 +19056,9 @@ static void sip_dump_history(struct sip_pvt *dialog)
 /*! \brief  Receive SIP INFO Message */
 static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
 {
-       char buf[1024];
+       char buf[1024] = "";
        unsigned int event;
-       const char *c = get_header(req, "Content-Type");
+       const char *c = sip_get_header(req, "Content-Type");
 
        /* Need to check the media/type */
        if (!strcasecmp(c, "application/dtmf-relay") ||
@@ -18645,16 +19093,21 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
                        return;
                }
 
-               if (buf[0] == '*') {
+               if ('0' <= buf[0] && buf[0] <= '9') {
+                       event = buf[0] - '0';
+               } else if (buf[0] == '*') {
                        event = 10;
                } else if (buf[0] == '#') {
                        event = 11;
-               } else if ((buf[0] >= 'A') && (buf[0] <= 'D')) {
+               } else if ('A' <= buf[0] && buf[0] <= 'D') {
                        event = 12 + buf[0] - 'A';
+               } else if ('a' <= buf[0] && buf[0] <= 'd') {
+                       event = 12 + buf[0] - 'a';
                } else if (buf[0] == '!') {
                        event = 16;
                } else {
-                       event = atoi(buf);
+                       /* Unknown digit */
+                       event = 0;
                }
                if (event == 16) {
                        /* send a FLASH event */
@@ -18693,7 +19146,7 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
                        return;
                }
 
-               get_msg_text(buf, sizeof(buf), req, TRUE);
+               get_msg_text(buf, sizeof(buf), req);
                duration = 100; /* 100 ms */
 
                if (ast_strlen_zero(buf)) {
@@ -18719,6 +19172,9 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
                                f.subclass.integer = '#';
                        } else if (event < 16) {
                                f.subclass.integer = 'A' + (event - 12);
+                       } else {
+                               /* Unknown digit. */
+                               f.subclass.integer = '0';
                        }
                        f.len = duration;
                        ast_queue_frame(p->owner, &f);
@@ -18736,7 +19192,7 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
                }
                transmit_response(p, "200 OK", req);
                return;
-       } else if (!ast_strlen_zero(c = get_header(req, "X-ClientCode"))) {
+       } else if (!ast_strlen_zero(c = sip_get_header(req, "X-ClientCode"))) {
                /* Client code (from SNOM phone) */
                if (ast_test_flag(&p->flags[0], SIP_USECLIENTCODE)) {
                        if (p->owner && p->owner->cdr) {
@@ -18750,22 +19206,45 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
                        transmit_response(p, "403 Forbidden", req);
                }
                return;
-       } else if (!ast_strlen_zero(c = get_header(req, "Record"))) {
+       } else if (!ast_strlen_zero(c = sip_get_header(req, "Record"))) {
                /* INFO messages generated by some phones to start/stop recording
-                       on phone calls.
-                       OEJ: I think this should be something that is enabled/disabled
-                       per device. I don't want incoming callers to record calls in my
-                       pbx.
-               */
-               /* first, get the feature string, if it exists */
-               struct ast_call_feature *feat;
+                * on phone calls.
+                */
+
+               struct ast_call_feature *feat = NULL;
                int j;
                struct ast_frame f = { AST_FRAME_DTMF, };
+               int suppress_warning = 0; /* Supress warning if the feature is blank */
+
+               if (!p->owner) {        /* not a PBX call */
+                       transmit_response(p, "481 Call leg/transaction does not exist", req);
+                       sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+                       return;
+               }
 
+               /* first, get the feature string, if it exists */
                ast_rdlock_call_features();
-               feat = ast_find_call_feature("automon");
+               if (p->relatedpeer) {
+                       if (!strcasecmp(c, "on")) {
+                               if (ast_strlen_zero(p->relatedpeer->record_on_feature)) {
+                                       suppress_warning = 1;
+                               } else {
+                                       feat = ast_find_call_feature(p->relatedpeer->record_on_feature);
+                               }
+                       } else if (!strcasecmp(c, "off")) {
+                               if (ast_strlen_zero(p->relatedpeer->record_on_feature)) {
+                                       suppress_warning = 1;
+                               } else {
+                                       feat = ast_find_call_feature(p->relatedpeer->record_off_feature);
+                               }
+                       } else {
+                               ast_log(LOG_ERROR, "Received INFO requesting to record with invalid value: %s\n", c);
+                       }
+               }
                if (!feat || ast_strlen_zero(feat->exten)) {
-                       ast_log(LOG_WARNING, "Recording requested, but no One Touch Monitor registered. (See features.conf)\n");
+                       if (!suppress_warning) {
+                               ast_log(LOG_WARNING, "Recording requested, but no One Touch Monitor registered. (See features.conf)\n");
+                       }
                        /* 403 means that we don't support this feature, so don't request it again */
                        transmit_response(p, "403 Forbidden", req);
                        ast_unlock_call_features();
@@ -18785,7 +19264,7 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
                ast_debug(1, "Got a Request to Record the channel, state %s\n", c);
                transmit_response(p, "200 OK", req);
                return;
-       } else if (ast_strlen_zero(c = get_header(req, "Content-Length")) || !strcasecmp(c, "0")) {
+       } else if (ast_strlen_zero(c = sip_get_header(req, "Content-Length")) || !strcasecmp(c, "0")) {
                /* This is probably just a packet making sure the signalling is still up, just send back a 200 OK */
                transmit_response(p, "200 OK", req);
                return;
@@ -18815,7 +19294,7 @@ static char *sip_do_debug_ip(int fd, const char *arg)
 /*! \brief  Turn on SIP debugging for a given peer */
 static char *sip_do_debug_peer(int fd, const char *arg)
 {
-       struct sip_peer *peer = find_peer(arg, NULL, TRUE, FINDPEERS, FALSE, 0);
+       struct sip_peer *peer = sip_find_peer(arg, NULL, TRUE, FINDPEERS, FALSE, 0);
        if (!peer) {
                ast_cli(fd, "No such peer '%s'\n", arg);
        } else if (ast_sockaddr_isnull(&peer->addr)) {
@@ -18826,7 +19305,7 @@ static char *sip_do_debug_peer(int fd, const char *arg)
                sipdebug |= sip_debug_console;
        }
        if (peer) {
-               unref_peer(peer, "sip_do_debug_peer: unref_peer, from find_peer call");
+               sip_unref_peer(peer, "sip_do_debug_peer: sip_unref_peer, from sip_find_peer call");
        }
        return CLI_SUCCESS;
 }
@@ -18919,7 +19398,7 @@ static char *sip_cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 
                if (create_addr(p, a->argv[i], NULL, 1, NULL)) {
                        /* Maybe they're not registered, etc. */
-                       dialog_unlink_all(p, TRUE, TRUE);
+                       dialog_unlink_all(p);
                        dialog_unref(p, "unref dialog inside for loop" );
                        /* sip_destroy(p); */
                        ast_cli(a->fd, "Could not create address for '%s'\n", a->argv[i]);
@@ -18949,9 +19428,9 @@ static char *sip_cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 
                /* Recalculate our side, and recalculate Call ID */
                ast_cli(a->fd, "Sending NOTIFY of type '%s' to '%s'\n", a->argv[2], a->argv[i]);
-               dialog_ref(p, "bump the count of p, which transmit_sip_request will decrement.");
                sip_scheddestroy(p, SIP_TRANS_TIMEOUT);
                transmit_invite(p, SIP_NOTIFY, 0, 2, NULL);
+               dialog_unref(p, "bump down the count of p since we're done with it.");
        }
 
        return CLI_SUCCESS;
@@ -18994,7 +19473,7 @@ static int do_register_auth(struct sip_pvt *p, struct sip_request *req, enum sip
        char digest[1024];
 
        p->authtries++;
-       auth_headers(code, &header, &respheader);
+       sip_auth_headers(code, &header, &respheader);
        memset(digest, 0, sizeof(digest));
        if (reply_digest(p, req, header, SIP_REGISTER, digest, sizeof(digest))) {
                /* There's nothing to use for authentication */
@@ -19021,7 +19500,7 @@ static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req, enum sip_au
                return -2;
 
        p->authtries++;
-       auth_headers(code, &header, &respheader);
+       sip_auth_headers(code, &header, &respheader);
        ast_debug(2, "Auth attempt %d on %s\n", p->authtries, sip_methods[sipmethod].text);
        memset(digest, 0, sizeof(digest));
        if (reply_digest(p, req, header, sipmethod, digest, sizeof(digest) )) {
@@ -19057,7 +19536,7 @@ static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header
                { NULL, 0 },
        };
 
-       ast_copy_string(tmp, get_header(req, header), sizeof(tmp));
+       ast_copy_string(tmp, sip_get_header(req, header), sizeof(tmp));
        if (ast_strlen_zero(tmp))
                return -1;
        if (strncasecmp(tmp, "Digest ", strlen("Digest "))) {
@@ -19312,7 +19791,7 @@ static int function_sippeer(struct ast_channel *chan, const char *cmd, char *dat
        else
                colname = "ip";
 
-       if (!(peer = find_peer(data, NULL, TRUE, FINDPEERS, FALSE, 0)))
+       if (!(peer = sip_find_peer(data, NULL, TRUE, FINDPEERS, FALSE, 0)))
                return -1;
 
        if (!strcasecmp(colname, "ip")) {
@@ -19384,7 +19863,7 @@ static int function_sippeer(struct ast_channel *chan, const char *cmd, char *dat
                buf[0] = '\0';
        }
 
-       unref_peer(peer, "unref_peer from function_sippeer, just before return");
+       sip_unref_peer(peer, "sip_unref_peer from function_sippeer, just before return");
 
        return 0;
 }
@@ -19479,7 +19958,7 @@ static void change_redirecting_information(struct sip_pvt *p, struct sip_request
        res = get_rdnis(p, req, &redirecting_from_name, &redirecting_from_number, &reason);
        if (res == -1) {
                if (is_response) {
-                       get_name_and_number(get_header(req, "TO"), &redirecting_from_name, &redirecting_from_number);
+                       get_name_and_number(sip_get_header(req, "TO"), &redirecting_from_name, &redirecting_from_number);
                } else {
                        return;
                }
@@ -19492,7 +19971,7 @@ static void change_redirecting_information(struct sip_pvt *p, struct sip_request
        if (is_response) {
                parse_moved_contact(p, req, &redirecting_to_name, &redirecting_to_number, set_call_forward);
        } else {
-               get_name_and_number(get_header(req, "TO"), &redirecting_to_name, &redirecting_to_number);
+               get_name_and_number(sip_get_header(req, "TO"), &redirecting_to_name, &redirecting_to_number);
        }
 
        if (!ast_strlen_zero(redirecting_from_number)) {
@@ -19547,7 +20026,7 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char
        char *domain;
        enum sip_transport transport = SIP_TRANSPORT_UDP;
 
-       ast_copy_string(contact, get_header(req, "Contact"), sizeof(contact));
+       ast_copy_string(contact, sip_get_header(req, "Contact"), sizeof(contact));
        if ((separator = strchr(contact, ',')))
                *separator = '\0';
 
@@ -19589,13 +20068,13 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char
                        *separator = '\0';
                if ((host = strchr(contact_number, '@'))) {
                        *host++ = '\0';
-                       ast_debug(2, "Found promiscuous redirection to 'SIP/%s::::%s@%s'\n", contact_number, get_transport(transport), host);
+                       ast_debug(2, "Found promiscuous redirection to 'SIP/%s::::%s@%s'\n", contact_number, sip_get_transport(transport), host);
                        if (p->owner)
-                               ast_string_field_build(p->owner, call_forward, "SIP/%s::::%s@%s", contact_number, get_transport(transport), host);
+                               ast_string_field_build(p->owner, call_forward, "SIP/%s::::%s@%s", contact_number, sip_get_transport(transport), host);
                } else {
-                       ast_debug(2, "Found promiscuous redirection to 'SIP/::::%s@%s'\n", get_transport(transport), contact_number);
+                       ast_debug(2, "Found promiscuous redirection to 'SIP/::::%s@%s'\n", sip_get_transport(transport), contact_number);
                        if (p->owner)
-                               ast_string_field_build(p->owner, call_forward, "SIP/::::%s@%s", get_transport(transport), contact_number);
+                               ast_string_field_build(p->owner, call_forward, "SIP/::::%s@%s", sip_get_transport(transport), contact_number);
                }
        } else {
                separator = strchr(contact, '@');
@@ -19723,7 +20202,7 @@ static void handle_response_update(struct sip_pvt *p, int resp, const char *rest
                p->options->auth_type = (resp == 401 ? WWW_AUTH : PROXY_AUTH);
        }
        if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, resp, SIP_UPDATE, 1)) {
-               ast_log(LOG_NOTICE, "Failed to authenticate on UPDATE to '%s'\n", get_header(&p->initreq, "From"));
+               ast_log(LOG_NOTICE, "Failed to authenticate on UPDATE to '%s'\n", sip_get_header(&p->initreq, "From"));
        }
 }
 
@@ -19754,7 +20233,7 @@ static void cc_handle_publish_error(struct sip_pvt *pvt, const int resp, struct
         * XXX Ideally this logic could be placed into its own function so that SUBSCRIBE,
         * PUBLISH, and REGISTER could all benefit from the same shared code.
         */
-       min_expires = get_header(req, "Min-Expires");
+       min_expires = sip_get_header(req, "Min-Expires");
        if (ast_strlen_zero(min_expires)) {
                pvt->expiry *= 2;
                if (pvt->expiry < 0) {
@@ -19780,7 +20259,7 @@ static void cc_handle_publish_error(struct sip_pvt *pvt, const int resp, struct
 static void handle_response_publish(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno)
 {
        struct sip_epa_entry *epa_entry = p->epa_entry;
-       const char *etag = get_header(req, "Sip-ETag");
+       const char *etag = sip_get_header(req, "Sip-ETag");
 
        ast_assert(epa_entry != NULL);
 
@@ -19790,7 +20269,7 @@ static void handle_response_publish(struct sip_pvt *p, int resp, const char *res
                        p->options->auth_type = (resp == 401 ? WWW_AUTH : PROXY_AUTH);
                }
                if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, resp, SIP_PUBLISH, 0)) {
-                       ast_log(LOG_NOTICE, "Failed to authenticate on PUBLISH to '%s'\n", get_header(&p->initreq, "From"));
+                       ast_log(LOG_NOTICE, "Failed to authenticate on PUBLISH to '%s'\n", sip_get_header(&p->initreq, "From"));
                        pvt_set_needdestroy(p, "Failed to authenticate on PUBLISH");
                        sip_alreadygone(p);
                }
@@ -19839,10 +20318,11 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
        struct ast_party_connected_line connected;
        struct ast_set_party_connected_line update_connected;
 
-       if (reinvite)
+       if (reinvite) {
                ast_debug(4, "SIP response %d to RE-invite on %s call %s\n", resp, outgoing ? "outgoing" : "incoming", p->callid);
-       else
+       } else {
                ast_debug(4, "SIP response %d to standard invite\n", resp);
+       }
 
        if (p->alreadygone) { /* This call is already gone */
                ast_debug(1, "Got response on call that is already terminated: %s (ignoring)\n", p->callid);
@@ -19856,8 +20336,9 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
        /* RFC3261 says we must treat every 1xx response (but not 100)
           that we don't recognize as if it was 183.
        */
-       if (resp > 100 && resp < 200 && resp!=101 && resp != 180 && resp != 181 && resp != 182 && resp != 183)
+       if (resp > 100 && resp < 200 && resp!=101 && resp != 180 && resp != 181 && resp != 182 && resp != 183) {
                resp = 183;
+       }
 
        /* For INVITE, treat all 2XX responses as we would a 200 response */
        if ((resp >= 200) && (resp < 300)) {
@@ -19865,16 +20346,19 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
        }
 
        /* Any response between 100 and 199 is PROCEEDING */
-       if (resp >= 100 && resp < 200 && p->invitestate == INV_CALLING)
+       if (resp >= 100 && resp < 200 && p->invitestate == INV_CALLING) {
                p->invitestate = INV_PROCEEDING;
+       }
 
        /* Final response, not 200 ? */
-       if (resp >= 300 && (p->invitestate == INV_CALLING || p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA ))
+       if (resp >= 300 && (p->invitestate == INV_CALLING || p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA )) {
                p->invitestate = INV_COMPLETED;
+       }
        
        /* Final response, clear out pending invite */
-       if ((resp == 200 || resp >= 300) && p->pendinginvite && seqno == p->pendinginvite)
+       if ((resp == 200 || resp >= 300) && p->pendinginvite && seqno == p->pendinginvite) {
                p->pendinginvite = 0;
+       }
 
        /* If this is a response to our initial INVITE, we need to set what we can use
         * for this peer.
@@ -19886,15 +20370,24 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
        switch (resp) {
        case 100:       /* Trying */
        case 101:       /* Dialog establishment */
-               if (!req->ignore && p->invitestate != INV_CANCELLED && sip_cancel_destroy(p))
+               if (!req->ignore && p->invitestate != INV_CANCELLED && sip_cancel_destroy(p)) {
                        ast_log(LOG_WARNING, "Unable to cancel SIP destruction.  Expect bad things.\n");
+               }
                check_pendings(p);
                break;
 
        case 180:       /* 180 Ringing */
        case 182:       /* 182 Queued */
-               if (!req->ignore && p->invitestate != INV_CANCELLED && sip_cancel_destroy(p))
+               if (!req->ignore && p->invitestate != INV_CANCELLED && sip_cancel_destroy(p)) {
                        ast_log(LOG_WARNING, "Unable to cancel SIP destruction.  Expect bad things.\n");
+               }
+               /* Store Route-set from provisional SIP responses so
+                * early-dialog request can be routed properly
+                * */
+               parse_ok_contact(p, req);
+               if (!reinvite) {
+                       build_route(p, req, 1);
+               }
                if (!req->ignore && p->owner) {
                        if (get_rpid(p, req)) {
                                /* Queue a connected line update */
@@ -19923,8 +20416,9 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                        }
                }
                if (find_sdp(req)) {
-                       if (p->invitestate != INV_CANCELLED)
+                       if (p->invitestate != INV_CANCELLED) {
                                p->invitestate = INV_EARLY_MEDIA;
+                       }
                        res = process_sdp(p, req, SDP_T38_NONE);
                        if (!req->ignore && p->owner) {
                                /* Queue a progress frame only if we have SDP in 180 or 182 */
@@ -19938,6 +20432,13 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
        case 181:       /* Call Is Being Forwarded */
                if (!req->ignore && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p))
                        ast_log(LOG_WARNING, "Unable to cancel SIP destruction.  Expect bad things.\n");
+               /* Store Route-set from provisional SIP responses so
+                * early-dialog request can be routed properly
+                * */
+               parse_ok_contact(p, req);
+               if (!reinvite) {
+                       build_route(p, req, 1);
+               }
                if (!req->ignore && p->owner) {
                        struct ast_party_redirecting redirecting;
                        struct ast_set_party_redirecting update_redirecting;
@@ -19955,8 +20456,16 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                break;
 
        case 183:       /* Session progress */
-               if (!req->ignore && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p))
+               if (!req->ignore && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p)) {
                        ast_log(LOG_WARNING, "Unable to cancel SIP destruction.  Expect bad things.\n");
+               }
+               /* Store Route-set from provisional SIP responses so
+                * early-dialog request can be routed properly
+                * */
+               parse_ok_contact(p, req);
+               if (!reinvite) {
+                       build_route(p, req, 1);
+               }
                if (!req->ignore && p->owner) {
                        if (get_rpid(p, req)) {
                                /* Queue a connected line update */
@@ -19981,8 +20490,9 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                        sip_handle_cc(p, req, AST_CC_CCNR);
                }
                if (find_sdp(req)) {
-                       if (p->invitestate != INV_CANCELLED)
+                       if (p->invitestate != INV_CANCELLED) {
                                p->invitestate = INV_EARLY_MEDIA;
+                       }
                        res = process_sdp(p, req, SDP_T38_NONE);
                        if (!req->ignore && p->owner) {
                                /* Queue a progress frame */
@@ -20002,8 +20512,9 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                break;
 
        case 200:       /* 200 OK on invite - someone's answering our call */
-               if (!req->ignore && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p))
+               if (!req->ignore && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p)) {
                        ast_log(LOG_WARNING, "Unable to cancel SIP destruction.  Expect bad things.\n");
+               }
                p->authtries = 0;
                if (find_sdp(req)) {
                        if ((res = process_sdp(p, req, SDP_T38_ACCEPT)) && !req->ignore)
@@ -20054,14 +20565,16 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                        update_call_counter(p, DEC_CALL_RINGING);
                        parse_ok_contact(p, req);
                        /* Save Record-Route for any later requests we make on this dialogue */
-                       if (!reinvite)
+                       if (!reinvite) {
                                build_route(p, req, 1);
+                       }
 
                        if(set_address_from_contact(p)) {
                                /* Bad contact - we don't know how to reach this device */
                                /* We need to ACK, but then send a bye */
-                               if (!p->route && !req->ignore)
+                               if (!p->route && !req->ignore) {
                                        ast_set_flag(&p->flags[0], SIP_PENDINGBYE);     
+                               }
                        }
 
                }
@@ -20069,24 +20582,30 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                if (!req->ignore && p->owner) {
                        if (!reinvite) {
                                ast_queue_control(p->owner, AST_CONTROL_ANSWER);
-                               if (sip_cfg.callevents)
+                               if (sip_cfg.callevents) {
                                        manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
                                                "Channel: %s\r\nChanneltype: %s\r\nUniqueid: %s\r\nSIPcallid: %s\r\nSIPfullcontact: %s\r\nPeername: %s\r\n",
                                                p->owner->name, "SIP", p->owner->uniqueid, p->callid, p->fullcontact, p->peername);
+                               }
                        } else {        /* RE-invite */
-                               ast_queue_frame(p->owner, &ast_null_frame);
+                               if (p->t38.state == T38_DISABLED || p->t38.state == T38_REJECTED) {
+                                       ast_queue_control(p->owner, AST_CONTROL_UPDATE_RTP_PEER);
+                               } else {
+                                       ast_queue_frame(p->owner, &ast_null_frame);
+                               }
                        }
                } else {
                         /* It's possible we're getting an 200 OK after we've tried to disconnect
                                  by sending CANCEL */
                        /* First send ACK, then send bye */
-                       if (!req->ignore)
+                       if (!req->ignore) {
                                ast_set_flag(&p->flags[0], SIP_PENDINGBYE);     
+                       }
                }
 
                /* Check for Session-Timers related headers */
                if (st_get_mode(p, 0) != SESSION_TIMER_MODE_REFUSE && p->outgoing_call == TRUE && !reinvite) {
-                       p_hdrval = (char*)get_header(req, "Session-Expires");
+                       p_hdrval = (char*)sip_get_header(req, "Session-Expires");
                        if (!ast_strlen_zero(p_hdrval)) {
                                /* UAS supports Session-Timers */
                                enum st_refresher tmp_st_ref = SESSION_TIMER_REFRESHER_AUTO;
@@ -20127,20 +20646,23 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
        case 401: /* Www auth */
                /* First we ACK */
                xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
-               if (p->options)
+               if (p->options) {
                        p->options->auth_type = resp;
+               }
 
                /* Then we AUTH */
                ast_string_field_set(p, theirtag, NULL);        /* forget their old tag, so we don't match tags when getting response */
                if (!req->ignore) {
-                       if (p->authtries < MAX_AUTHTRIES)
+                       if (p->authtries < MAX_AUTHTRIES) {
                                p->invitestate = INV_CALLING;
+                       }
                        if (p->authtries == MAX_AUTHTRIES || do_proxy_auth(p, req, resp, SIP_INVITE, 1)) {
-                               ast_log(LOG_NOTICE, "Failed to authenticate on INVITE to '%s'\n", get_header(&p->initreq, "From"));
+                               ast_log(LOG_NOTICE, "Failed to authenticate on INVITE to '%s'\n", sip_get_header(&p->initreq, "From"));
                                pvt_set_needdestroy(p, "failed to authenticate on INVITE");
                                sip_alreadygone(p);
-                               if (p->owner)
+                               if (p->owner) {
                                        ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
+                               }
                        }
                }
                break;
@@ -20148,7 +20670,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
        case 403: /* Forbidden */
                /* First we ACK */
                xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
-               ast_log(LOG_WARNING, "Received response: \"Forbidden\" from '%s'\n", get_header(&p->initreq, "From"));
+               ast_log(LOG_WARNING, "Received response: \"Forbidden\" from '%s'\n", sip_get_header(&p->initreq, "From"));
                if (!req->ignore && p->owner) {
                        ast_set_hangupsource(p->owner, p->owner->name, 0);
                        ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
@@ -20171,8 +20693,9 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                /* Could be REFER caused INVITE with replaces */
                ast_log(LOG_WARNING, "Re-invite to non-existing call leg on other UA. SIP dialog '%s'. Giving up.\n", p->callid);
                xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
-               if (p->owner)
+               if (p->owner) {
                        ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
+               }
                sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
                break;
 
@@ -20186,8 +20709,9 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
                append_history(p, "Identity", "SIP identity is required. Not supported by Asterisk.");
                ast_log(LOG_WARNING, "SIP identity required by proxy. SIP dialog '%s'. Giving up.\n", p->callid);
-               if (p->owner)
+               if (p->owner) {
                        ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
+               }
                break;
 
                
@@ -20214,18 +20738,21 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                if (p->udptl && p->t38.state == T38_LOCAL_REINVITE) {
                        change_t38_state(p, T38_REJECTED);
                        /* Try to reset RTP timers */
+                       /* XXX Why is this commented away??? */
                        //ast_rtp_set_rtptimers_onhold(p->rtp);
 
                        /* Trigger a reinvite back to audio */
                        transmit_reinvite_with_sdp(p, FALSE, FALSE);
                } else {
                        /* We can't set up this call, so give up */
-                       if (p->owner && !req->ignore)
+                       if (p->owner && !req->ignore) {
                                ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
+                       }
                        pvt_set_needdestroy(p, "received 488 response");
                        /* If there's no dialog to end, then mark p as already gone */
-                       if (!reinvite)
+                       if (!reinvite) {
                                sip_alreadygone(p);
+                       }
                }
                break;
        case 491: /* Pending */
@@ -20256,12 +20783,14 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
        case 405: /* Not allowed */
        case 501: /* Not implemented */
                xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
-               if (p->owner)
+               if (p->owner) {
                        ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
+               }
                break;
        }
-       if (xmitres == XMIT_ERROR)
+       if (xmitres == XMIT_ERROR) {
                ast_log(LOG_WARNING, "Could not transmit message in dialog %s\n", p->callid);
+       }
 }
 
 /* \brief Handle SIP response in NOTIFY transaction
@@ -20302,7 +20831,7 @@ static void handle_response_notify(struct sip_pvt *p, int resp, const char *rest
                        pvt_set_needdestroy(p, "unable to authenticate NOTIFY");
                }
                if (p->authtries > 1 || do_proxy_auth(p, req, resp, SIP_NOTIFY, 0)) {
-                       ast_log(LOG_NOTICE, "Failed to authenticate on NOTIFY to '%s'\n", get_header(&p->initreq, "From"));
+                       ast_log(LOG_NOTICE, "Failed to authenticate on NOTIFY to '%s'\n", sip_get_header(&p->initreq, "From"));
                        pvt_set_needdestroy(p, "failed to authenticate NOTIFY");
                }
                break;
@@ -20354,7 +20883,7 @@ static void handle_response_subscribe(struct sip_pvt *p, int resp, const char *r
        case 407:
                ast_string_field_set(p, theirtag, NULL);
                if (p->authtries > 1 || do_proxy_auth(p, req, resp, SIP_SUBSCRIBE, 0)) {
-                       ast_log(LOG_NOTICE, "Failed to authenticate on SUBSCRIBE to '%s'\n", get_header(&p->initreq, "From"));
+                       ast_log(LOG_NOTICE, "Failed to authenticate on SUBSCRIBE to '%s'\n", sip_get_header(&p->initreq, "From"));
                        p->mwi->call = NULL;
                        ASTOBJ_UNREF(p->mwi, sip_subscribe_mwi_destroy);
                        pvt_set_needdestroy(p, "failed to authenticate SUBSCRIBE");
@@ -20422,7 +20951,7 @@ static void handle_response_refer(struct sip_pvt *p, int resp, const char *rest,
                        pvt_set_needdestroy(p, "unable to authenticate REFER");
                }
                if (p->authtries > 1 || do_proxy_auth(p, req, resp, SIP_REFER, 0)) {
-                       ast_log(LOG_NOTICE, "Failed to authenticate on REFER to '%s'\n", get_header(&p->initreq, "From"));
+                       ast_log(LOG_NOTICE, "Failed to authenticate on REFER to '%s'\n", sip_get_header(&p->initreq, "From"));
                        p->refer->status = REFER_NOAUTH;
                        if (p->owner) {
                                ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message));
@@ -20522,7 +21051,7 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
                break;
        case 407:       /* Proxy auth */
                if (p->authtries == MAX_AUTHTRIES || do_register_auth(p, req, resp)) {
-                       ast_log(LOG_NOTICE, "Failed to authenticate on REGISTER to '%s' (tries '%d')\n", get_header(&p->initreq, "From"), p->authtries);
+                       ast_log(LOG_NOTICE, "Failed to authenticate on REGISTER to '%s' (tries '%d')\n", sip_get_header(&p->initreq, "From"), p->authtries);
                        pvt_set_needdestroy(p, "failed to authenticate REGISTER");
                }
                break;
@@ -20535,7 +21064,7 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
                }
                break;
        case 423:       /* Interval too brief */
-               r->expiry = atoi(get_header(req, "Min-Expires"));
+               r->expiry = atoi(sip_get_header(req, "Min-Expires"));
                ast_log(LOG_WARNING, "Got 423 Interval too brief for service %s@%s, minimum is %d seconds\n", p->registry->username, p->registry->hostname, r->expiry);
                AST_SCHED_DEL_UNREF(sched, r->timeout, registry_unref(r, "reg ptr unref from handle_response_register 423"));
                if (r->call) {
@@ -20590,7 +21119,7 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
                expires = 0;
 
                /* XXX todo: try to save the extra call */
-               if (!ast_strlen_zero(get_header(req, "Contact"))) {
+               if (!ast_strlen_zero(sip_get_header(req, "Contact"))) {
                        const char *contact = NULL;
                        const char *tmptmp = NULL;
                        int start = 0;
@@ -20613,7 +21142,7 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
                        
                }
                if (!expires)
-                       expires=atoi(get_header(req, "expires"));
+                       expires=atoi(sip_get_header(req, "expires"));
                if (!expires)
                        expires=default_expiry;
                
@@ -20639,7 +21168,7 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
 /*! \brief Handle qualification responses (OPTIONS) */
 static void handle_response_peerpoke(struct sip_pvt *p, int resp, struct sip_request *req)
 {
-       struct sip_peer *peer = /* ref_peer( */ p->relatedpeer /* , "bump refcount on p, as it is being used in this function(handle_response_peerpoke)")*/ ; /* hope this is already refcounted! */
+       struct sip_peer *peer = /* sip_ref_peer( */ p->relatedpeer /* , "bump refcount on p, as it is being used in this function(handle_response_peerpoke)")*/ ; /* hope this is already refcounted! */
        int statechanged, is_reachable, was_reachable;
        int pingtime = ast_tvdiff_ms(ast_tvnow(), peer->ps);
 
@@ -20648,8 +21177,14 @@ static void handle_response_peerpoke(struct sip_pvt *p, int resp, struct sip_req
         * -1 means did not respond, 0 means unknown,
         * 1..maxms is a valid response, >maxms means late response.
         */
-       if (pingtime < 1)       /* zero = unknown, so round up to 1 */
+       if (pingtime < 1) {     /* zero = unknown, so round up to 1 */
                pingtime = 1;
+       }
+
+       if (!peer->maxms) { /* this should never happens */
+               pvt_set_needdestroy(p, "got OPTIONS response but qualify is not enabled");
+               return;
+       }
 
        /* Now determine new state and whether it has changed.
         * Use some helper variables to simplify the writing
@@ -20686,9 +21221,9 @@ static void handle_response_peerpoke(struct sip_pvt *p, int resp, struct sip_req
        AST_SCHED_REPLACE_UNREF(peer->pokeexpire, sched,
                        is_reachable ? peer->qualifyfreq : DEFAULT_FREQ_NOTOK,
                        sip_poke_peer_s, peer,
-                       unref_peer(_data, "removing poke peer ref"),
-                       unref_peer(peer, "removing poke peer ref"),
-                       ref_peer(peer, "adding poke peer ref"));
+                       sip_unref_peer(_data, "removing poke peer ref"),
+                       sip_unref_peer(peer, "removing poke peer ref"),
+                       sip_ref_peer(peer, "adding poke peer ref"));
 }
 
 /*!
@@ -20748,7 +21283,7 @@ static int do_message_auth(struct sip_pvt *p, int resp, const char *rest, struct
        }
 
        ++p->authtries;
-       auth_headers((resp == 401 ? WWW_AUTH : PROXY_AUTH), &header, &respheader);
+       sip_auth_headers((resp == 401 ? WWW_AUTH : PROXY_AUTH), &header, &respheader);
        memset(digest, 0, sizeof(digest));
        if (reply_digest(p, req, header, SIP_MESSAGE, digest, sizeof(digest))) {
                /* There's nothing to use for authentication */
@@ -20836,7 +21371,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
 {
        struct ast_channel *owner;
        int sipmethod;
-       const char *c = get_header(req, "Cseq");
+       const char *c = sip_get_header(req, "Cseq");
        /* GCC 4.2 complains if I try to cast c as a char * when passing it to ast_skip_nonblanks, so make a copy of it */
        char *c_copy = ast_strdupa(c);
        /* Skip the Cseq and its subsequent spaces */
@@ -20852,7 +21387,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
                const char *rp = NULL, *rh = NULL;
 
                owner->hangupcause = 0;
-               if (ast_test_flag(&p->flags[1], SIP_PAGE2_Q850_REASON) && (rh = get_header(req, "Reason"))) {
+               if (ast_test_flag(&p->flags[1], SIP_PAGE2_Q850_REASON) && (rh = sip_get_header(req, "Reason"))) {
                        rh = ast_skip_blanks(rh);
                        if (!strncasecmp(rh, "Q.850", 5)) {
                                rp = strstr(rh, "cause=");
@@ -20923,7 +21458,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
                return;
        }
 
-       if (p->relatedpeer && p->method == SIP_OPTIONS) {
+       if (p->relatedpeer && sipmethod == SIP_OPTIONS) {
                /* We don't really care what the response is, just that it replied back.
                   Well, as long as it's not a 100 response...  since we might
                   need to hang around for something more "definitive" */
@@ -20989,11 +21524,11 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
                                                        msg, ast_sockaddr_stringify(&p->recv));
                                        pvt_set_needdestroy(p, "unable to authenticate BYE");
                                } else if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, resp,  sipmethod, 0)) {
-                                       ast_log(LOG_NOTICE, "Failed to authenticate on %s to '%s'\n", msg, get_header(&p->initreq, "From"));
+                                       ast_log(LOG_NOTICE, "Failed to authenticate on %s to '%s'\n", msg, sip_get_header(&p->initreq, "From"));
                                        pvt_set_needdestroy(p, "failed to authenticate BYE");
                                }
                        } else {
-                               ast_log(LOG_WARNING, "Got authentication request (%d) on %s to '%s'\n", resp, sip_methods[sipmethod].text, get_header(req, "To"));
+                               ast_log(LOG_WARNING, "Got authentication request (%d) on %s to '%s'\n", resp, sip_methods[sipmethod].text, sip_get_header(req, "To"));
                                pvt_set_needdestroy(p, "received 407 response");
                        }
                        break;
@@ -21149,6 +21684,18 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
                                        if (owner)
                                                ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
                                        break;
+                               case 484: /* Address Incomplete */
+                                       if (owner && sipmethod != SIP_BYE) {
+                                               switch (ast_test_flag(&p->flags[1], SIP_PAGE2_ALLOWOVERLAP)) {
+                                               case SIP_PAGE2_ALLOWOVERLAP_YES:
+                                                       ast_queue_hangup_with_cause(p->owner, hangup_sip2cause(resp));
+                                                       break;
+                                               default:
+                                                       ast_queue_hangup_with_cause(p->owner, hangup_sip2cause(404));
+                                                       break;
+                                               }
+                                       }
+                                       break;
                                default:
                                        /* Send hangup */       
                                        if (owner && sipmethod != SIP_BYE)
@@ -21227,7 +21774,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
                                handle_response_invite(p, resp, rest, req, seqno);
                        else if (sipmethod == SIP_BYE) {
                                if (p->authtries == MAX_AUTHTRIES || do_proxy_auth(p, req, resp, sipmethod, 0)) {
-                                       ast_log(LOG_NOTICE, "Failed to authenticate on %s to '%s'\n", msg, get_header(&p->initreq, "From"));
+                                       ast_log(LOG_NOTICE, "Failed to authenticate on %s to '%s'\n", msg, sip_get_header(&p->initreq, "From"));
                                        pvt_set_needdestroy(p, "failed to authenticate BYE");
                                }
                        }
@@ -21291,35 +21838,19 @@ static void *sip_park_thread(void *stuff)
 {
        struct ast_channel *transferee, *transferer;    /* Chan1: The transferee, Chan2: The transferer */
        struct sip_dual *d;
-       struct sip_request req = {0,};
        int ext;
        int res;
 
        d = stuff;
        transferee = d->chan1;
        transferer = d->chan2;
-       copy_request(&req, &d->req);
 
-       if (!transferee || !transferer) {
-               ast_log(LOG_ERROR, "Missing channels for parking! Transferer %s Transferee %s\n", transferer ? "<available>" : "<missing>", transferee ? "<available>" : "<missing>" );
-               deinit_req(&d->req);
-               ast_free(d);
-               return NULL;
-       }
        ast_debug(4, "SIP Park: Transferer channel %s, Transferee %s\n", transferer->name, transferee->name);
 
-       if (ast_do_masquerade(transferee)) {
-               ast_log(LOG_WARNING, "Masquerade failed.\n");
-               transmit_response(transferer->tech_pvt, "503 Internal error", &req);
-               deinit_req(&d->req);
-               ast_free(d);
-               return NULL;
-       }
-
-       res = ast_park_call(transferee, transferer, 0, d->parkexten, &ext);
+       res = ast_park_call_exten(transferee, transferer, d->park_exten, d->park_context, 0, &ext);
 
 #ifdef WHEN_WE_KNOW_THAT_THE_CLIENT_SUPPORTS_MESSAGE
-       if (!res) {
+       if (res) {
                transmit_message_with_text(transferer->tech_pvt, "Unable to park call.\n", 0, 0);
        } else {
                /* Then tell the transferer what happened */
@@ -21344,31 +21875,40 @@ static void *sip_park_thread(void *stuff)
                /* Do not hangup call */
        }
        deinit_req(&d->req);
+       ast_free(d->park_exten);
+       ast_free(d->park_context);
        ast_free(d);
        return NULL;
 }
 
-/*! \brief Park a call using the subsystem in res_features.c
-       This is executed in a separate thread
-*/
-static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno, char *parkexten)
+/*! DO NOT hold any locks while calling sip_park */
+static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno, const char *park_exten, const char *park_context)
 {
        struct sip_dual *d;
        struct ast_channel *transferee, *transferer;
-               /* Chan2m: The transferer, chan1m: The transferee */
        pthread_t th;
 
        transferee = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan1->accountcode, chan1->exten, chan1->context, chan1->linkedid, chan1->amaflags, "Parking/%s", chan1->name);
        transferer = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan2->exten, chan2->context, chan2->linkedid, chan2->amaflags, "SIPPeer/%s", chan2->name);
-       if ((!transferer) || (!transferee)) {
+       d = ast_calloc(1, sizeof(*d));
+       if (!transferee || !transferer || !d) {
                if (transferee) {
-                       transferee->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
                        ast_hangup(transferee);
                }
                if (transferer) {
-                       transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
                        ast_hangup(transferer);
                }
+               ast_free(d);
+               return -1;
+       }
+       d->park_exten = ast_strdup(park_exten);
+       d->park_context = ast_strdup(park_context);
+       if (!d->park_exten || !d->park_context) {
+               ast_hangup(transferee);
+               ast_hangup(transferer);
+               ast_free(d->park_exten);
+               ast_free(d->park_context);
+               ast_free(d);
                return -1;
        }
 
@@ -21377,67 +21917,56 @@ static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct
        transferee->writeformat = chan1->writeformat;
 
        /* Prepare for taking over the channel */
-       ast_channel_masquerade(transferee, chan1);
+       if (ast_channel_masquerade(transferee, chan1)) {
+               ast_hangup(transferee);
+               ast_hangup(transferer);
+               ast_free(d->park_exten);
+               ast_free(d->park_context);
+               ast_free(d);
+               return -1;
+       }
 
        /* Setup the extensions and such */
        ast_copy_string(transferee->context, chan1->context, sizeof(transferee->context));
        ast_copy_string(transferee->exten, chan1->exten, sizeof(transferee->exten));
        transferee->priority = chan1->priority;
-               
+
+       ast_do_masquerade(transferee);
+
        /* We make a clone of the peer channel too, so we can play
           back the announcement */
 
        /* Make formats okay */
        transferer->readformat = chan2->readformat;
        transferer->writeformat = chan2->writeformat;
-       if (!ast_strlen_zero(chan2->parkinglot))
-               ast_string_field_set(transferer, parkinglot, chan2->parkinglot);
-
-       /* Prepare for taking over the channel.  Go ahead and grab this channel
-        * lock here to avoid a deadlock with callbacks into the channel driver
-        * that hold the channel lock and want the pvt lock.  */
-       while (ast_channel_trylock(chan2)) {
-               struct sip_pvt *pvt = chan2->tech_pvt;
-               sip_pvt_unlock(pvt);
-               usleep(1);
-               sip_pvt_lock(pvt);
-       }
-       ast_channel_masquerade(transferer, chan2);
-       ast_channel_unlock(chan2);
+       ast_string_field_set(transferer, parkinglot, chan2->parkinglot);
 
-       /* Setup the extensions and such */
-       ast_copy_string(transferer->context, chan2->context, sizeof(transferer->context));
-       ast_copy_string(transferer->exten, chan2->exten, sizeof(transferer->exten));
-       transferer->priority = chan2->priority;
-
-       if (ast_do_masquerade(transferer)) {
-               ast_log(LOG_WARNING, "Masquerade failed :(\n");
-               transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
+       /* Prepare for taking over the channel */
+       if (ast_channel_masquerade(transferer, chan2)) {
                ast_hangup(transferer);
+               ast_free(d->park_exten);
+               ast_free(d->park_context);
+               ast_free(d);
                return -1;
        }
-       if (!transferer || !transferee) {
-               if (!transferer) {
-                       ast_debug(1, "No transferer channel, giving up parking\n");
-               }
-               if (!transferee) {
-                       ast_debug(1, "No transferee channel, giving up parking\n");
-               }
-               return -1;
-       }
-       if (!(d = ast_calloc(1, sizeof(*d)))) {
-               return -1;
-       }
+
+       /* Setup the extensions and such */
+       ast_copy_string(transferer->context, chan2->context, sizeof(transferer->context));
+       ast_copy_string(transferer->exten, chan2->exten, sizeof(transferer->exten));
+       transferer->priority = chan2->priority;
+
+       ast_do_masquerade(transferer);
 
        /* Save original request for followup */
        copy_request(&d->req, req);
        d->chan1 = transferee;  /* Transferee */
        d->chan2 = transferer;  /* Transferer */
        d->seqno = seqno;
-       d->parkexten = parkexten;
        if (ast_pthread_create_detached_background(&th, NULL, sip_park_thread, d) < 0) {
                /* Could not start thread */
                deinit_req(&d->req);
+               ast_free(d->park_exten);
+               ast_free(d->park_context);
                ast_free(d);    /* We don't need it anymore. If thread is created, d will be free'd
                                   by sip_park_thread() */
                return -1;
@@ -21579,7 +22108,7 @@ static const char *gettag(const struct sip_request *req, const char *header, cha
        if (!tagbuf)
                return NULL;
        tagbuf[0] = '\0';       /* reset the buffer */
-       thetag = get_header(req, header);
+       thetag = sip_get_header(req, header);
        thetag = strcasestr(thetag, ";tag=");
        if (thetag) {
                thetag += 5;
@@ -21622,7 +22151,7 @@ static int handle_cc_notify(struct sip_pvt *pvt, struct sip_request *req)
        /* It's open! Yay! */
        uri = get_body(req, "cc-URI", ':');
        if (ast_strlen_zero(uri)) {
-               uri = get_in_brackets((char *)get_header(req, "From"));
+               uri = get_in_brackets((char *)sip_get_header(req, "From"));
        }
 
        ast_string_field_set(monitor_instance, notify_uri, uri);
@@ -21655,7 +22184,7 @@ static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, str
        /* This is mostly a skeleton for future improvements */
        /* Mostly created to return proper answers on notifications on outbound REFER's */
        int res = 0;
-       const char *event = get_header(req, "Event");
+       const char *event = sip_get_header(req, "Event");
        char *sep;
 
        if( (sep = strchr(event, ';')) ) {      /* XXX bug here - overwriting string ? */
@@ -21683,7 +22212,7 @@ static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, str
                 Check if we have an owner of this event */
 
                /* Check the content type */
-               if (strncasecmp(get_header(req, "Content-Type"), "message/sipfrag", strlen("message/sipfrag"))) {
+               if (strncasecmp(sip_get_header(req, "Content-Type"), "message/sipfrag", strlen("message/sipfrag"))) {
                        /* We need a sipfrag */
                        transmit_response(p, "400 Bad request", req);
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
@@ -21691,7 +22220,7 @@ static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, str
                }
 
                /* Get the text of the attachment */
-               if (get_msg_text(buf, sizeof(buf), req, TRUE)) {
+               if (get_msg_text(buf, sizeof(buf), req)) {
                        ast_log(LOG_WARNING, "Unable to retrieve attachment from NOTIFY %s\n", p->callid);
                        transmit_response(p, "400 Bad request", req);
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
@@ -21778,11 +22307,11 @@ static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, str
                char *c = ast_strdupa(get_body(req, "Voice-Message", ':'));
 
                if (!p->mwi) {
-                       struct sip_peer *peer = find_peer(NULL, &p->recv, TRUE, FINDPEERS, FALSE, p->socket.type);
+                       struct sip_peer *peer = sip_find_peer(NULL, &p->recv, TRUE, FINDPEERS, FALSE, p->socket.type);
 
                        if (peer) {
                                mailbox = ast_strdupa(peer->unsolicited_mailbox);
-                               unref_peer(peer, "removing unsolicited mwi ref");
+                               sip_unref_peer(peer, "removing unsolicited mwi ref");
                        }
                } else {
                        mailbox = p->mwi->mailbox;
@@ -21850,10 +22379,10 @@ static int handle_request_options(struct sip_pvt *p, struct sip_request *req, st
                }
                if (res < 0) { /* Something failed in authentication */
                        if (res == AUTH_FAKE_AUTH) {
-                               ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", get_header(req, "From"));
+                               ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", sip_get_header(req, "From"));
                                transmit_fake_auth_response(p, SIP_OPTIONS, req, XMIT_UNRELIABLE);
                        } else {
-                               ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
+                               ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From"));
                                transmit_response(p, "403 Forbidden", req);
                        }
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
@@ -21876,7 +22405,7 @@ static int handle_request_options(struct sip_pvt *p, struct sip_request *req, st
                case SIP_GET_DEST_INVALID_URI:
                        msg = "416 Unsupported URI scheme";
                        break;
-               case SIP_GET_DEST_PICKUP_EXTEN_FOUND:
+               case SIP_GET_DEST_EXTEN_MATCHMORE:
                case SIP_GET_DEST_REFUSED:
                case SIP_GET_DEST_EXTEN_NOT_FOUND:
                        //msg = "404 Not Found";
@@ -22087,7 +22616,7 @@ static int sip_t38_abort(const void *data)
  */
 static int handle_request_update(struct sip_pvt *p, struct sip_request *req)
 {
-       if (ast_strlen_zero(get_header(req, "X-Asterisk-rpid-update"))) {
+       if (ast_strlen_zero(sip_get_header(req, "X-Asterisk-rpid-update"))) {
                transmit_response(p, "501 Method Not Implemented", req);
                return 0;
        }
@@ -22125,7 +22654,7 @@ static int handle_request_update(struct sip_pvt *p, struct sip_request *req)
  */
 static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct ast_sockaddr *addr, int *recount, const char *e, int *nounlock)
 {
-       int res = 1;
+       int res = INV_REQ_SUCCESS;
        int gotdest;
        const char *p_replaces;
        char *replace_id = NULL;
@@ -22157,14 +22686,14 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
 
        /* Find out what they support */
        if (!p->sipoptions) {
-               const char *supported = get_header(req, "Supported");
+               const char *supported = sip_get_header(req, "Supported");
                if (!ast_strlen_zero(supported)) {
                        p->sipoptions = parse_sip_options(supported, NULL, 0);
                }
        }
 
        /* Find out what they require */
-       required = get_header(req, "Require");
+       required = sip_get_header(req, "Require");
        if (!ast_strlen_zero(required)) {
                char unsupported[256] = { 0, };
                required_profile = parse_sip_options(required, unsupported, ARRAY_LEN(unsupported));
@@ -22177,7 +22706,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                        p->invitestate = INV_COMPLETED;
                        if (!p->lastinvite)
                                sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-                       res = -1;
+                       res = INV_REQ_ERROR;
                        goto request_invite_cleanup;
                }
        }
@@ -22205,7 +22734,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                        transmit_response(p, "482 Loop Detected", req);
                        p->invitestate = INV_COMPLETED;
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-                       res = 0;
+                       res = INV_REQ_FAILED;
                        goto request_invite_cleanup;
                } else {
                        /*! This is a spiral. What we need to do is to just change the outgoing INVITE
@@ -22232,7 +22761,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                         */
                        ast_string_field_set(p->owner, call_forward, peerorhost);
                        ast_queue_control(p->owner, AST_CONTROL_BUSY);
-                       res = 0;
+                       res = INV_REQ_FAILED;
                        goto request_invite_cleanup;
                }
        }
@@ -22271,12 +22800,12 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                        transmit_response_reliable(p, "491 Request Pending", req);
                        ast_debug(1, "Got INVITE on call where we already have pending INVITE, deferring that - %s\n", p->callid);
                        /* Don't destroy dialog here */
-                       res = 0;
+                       res = INV_REQ_FAILED;
                        goto request_invite_cleanup;
                }
        }
 
-       p_replaces = get_header(req, "Replaces");
+       p_replaces = sip_get_header(req, "Replaces");
        if (!ast_strlen_zero(p_replaces)) {
                /* We have a replaces header */
                char *ptr;
@@ -22289,7 +22818,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                        ast_debug(3, "INVITE w Replaces on existing call? Refusing action. [%s]\n", p->callid);
                        transmit_response_reliable(p, "400 Bad request", req);  /* The best way to not not accept the transfer */
                        /* Do not destroy existing call */
-                       res = -1;
+                       res = INV_REQ_ERROR;
                        goto request_invite_cleanup;
                }
 
@@ -22304,7 +22833,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                        append_history(p, "Xfer", "INVITE/Replace Failed. Out of memory.");
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
                        p->invitestate = INV_COMPLETED;
-                       res = -1;
+                       res = INV_REQ_ERROR;
                        goto request_invite_cleanup;
                }
 
@@ -22405,7 +22934,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                        }
                        refer_locked = 0;
                        p->invitestate = INV_COMPLETED;
-                       res = -1;
+                       res = INV_REQ_ERROR;
                        goto request_invite_cleanup;
                }
        }
@@ -22458,7 +22987,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                        /* Handle SDP here if we already have an owner */
                        if (find_sdp(req)) {
                                if (process_sdp(p, req, SDP_T38_INITIATE)) {
-                                       if (!ast_strlen_zero(get_header(req, "Content-Encoding"))) {
+                                       if (!ast_strlen_zero(sip_get_header(req, "Content-Encoding"))) {
                                                /* Asterisk does not yet support any Content-Encoding methods.  Always
                                                 * attempt to process the sdp, but return a 415 if a Content-Encoding header
                                                 * was present after processing failed.  */
@@ -22468,7 +22997,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                                        }
                                        if (!p->lastinvite)
                                                sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-                                       res = -1;
+                                       res = INV_REQ_ERROR;
                                        goto request_invite_cleanup;
                                }
                                ast_queue_control(p->owner, AST_CONTROL_SRCUPDATE);
@@ -22499,29 +23028,27 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                res = check_user_full(p, req, SIP_INVITE, e, XMIT_RELIABLE, addr, &authpeer);
                if (res == AUTH_CHALLENGE_SENT) {
                        p->invitestate = INV_COMPLETED;         /* Needs to restart in another INVITE transaction */
-                       res = 0;
                        goto request_invite_cleanup;
                }
                if (res < 0) { /* Something failed in authentication */
                        if (res == AUTH_FAKE_AUTH) {
-                               ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", get_header(req, "From"));
+                               ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", sip_get_header(req, "From"));
                                transmit_fake_auth_response(p, SIP_INVITE, req, XMIT_RELIABLE);
                        } else {
-                               ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
+                               ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From"));
                                transmit_response_reliable(p, "403 Forbidden", req);
                        }
                        p->invitestate =