Merge OEJ's print groups feature (bug #3228, with changes)
[asterisk/asterisk.git] / channels / chan_sip.c
index dde707e..2b36e1a 100755 (executable)
@@ -43,6 +43,7 @@
 #include <asterisk/causes.h>
 #include <asterisk/utils.h>
 #include <asterisk/file.h>
+#include <asterisk/astobj.h>
 #ifdef OSP_SUPPORT
 #include <asterisk/astosp.h>
 #endif
@@ -74,6 +75,7 @@
 #define SIPDUMPER
 #define DEFAULT_DEFAULT_EXPIRY  120
 #define DEFAULT_MAX_EXPIRY      3600
+#define DEFAULT_REGISTRATION_TIMEOUT   20
 
 /* guard limit must be larger than guard secs */
 /* guard min must be < 1000, and should be >= 250 */
@@ -96,10 +98,6 @@ static int default_expiry = DEFAULT_DEFAULT_EXPIRY;
 
 #define CALLERID_UNKNOWN       "Unknown"
 
-/* --- Choices for DTMF support in SIP channel */
-#define SIP_DTMF_RFC2833       (1 << 0)        /* RTP DTMF */
-#define SIP_DTMF_INBAND                (1 << 1)        /* Inband audio, only for ULAW/ALAW */
-#define SIP_DTMF_INFO          (1 << 2)        /* SIP Info messages */
 
 
 #define DEFAULT_MAXMS          2000            /* Must be faster than 2 seconds by default */
@@ -138,6 +136,8 @@ static char default_fromdomain[AST_MAX_EXTENSION] = "";
 #define DEFAULT_NOTIFYMIME "application/simple-message-summary"
 static char default_notifymime[AST_MAX_EXTENSION] = DEFAULT_NOTIFYMIME;
 
+static struct ast_flags global_flags = {0};            /* global SIP_ flags */
+
 static int srvlookup = 0;              /* SRV Lookup on or off. Default is off, RFC behavior is on */
 
 static int pedanticsipchecking = 0;    /* Extra checking ?  Default off */
@@ -150,13 +150,15 @@ static int global_rtptimeout = 0;
 
 static int global_rtpholdtimeout = 0;
 
-static int global_trustrpid = 0;       /* Trust RPID headers? Default off. */
-
-static int global_progressinband = 0;
+static int global_reg_timeout = DEFAULT_REGISTRATION_TIMEOUT;
 
-#ifdef OSP_SUPPORT
-static int global_ospauth = 0;         /* OSP = Open Settlement Protocol */
-#endif
+/* Object counters */
+static int suserobjs = 0;
+static int ruserobjs = 0;
+static int speerobjs = 0;
+static int rpeerobjs = 0;
+static int apeerobjs = 0;
+static int regobjs = 0;
 
 #define DEFAULT_MWITIME 10
 static int global_mwitime = DEFAULT_MWITIME;   /* Time between MWI checks for peers */
@@ -198,10 +200,7 @@ static int videosupport = 0;
 
 static int compactheaders = 0;                                                 /* send compact sip headers */
 
-static int global_dtmfmode = SIP_DTMF_RFC2833;         /* DTMF mode default */
 static int recordhistory = 0;                          /* Record SIP history. Off by default */
-static int global_promiscredir;                                /* Support of 302 REDIR - Default off */
-static int global_usereqphone;                         /* User=phone support, default 0 */
 
 static char global_musicclass[MAX_LANGUAGE] = "";      /* Global music on hold class */
 static char global_realm[AST_MAX_EXTENSION] = "asterisk";      /* Default realm */
@@ -251,6 +250,53 @@ struct sip_history {
        struct sip_history *next;
 };
 
+#define SIP_ALREADYGONE                (1 << 0)        /* Whether or not we've already been destroyed by our peer */
+#define SIP_NEEDDESTROY                (1 << 1)        /* if we need to be destroyed */
+#define SIP_NOVIDEO            (1 << 2)        /* Didn't get video in invite, don't offer */
+#define SIP_RINGING            (1 << 3)        /* Have sent 180 ringing */
+#define SIP_PROGRESS_SENT              (1 << 4)        /* Have sent 183 message progress */
+#define SIP_NEEDREINVITE       (1 << 5)        /* Do we need to send another reinvite? */
+#define SIP_PENDINGBYE         (1 << 6)        /* Need to send bye after we ack? */
+#define SIP_GOTREFER           (1 << 7)        /* Got a refer? */
+#define SIP_PROMISCREDIR       (1 << 8)        /* Promiscuous redirection */
+#define SIP_TRUSTRPID          (1 << 9)        /* Trust RPID headers? */
+#define SIP_USEREQPHONE                (1 << 10)       /* Add user=phone to numeric URI. Default off */
+#define SIP_REALTIME           (1 << 11)       /* Flag for realtime users */
+#define SIP_USECLIENTCODE      (1 << 12)       /* Trust X-ClientCode info message */
+#define SIP_OUTGOING           (1 << 13)       /* Is this an outgoing call? */
+#define SIP_SELFDESTRUCT       (1 << 14)       
+#define SIP_DYNAMIC            (1 << 15)       /* Is this a dynamic peer? */
+/* --- Choices for DTMF support in SIP channel */
+#define SIP_DTMF               (3 << 16)       /* three settings, uses two bits */
+#define SIP_DTMF_RFC2833       (0 << 16)       /* RTP DTMF */
+#define SIP_DTMF_INBAND                (1 << 16)       /* Inband audio, only for ULAW/ALAW */
+#define SIP_DTMF_INFO          (2 << 16)       /* SIP Info messages */
+/* NAT settings */
+#define SIP_NAT                        (3 << 18)       /* four settings, uses two bits */
+#define SIP_NAT_NEVER          (0 << 18)       /* No nat support */
+#define SIP_NAT_RFC3581                (1 << 18)
+#define SIP_NAT_ROUTE          (2 << 18)
+#define SIP_NAT_ALWAYS         (3 << 18)
+/* re-INVITE related settings */
+#define SIP_REINVITE           (3 << 20)       /* two bits used */
+#define SIP_CAN_REINVITE       (1 << 20)       /* allow peers to be reinvited to send media directly to us */
+#define SIP_REINVITE_UPDATE    (2 << 20)       /* use UPDATE (RFC3311) when reinviting this peer */
+/* "insecure" settings */
+#define SIP_INSECURE           (3 << 22)       /* three settings, uses two bits */
+#define SIP_SECURE             (0 << 22)
+#define SIP_INSECURE_NORMAL    (1 << 22)
+#define SIP_INSECURE_VERY      (2 << 22)
+/* Sending PROGRESS in-band settings */
+#define SIP_PROG_INBAND                (3 << 24)       /* three settings, uses two bits */
+#define SIP_PROG_INBAND_NEVER  (0 << 24)
+#define SIP_PROG_INBAND_NO     (1 << 24)
+#define SIP_PROG_INBAND_YES    (2 << 24)
+/* Open Settlement Protocol authentication */
+#define SIP_OSPAUTH            (3 << 26)       /* three settings, uses two bits */
+#define SIP_OSPAUTH_NO         (0 << 26)
+#define SIP_OSPAUTH_YES                (1 << 26)
+#define SIP_OSPAUTH_EXCLUSIVE  (2 << 26)
+
 /* sip_pvt: PVT structures are used for each SIP conversation, ie. a call  */
 static struct sip_pvt {
        ast_mutex_t lock;                       /* Channel private lock */
@@ -262,26 +308,17 @@ static struct sip_pvt {
        unsigned int callgroup;                 /* Call group */
        unsigned int pickupgroup;               /* Pickup group */
        int lastinvite;                         /* Last Cseq of invite */
-       int alreadygone;                        /* Whether or not we've already been destroyed by or peer */
-       int needdestroy;                        /* if we need to be destroyed */
+       int flags;                              /* SIP_ flags */        
        int capability;                         /* Special capability (codec) */
-       int novideo;                            /* Didn't get video in invite, don't offer */
        int jointcapability;                    /* Supported capability at both ends (codecs ) */
        int peercapability;                     /* Supported peer capability */
        int prefcodec;                          /* Preferred codec (outbound only) */
        int noncodeccapability;
        int callingpres;                        /* Calling presentation */
-       int outgoing;                           /* Outgoing or incoming call? */
        int authtries;                          /* Times we've tried to authenticate */
-       int insecure;                           /* Don't check source port/ip */
        int expiry;                             /* How long we take to expire */
        int branch;                             /* One random number */
-       int canreinvite;                        /* Do we support reinvite */
-       int ringing;                            /* Have sent 180 ringing */
-       int progress;                           /* Have sent 183 message progress */
-       int useclientcode;                      /* Trust X-ClientCode info message */
        int tag;                                /* Another random number */
-       int nat;                                /* Whether to try to support NAT */
        int sessionid;                          /* SDP Session ID */
        int sessionversion;                     /* SDP Session Version */
        struct sockaddr_in sa;                  /* Our peer */
@@ -312,6 +349,7 @@ static struct sip_pvt {
        char peername[256];
        char authname[256];                     /* Who we use for authentication */
        char uri[256];                          /* Original requested URI */
+       char okcontacturi[256];                 /* URI from the 200 OK on INVITE */
        char peersecret[256];                   /* Password */
        char peermd5secret[256];
        char cid_num[256];                      /* Caller*ID */
@@ -324,15 +362,11 @@ static struct sip_pvt {
        char nonce[256];                        /* Authorization nonce */
        char opaque[256];                       /* Opaque nonsense */
        char qop[80];                           /* Quality of Protection, since SIP wasn't complicated enough yet. */
-       char domain[256];                       /* Authorization nonce */
+       char domain[256];                       /* Authorization domain */
        char lastmsg[256];                      /* Last Message sent/received */
        int amaflags;                           /* AMA Flags */
        int pendinginvite;                      /* Any pending invite */
-       int needreinvite;                       /* Do we need to send another reinvite? */
-       int pendingbye;                         /* Need to send bye after we ack? */
-       int gotrefer;                           /* Got a refer? */
 #ifdef OSP_SUPPORT
-       int ospauth;                            /* Allow OSP Authentication */
        int osphandle;                          /* OSP Handle for call */
        time_t ospstart;                        /* OSP Start time */
 #endif
@@ -348,13 +382,7 @@ static struct sip_pvt {
        int subscribed;                         /* Is this call a subscription?  */
        int stateid;
        int dialogver;
-       int promiscredir;                       /* Promiscuous redirection */
-       int usereqphone;                        /* Add user=phone to numeric URI. Default off */
-       
-       int trustrpid;                          /* Trust RPID headers? */
-       int progressinband;
        
-       int dtmfmode;                           /* DTMF to use for this call */
        struct ast_dsp *vad;
        
        struct sip_peer *peerpoke;              /* If this calls is to poke a peer, which one */
@@ -385,7 +413,7 @@ struct sip_pkt {
 /* Structure for SIP user data. User's place calls to us */
 struct sip_user {
        /* Users who can access various contexts */
-       char name[80];                  /* The name in sip.conf */
+       ASTOBJ_COMPONENTS(struct sip_user);
        char secret[80];                /* Password */
        char md5secret[80];             /* Password in md5 */
        char context[80];               /* Default context for incoming calls */
@@ -398,33 +426,21 @@ struct sip_user {
        struct ast_codec_pref prefs; /* codec prefs */
        unsigned int callgroup;         /* Call group */
        unsigned int pickupgroup;       /* Pickup Group */
-       int nat;                        /* NAT setting */
+       int flags;                      /* SIP_ flags */        
        int amaflags;                   /* AMA flags for billing */
        int callingpres;                /* Calling id presentation */
-       int insecure;                   /* Insecure means don't check password */
-       int canreinvite;                /* Do we support re-invites ? */
        int capability;                 /* Codec capability */
-#ifdef OSP_SUPPORT
-       int ospauth;                    /* Allow OSP Authentication */
-#endif
-       int dtmfmode;                   /* DTMF setting */
        int inUse;
        int incominglimit;
        int outUse;
        int outgoinglimit;
-       int promiscredir;               /* Support of 302 redirect */
-       int useclientcode;              /* SNOM clientcode support */
-       int trustrpid;                  /* Trust remote party ID from this UA */
-       int progressinband;
        struct ast_ha *ha;              /* ACL setting */
-       int temponly;                   /* Flag for temporary users (realtime) */
        struct ast_variable *vars;
-       struct sip_user *next;
 };
 
 /* Structure for SIP peer data, we place calls to peers if registred  or fixed IP address (host) */
 struct sip_peer {
-       char name[80];                  /* Peer name in sip.conf */
+       ASTOBJ_COMPONENTS(struct sip_peer);
        char secret[80];                /* Password */
        char md5secret[80];             /* Password in MD5 */
        char context[80];               /* Default context for incoming calls */
@@ -443,26 +459,14 @@ struct sip_peer {
        struct ast_codec_pref prefs; /* codec prefs */
        int lastmsgssent;
        time_t  lastmsgcheck;           /* Last time we checked for MWI */
-       int dynamic;                    /* Dynamic? Yes or no. Dynamic hosts register with us  */
+       int flags;                      /* SIP_ flags */        
        int expire;                     /* Registration expiration */
        int expiry;
        int capability;                 /* Codec capability */
        int rtptimeout;
        int rtpholdtimeout;
-       int insecure;                   /* Do we want to authenticate this peer? */
-#ifdef OSP_SUPPORT
-       int ospauth;                    /* Allow OSP Authentication */
-#endif 
-       int nat;                        /* NAT support needed? */
-       int canreinvite;                /* Does the peer support re-invites? */
        unsigned int callgroup;         /* Call group */
        unsigned int pickupgroup;       /* Pickup group */
-       int promiscredir;               /* Support of 302 redirect? */
-       int dtmfmode;                   /* DTMF mode */
-       int trustrpid;                  /* Trust Remote Party ID headers? */
-       int useclientcode;              /* SNOM clientcode support */
-       int progressinband;
-       int usereqphone;                /* Add user=phone to URI. Default off */
        struct sockaddr_in addr;        /* IP address of peer */
        struct in_addr mask;
 
@@ -475,11 +479,7 @@ struct sip_peer {
        
        struct sockaddr_in defaddr;     /* Default IP address, used until registration */
        struct ast_ha *ha;              /* Access control list */
-       int delme;
-       int selfdestruct;
        int lastmsg;
-       int temponly;
-       struct sip_peer *next;
 };
 
 AST_MUTEX_DEFINE_STATIC(sip_reload_lock);
@@ -494,14 +494,10 @@ static int sip_reloading = 0;
 #define REG_STATE_TIMEOUT              5
 #define REG_STATE_NOAUTH               6
 
-/* NAT settings */
-#define SIP_NAT_NEVER          0               /* No nat support */
-#define SIP_NAT_RFC3581                (1 << 0)
-#define SIP_NAT_ROUTE          (1 << 2)
-#define SIP_NAT_ALWAYS         (SIP_NAT_ROUTE | SIP_NAT_RFC3581)
 
 /* sip_registry: Registrations with other SIP proxies */
 struct sip_registry {
+       ASTOBJ_COMPONENTS_FULL(struct sip_registry,1,1);
        int portno;                     /* Optional port override */
        char username[80];              /* Who we are registering as */
        char authuser[80];              /* Who we *authenticate* as */
@@ -519,41 +515,44 @@ struct sip_registry {
        char callid[80];                /* Global CallID for this registry */
        unsigned int ocseq;             /* Sequence number we got to for REGISTERs for this registry */
        struct sockaddr_in us;          /* Who the server thinks we are */
-       struct sip_registry *next;
+       
+                                       /* Saved headers */
+       char realm[256];                /* Authorization realm */
+       char nonce[256];                /* Authorization nonce */
+       char domain[256];               /* Authorization domain */
+       char opaque[256];               /* Opaque nonsense */
+       char qop[80];                   /* Quality of Protection. */
+       char lastmsg[256];              /* Last Message sent/received */
 };
 
 /*--- The user list: Users and friends ---*/
 static struct ast_user_list {
-       struct sip_user *users;
-       ast_mutex_t lock;
+       ASTOBJ_CONTAINER_COMPONENTS(struct sip_user);
 } userl;
 
 /*--- The peer list: Peers and Friends ---*/
 static struct ast_peer_list {
-       struct sip_peer *peers;
-       ast_mutex_t lock;
+       ASTOBJ_CONTAINER_COMPONENTS(struct sip_peer);
 } peerl;
 
 /*--- The register list: Other SIP proxys we register with and call ---*/
 static struct ast_register_list {
-       struct sip_registry *registrations;
-       ast_mutex_t lock;
+       ASTOBJ_CONTAINER_COMPONENTS(struct sip_registry);
        int recheck;
 } regl;
 
 
-#define REINVITE_INVITE                1
-#define REINVITE_UPDATE                2
-
 static int __sip_do_register(struct sip_registry *r);
 
 static int sipsock  = -1;
-static int global_nat = SIP_NAT_RFC3581;
-static int global_canreinvite = REINVITE_INVITE;
 
 
 static struct sockaddr_in bindaddr;
 static struct sockaddr_in externip;
+static char externhost[256] = "";
+static time_t externexpire = 0;
+static int externrefresh = 10;
 static struct ast_ha *localaddr;
 
 static struct ast_frame  *sip_read(struct ast_channel *ast);
@@ -594,7 +593,7 @@ static inline int sip_debug_test_pvt(struct sip_pvt *p)
 {
        if (sipdebug == 0)
                return 0;
-       return sip_debug_test_addr(((p->nat & SIP_NAT_ROUTE) ? &p->recv : &p->sa));
+       return sip_debug_test_addr(((ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE) ? &p->recv : &p->sa));
 }
 
 
@@ -603,7 +602,7 @@ static int __sip_xmit(struct sip_pvt *p, char *data, int len)
 {
        int res;
        char iabuf[INET_ADDRSTRLEN];
-       if (p->nat & SIP_NAT_ROUTE)
+       if (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)
            res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->recv, sizeof(struct sockaddr_in));
        else
            res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->sa, sizeof(struct sockaddr_in));
@@ -626,6 +625,16 @@ static int ast_sip_ouraddrfor(struct in_addr *them, struct in_addr *us)
         */
        struct sockaddr_in theirs;
        theirs.sin_addr = *them;
+       if (externexpire && (time(NULL) >= externexpire)) {
+               struct ast_hostent ahp;
+               struct hostent *hp;
+               time(&externexpire);
+               externexpire += externrefresh;
+               if ((hp = ast_gethostbyname(externhost, &ahp))) {
+                       memcpy(&externip, hp->h_addr, sizeof(externip));
+               } else
+                       ast_log(LOG_NOTICE, "Warning: Re-lookup of '%s' failed!\n", externhost);
+       }
        if (localaddr && externip.sin_addr.s_addr &&
           ast_apply_ha(localaddr, &theirs)) {
                char iabuf[INET_ADDRSTRLEN];
@@ -682,7 +691,7 @@ static int retrans_pkt(void *data)
        if (pkt->retrans < MAX_RETRANS) {
                pkt->retrans++;
                if (sip_debug_test_pvt(pkt->owner)) {
-                       if (pkt->owner->nat & SIP_NAT_ROUTE)
+                       if (ast_test_flag(pkt->owner, SIP_NAT) & SIP_NAT_ROUTE)
                                ast_verbose("Retransmitting #%d (NAT):\n%s\n to %s:%d\n", pkt->retrans, pkt->data, ast_inet_ntoa(iabuf, sizeof(iabuf), pkt->owner->recv.sin_addr), ntohs(pkt->owner->recv.sin_port));
                        else
                                ast_verbose("Retransmitting #%d (no NAT):\n%s\n to %s:%d\n", pkt->retrans, pkt->data, ast_inet_ntoa(iabuf, sizeof(iabuf), pkt->owner->sa.sin_addr), ntohs(pkt->owner->sa.sin_port));
@@ -701,12 +710,12 @@ static int retrans_pkt(void *data)
                                ast_mutex_lock(&pkt->owner->lock);
                        }
                        if (pkt->owner->owner) {
-                               pkt->owner->alreadygone=1;
+                               ast_set_flag(pkt->owner, SIP_ALREADYGONE);
                                ast_queue_hangup(pkt->owner->owner);
                                ast_mutex_unlock(&pkt->owner->owner->lock);
                        } else {
                                /* If no owner, destroy now */
-                               pkt->owner->needdestroy = 1;
+                               ast_set_flag(pkt->owner, SIP_NEEDDESTROY);      
                        }
                }
                /* In any case, go ahead and remove the packet */
@@ -892,7 +901,7 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, int reliabl
        struct sip_request tmp;
        char tmpmsg[80];
        if (sip_debug_test_pvt(p)) {
-               if (p->nat & SIP_NAT_ROUTE)
+               if (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)
                        ast_verbose("%sTransmitting (NAT):\n%s\n to %s:%d\n", reliable ? "Reliably " : "", req->data, ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr), ntohs(p->recv.sin_port));
                else
                        ast_verbose("%sTransmitting (no NAT):\n%s\n to %s:%d\n", reliable ? "Reliably " : "", req->data, ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), ntohs(p->sa.sin_port));
@@ -925,7 +934,7 @@ static int send_request(struct sip_pvt *p, struct sip_request *req, int reliable
        struct sip_request tmp;
        char tmpmsg[80];
        if (sip_debug_test_pvt(p)) {
-               if (p->nat & SIP_NAT_ROUTE)
+               if (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)
                        ast_verbose("%sTransmitting:\n%s (NAT) to %s:%d\n", reliable ? "Reliably " : "", req->data, ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr), ntohs(p->recv.sin_port));
                else
                        ast_verbose("%sTransmitting:\n%s (no NAT) to %s:%d\n", reliable ? "Reliably " : "", req->data, ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), ntohs(p->sa.sin_port));
@@ -1051,7 +1060,7 @@ static void register_peer_exten(struct sip_peer *peer, int onoff)
        }
 }
 
-static void destroy_peer(struct sip_peer *peer)
+static void sip_destroy_peer(struct sip_peer *peer)
 {
        /* Delete it, it needs to disappear */
        if (peer->call)
@@ -1062,13 +1071,19 @@ static void destroy_peer(struct sip_peer *peer)
                ast_sched_del(sched, peer->pokeexpire);
        register_peer_exten(peer, 0);
        ast_free_ha(peer->ha);
+       if (ast_test_flag(peer, SIP_SELFDESTRUCT))
+               apeerobjs--;
+       else if (ast_test_flag(peer, SIP_REALTIME))
+               rpeerobjs--;
+       else
+               speerobjs--;
        free(peer);
 }
 
 /*--- update_peer: Update peer data in database (if used) ---*/
 static void update_peer(struct sip_peer *p, int expiry)
 {
-       if (p->temponly)
+       if (ast_test_flag(p, SIP_REALTIME))
                realtime_update_peer(p->name, &p->addr, p->username, expiry);
 }
 
@@ -1093,14 +1108,14 @@ static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *
                peer = build_peer(peername, var, 1);
                if (peer) {
                        /* Add some finishing touches, addresses, etc */
-                       peer->temponly = 1;
+                       ast_set_flag(peer, SIP_REALTIME);
                        tmp = var;
                        while(tmp) {
                                if (!strcasecmp(tmp->name, "type")) {
                                        if (strcasecmp(tmp->value, "friend") &&
                                                strcasecmp(tmp->value, "peer")) {
                                                /* Whoops, we weren't supposed to exist! */
-                                               destroy_peer(peer);
+                                               sip_destroy_peer(peer);
                                                peer = NULL;
                                                break;
                                        } 
@@ -1128,35 +1143,31 @@ static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *
                }
                ast_destroy_realtime(var);
        }
+       if (peer) {
+               /* Destroy, so when our caller unrefs, it will disappear */
+               ASTOBJ_DESTROY(peer, sip_destroy_peer);
+       }
        return peer;
 }
 
+static int sip_addrcmp(char *name, struct sockaddr_in *sin)
+{
+       /* We know name is the first field, so we can cast */
+       struct sip_peer *p = (struct sip_peer *)name;
+       return  !(!inaddrcmp(&p->addr, sin) || 
+                                       (ast_test_flag(p, SIP_INSECURE) &&
+                                       (p->addr.sin_addr.s_addr == sin->sin_addr.s_addr)));
+}
+
 /*--- find_peer: Locate peer by name or ip address */
 static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin)
 {
        struct sip_peer *p = NULL;
 
-       p = peerl.peers;
-       if (peer) {
-               /* Find by peer name */
-               while(p) {
-                       if (!strcasecmp(p->name, peer)) {
-                               break;
-                       }
-                       p = p->next;
-               }       
-       }
-       else {
-               /* Find by sin */
-               while(p) {
-                       if (!inaddrcmp(&p->addr, sin) || 
-                                       (p->insecure &&
-                                       (p->addr.sin_addr.s_addr == sin->sin_addr.s_addr))) {
-                               break;
-                       }
-                       p = p->next;
-               }
-       }
+       if (peer)
+               p = ASTOBJ_CONTAINER_FIND(&peerl,peer);
+       else
+               p = ASTOBJ_CONTAINER_FIND_FULL(&peerl,sin,name,sip_addr_hashfunc,1,sip_addrcmp);
 
        if (!p) {
                p = realtime_peer(peer, sin);
@@ -1165,13 +1176,17 @@ static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin)
        return(p);
 }
 
-static void destroy_user(struct sip_user *user)
+static void sip_destroy_user(struct sip_user *user)
 {
        ast_free_ha(user->ha);
        if(user->vars) {
                ast_destroy_realtime(user->vars);
                user->vars = NULL;
        }
+       if (ast_test_flag(user, SIP_REALTIME))
+               ruserobjs--;
+       else
+               suserobjs--;
        free(user);
 }
 
@@ -1186,15 +1201,18 @@ static struct sip_user *realtime_user(const char *username)
                /* Make sure it's not a user only... */
                user = build_user(username, var);
                if (user) {
+                       /* Move counter from s to r... */
+                       suserobjs--;
+                       ruserobjs++;
                        /* Add some finishing touches, addresses, etc */
-                       user->temponly = 1;
+                       ast_set_flag(user, SIP_REALTIME);       
                        tmp = var;
                        while(tmp) {
                                if (!strcasecmp(tmp->name, "type")) {
                                        if (strcasecmp(tmp->value, "friend") &&
                                                strcasecmp(tmp->value, "user")) {
                                                /* Whoops, we weren't supposed to exist! */
-                                               destroy_user(user);
+                                               sip_destroy_user(user);
                                                user = NULL;
                                                break;
                                        } 
@@ -1204,21 +1222,19 @@ static struct sip_user *realtime_user(const char *username)
                }
                ast_destroy_realtime(var);
        }
+       if (user) {
+               /* Reference and destroy, so when our caller unrefs, we disappear */
+               ASTOBJ_REF(user);
+               ASTOBJ_DESTROY(user, sip_destroy_user);
+       }
        return user;
 }
 
 /*--- find_user: Locate user by name */
-static struct sip_user *find_user(char *name)
+static struct sip_user *find_user(const char *name)
 {
        struct sip_user *u = NULL;
-
-       u = userl.users;
-       while(u) {
-               if (!strcasecmp(u->name, name)) {
-                       break;
-               }
-               u = u->next;
-       }
+       u = ASTOBJ_CONTAINER_FIND(&userl,name);
        if (!u) {
                u = realtime_user(name);
        }
@@ -1247,20 +1263,19 @@ static int create_addr(struct sip_pvt *r, char *opeer)
                port++;
        }
        r->sa.sin_family = AF_INET;
-       ast_mutex_lock(&peerl.lock);
        p = find_peer(peer, NULL);
 
        if (p) {
                        found++;
+                       ast_copy_flags(r, p, SIP_PROMISCREDIR | SIP_USEREQPHONE | SIP_DTMF | SIP_NAT | SIP_REINVITE | SIP_INSECURE);
                        r->capability = p->capability;
-                       r->nat = p->nat;
                        if (r->rtp) {
-                               ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (r->nat & SIP_NAT_ROUTE));
-                               ast_rtp_setnat(r->rtp, (r->nat & SIP_NAT_ROUTE));
+                               ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE));
+                               ast_rtp_setnat(r->rtp, (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE));
                        }
                        if (r->vrtp) {
-                               ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (r->nat & SIP_NAT_ROUTE));
-                               ast_rtp_setnat(r->vrtp, (r->nat & SIP_NAT_ROUTE));
+                               ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE));
+                               ast_rtp_setnat(r->vrtp, (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE));
                        }
                        strncpy(r->peername, p->username, sizeof(r->peername)-1);
                        strncpy(r->authname, p->username, sizeof(r->authname)-1);
@@ -1284,20 +1299,13 @@ static int create_addr(struct sip_pvt *r, char *opeer)
                                strncpy(r->fromdomain, p->fromdomain, sizeof(r->fromdomain)-1);
                        if (!ast_strlen_zero(p->fromuser))
                                strncpy(r->fromuser, p->fromuser, sizeof(r->fromuser)-1);
-                       r->insecure = p->insecure;
-                       r->canreinvite = p->canreinvite;
                        r->maxtime = p->maxms;
                        r->callgroup = p->callgroup;
                        r->pickupgroup = p->pickupgroup;
-                       if (p->dtmfmode) {
-                               r->dtmfmode = p->dtmfmode;
-                               if (r->dtmfmode & SIP_DTMF_RFC2833)
-                                       r->noncodeccapability |= AST_RTP_DTMF;
-                               else
-                                       r->noncodeccapability &= ~AST_RTP_DTMF;
-                       }
-                       r->promiscredir = p->promiscredir;
-                       r->usereqphone = p->usereqphone;
+                       if (ast_test_flag(r, SIP_DTMF) == SIP_DTMF_RFC2833)
+                               r->noncodeccapability |= AST_RTP_DTMF;
+                       else
+                               r->noncodeccapability &= ~AST_RTP_DTMF;
                        strncpy(r->context, p->context,sizeof(r->context)-1);
                        if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) &&
                                (!p->maxms || ((p->lastms >= 0)  && (p->lastms <= p->maxms)))) {
@@ -1310,13 +1318,9 @@ static int create_addr(struct sip_pvt *r, char *opeer)
                                }
                                memcpy(&r->recv, &r->sa, sizeof(r->recv));
                        } else {
-                               if (p->temponly) {
-                                       destroy_peer(p);
-                               }
-                               p = NULL;
+                               ASTOBJ_UNREF(p,sip_destroy_peer);
                        }
        }
-       ast_mutex_unlock(&peerl.lock);
        if (!p && !found) {
                hostn = peer;
                if (port)
@@ -1348,9 +1352,7 @@ static int create_addr(struct sip_pvt *r, char *opeer)
        } else if (!p)
                return -1;
        else {
-               if (p->temponly) {
-                       destroy_peer(p);
-               }
+               ASTOBJ_UNREF(p,sip_destroy_peer);
                return 0;
        }
 }
@@ -1422,7 +1424,7 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
        }
        
        res = 0;
-       p->outgoing = 1;
+       ast_set_flag(p, SIP_OUTGOING);
 #ifdef OSP_SUPPORT
        if (!osptoken || !osphandle || (sscanf(osphandle, "%i", &p->osphandle) != 1)) {
                /* Force Disable OSP support */
@@ -1445,6 +1447,24 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
        return res;
 }
 
+static void sip_registry_destroy(struct sip_registry *reg)
+{
+       /* Really delete */
+       if (reg->call) {
+               /* Clear registry before destroying to ensure
+                  we don't get reentered trying to grab the registry lock */
+               reg->call->registry = NULL;
+               sip_destroy(reg->call);
+       }
+       if (reg->expire > -1)
+               ast_sched_del(sched, reg->expire);
+       if (reg->timeout > -1)
+               ast_sched_del(sched, reg->timeout);
+       regobjs--;
+       free(reg);
+       
+}
+
 /*---  __sip_destroy: Execute destrucion of call structure, release memory---*/
 static void __sip_destroy(struct sip_pvt *p, int lockowner)
 {
@@ -1472,16 +1492,9 @@ static void __sip_destroy(struct sip_pvt *p, int lockowner)
                p->route = NULL;
        }
        if (p->registry) {
-               /* Carefully unlink from registry */
-               struct sip_registry *reg;
-               ast_mutex_lock(&regl.lock);
-               reg = regl.registrations;
-               while(reg) {
-                       if ((reg == p->registry) && (p->registry->call == p))
-                               p->registry->call=NULL;
-                       reg = reg->next;
-               }
-               ast_mutex_unlock(&regl.lock);
+               if (p->registry->call == p)
+                       p->registry->call = NULL;
+               ASTOBJ_UNREF(p->registry,sip_registry_destroy);
        }
        /* Unlink us from the owner if we have one */
        if (p->owner) {
@@ -1537,11 +1550,9 @@ static int update_user_counter(struct sip_pvt *fup, int event)
        char name[256] = "";
        struct sip_user *u;
        strncpy(name, fup->username, sizeof(name) - 1);
-       ast_mutex_lock(&userl.lock);
        u = find_user(name);
        if (!u) {
                ast_log(LOG_DEBUG, "%s is not a local user\n", name);
-               ast_mutex_unlock(&userl.lock);
                return 0;
        }
        switch(event) {
@@ -1563,10 +1574,7 @@ static int update_user_counter(struct sip_pvt *fup, int event)
                                        if ( event == INC_OUT_USE ) {
                                                u->inUse++;
                                        }
-                                       ast_mutex_unlock(&userl.lock);
-                                       if (u->temponly) {
-                                               destroy_user(u);
-                                       }
+                                       ASTOBJ_UNREF(u,sip_destroy_user);
                                        return -1; 
                                }
                        }
@@ -1598,10 +1606,7 @@ static int update_user_counter(struct sip_pvt *fup, int event)
                default:
                        ast_log(LOG_ERROR, "update_user_counter(%s,%d) called with no event!\n",u->name,event);
        }
-       ast_mutex_unlock(&userl.lock);
-       if (u->temponly) {
-               destroy_user(u);
-       }
+       ASTOBJ_UNREF(u,sip_destroy_user);
        return 0;
 }
 
@@ -1659,7 +1664,7 @@ static int sip_hangup(struct ast_channel *ast)
 {
        struct sip_pvt *p = ast->pvt->pvt;
        int needcancel = 0;
-       int needdestroy = 0;
+       struct ast_flags locflags = {0};
        if (option_debug)
                ast_log(LOG_DEBUG, "sip_hangup(%s)\n", ast->name);
        if (!ast->pvt->pvt) {
@@ -1672,7 +1677,7 @@ static int sip_hangup(struct ast_channel *ast)
                ast_osp_terminate(p->osphandle, AST_CAUSE_NORMAL, p->ospstart, time(NULL) - p->ospstart);
        }
 #endif 
-       if ( p->outgoing ) {
+       if (ast_test_flag(p, SIP_OUTGOING)) {
                ast_log(LOG_DEBUG, "update_user_counter(%s) - decrement outUse counter\n", p->username);
                update_user_counter(p, DEC_OUT_USE);
        } else {
@@ -1700,20 +1705,20 @@ static int sip_hangup(struct ast_channel *ast)
        ast_mutex_unlock(&usecnt_lock);
        ast_update_use_count();
 
-       needdestroy = 1; 
+       ast_set_flag(&locflags, SIP_NEEDDESTROY);       
        /* Start the process if it's not already started */
-       if (!p->alreadygone && !ast_strlen_zero(p->initreq.data)) {
+       if (!ast_test_flag(p, SIP_ALREADYGONE) && !ast_strlen_zero(p->initreq.data)) {
                if (needcancel) {
-                       if (p->outgoing) {
+                       if (ast_test_flag(p, SIP_OUTGOING)) {
                                transmit_request_with_auth(p, "CANCEL", p->ocseq, 1, 0);
                                /* Actually don't destroy us yet, wait for the 487 on our original 
                                   INVITE, but do set an autodestruct just in case we never get it. */
-                               needdestroy = 0;
+                               ast_clear_flag(&locflags, SIP_NEEDDESTROY);
                                sip_scheddestroy(p, 15000);
                                if ( p->initid != -1 ) {
                                        /* channel still up - reverse dec of inUse counter
                                           only if the channel is not auto-congested */
-                                       if ( p->outgoing ) {
+                                       if (ast_test_flag(p, SIP_OUTGOING)) {
                                                update_user_counter(p, INC_OUT_USE);
                                        }
                                        else {
@@ -1734,12 +1739,12 @@ static int sip_hangup(struct ast_channel *ast)
                        } else {
                                /* Note we will need a BYE when this all settles out
                                   but we can't send one while we have "INVITE" outstanding. */
-                               p->pendingbye = 1;
-                               p->needreinvite = 0;
+                               ast_set_flag(p, SIP_PENDINGBYE);        
+                               ast_clear_flag(p, SIP_NEEDREINVITE);    
                        }
                }
        }
-       p->needdestroy = needdestroy;
+       ast_copy_flags(p, (&locflags), SIP_NEEDDESTROY);        
        ast_mutex_unlock(&p->lock);
        return 0;
 }
@@ -1793,9 +1798,9 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
                if (p) {
                        ast_mutex_lock(&p->lock);
                        if (p->rtp) {
-                               if ((ast->_state != AST_STATE_UP) && !p->progress && !p->outgoing) {
+                               if ((ast->_state != AST_STATE_UP) && !ast_test_flag(p, SIP_PROGRESS_SENT) && !ast_test_flag(p, SIP_OUTGOING)) {
                                        transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, 0);
-                                       p->progress = 1;
+                                       ast_set_flag(p, SIP_PROGRESS_SENT);     
                                }
                                res =  ast_rtp_write(p->rtp, frame);
                        }
@@ -1805,9 +1810,9 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
                if (p) {
                        ast_mutex_lock(&p->lock);
                        if (p->vrtp) {
-                               if ((ast->_state != AST_STATE_UP) && !p->progress && !p->outgoing) {
+                               if ((ast->_state != AST_STATE_UP) && !ast_test_flag(p, SIP_PROGRESS_SENT) && !ast_test_flag(p, SIP_OUTGOING)) {
                                        transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, 0);
-                                       p->progress = 1;
+                                       ast_set_flag(p, SIP_PROGRESS_SENT);     
                                }
                                res =  ast_rtp_write(p->vrtp, frame);
                        }
@@ -1844,16 +1849,22 @@ static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 static int sip_senddigit(struct ast_channel *ast, char digit)
 {
        struct sip_pvt *p = ast->pvt->pvt;
-       if (p && (p->dtmfmode & SIP_DTMF_INFO)) {
+       int res = 0;
+       ast_mutex_lock(&p->lock);
+       switch (ast_test_flag(p, SIP_DTMF)) {
+       case SIP_DTMF_INFO:
                transmit_info_with_digit(p, digit);
+               break;
+       case SIP_DTMF_RFC2833:
+               if (p->rtp)
+                       ast_rtp_senddigit(p->rtp, digit);
+               break;
+       case SIP_DTMF_INBAND:
+               res = -1;
+               break;
        }
-       if (p && p->rtp && (p->dtmfmode & SIP_DTMF_RFC2833)) {
-               ast_rtp_senddigit(p->rtp, digit);
-       }
-       /* If in-band DTMF is desired, send that */
-       if (p->dtmfmode & SIP_DTMF_INBAND)
-               return -1;
-       return 0;
+       ast_mutex_unlock(&p->lock);
+       return res;
 }
 
 
@@ -1862,7 +1873,9 @@ static int sip_transfer(struct ast_channel *ast, char *dest)
 {
        struct sip_pvt *p = ast->pvt->pvt;
        int res;
+       ast_mutex_lock(&p->lock);
        res = transmit_refer(p, dest);
+       ast_mutex_unlock(&p->lock);
        return res;
 }
 
@@ -1872,51 +1885,62 @@ static int sip_transfer(struct ast_channel *ast, char *dest)
 static int sip_indicate(struct ast_channel *ast, int condition)
 {
        struct sip_pvt *p = ast->pvt->pvt;
+       int res = 0;
+
+       ast_mutex_lock(&p->lock);
        switch(condition) {
        case AST_CONTROL_RINGING:
                if (ast->_state == AST_STATE_RING) {
-                       if (!p->progress || !p->progressinband) {
+                       if (!ast_test_flag(p, SIP_PROGRESS_SENT) ||
+                           (ast_test_flag(p, SIP_PROG_INBAND) == SIP_PROG_INBAND_NEVER)) {
                                /* Send 180 ringing if out-of-band seems reasonable */
                                transmit_response(p, "180 Ringing", &p->initreq);
-                               p->ringing = 1;
-                               if (p->progressinband < 2)
+                               ast_set_flag(p, SIP_RINGING);
+                               if (ast_test_flag(p, SIP_PROG_INBAND) != SIP_PROG_INBAND_YES)
                                        break;
                        } else {
                                /* Well, if it's not reasonable, just send in-band */
                        }
                }
-               return -1;
+               res = -1;
+               break;
        case AST_CONTROL_BUSY:
                if (ast->_state != AST_STATE_UP) {
                        transmit_response(p, "486 Busy Here", &p->initreq);
-                       p->alreadygone = 1;
+                       ast_set_flag(p, SIP_ALREADYGONE);       
                        ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
                        break;
                }
-               return -1;
+               res = -1;
+               break;
        case AST_CONTROL_CONGESTION:
                if (ast->_state != AST_STATE_UP) {
                        transmit_response(p, "503 Service Unavailable", &p->initreq);
-                       p->alreadygone = 1;
+                       ast_set_flag(p, SIP_ALREADYGONE);       
                        ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
                        break;
                }
-               return -1;
+               res = -1;
+               break;
        case AST_CONTROL_PROGRESS:
        case AST_CONTROL_PROCEEDING:
-               if ((ast->_state != AST_STATE_UP) && !p->progress && !p->outgoing) {
+               if ((ast->_state != AST_STATE_UP) && !ast_test_flag(p, SIP_PROGRESS_SENT) && !ast_test_flag(p, SIP_OUTGOING)) {
                        transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, 0);
-                       p->progress = 1;
+                       ast_set_flag(p, SIP_PROGRESS_SENT);     
                        break;
                }
-               return -1;
+               res = -1;
+               break;
        case -1:
-               return -1;
+               res = -1;
+               break;
        default:
                ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", condition);
-               return -1;
+               res = -1;
+               break;
        }
-       return 0;
+       ast_mutex_unlock(&p->lock);
+       return res;
 }
 
 
@@ -1957,7 +1981,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
                                snprintf(tmp->name, sizeof(tmp->name), "SIP/%s-%08x", i->fromdomain, (int)(long)(i));
                        }
                tmp->type = channeltype;
-                if (i->dtmfmode & SIP_DTMF_INBAND) {
+                if (ast_test_flag(i, SIP_DTMF) ==  SIP_DTMF_INBAND) {
                     i->vad = ast_dsp_new();
                     ast_dsp_set_features(i->vad, DSP_FEATURE_DTMF_DETECT);
                    if (relaxdtmf)
@@ -2017,6 +2041,9 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
                if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s"))
                        tmp->cid.cid_dnid = strdup(i->exten);
                tmp->priority = 1;
+               if (!ast_strlen_zero(i->uri)) {
+                       pbx_builtin_setvar_helper(tmp, "SIPURI", i->uri);
+               }
                if (!ast_strlen_zero(i->domain)) {
                        pbx_builtin_setvar_helper(tmp, "SIPDOMAIN", i->domain);
                }
@@ -2180,7 +2207,7 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
                f = &null_frame;
        }
        /* Don't send RFC2833 if we're not supposed to */
-       if (f && (f->frametype == AST_FRAME_DTMF) && !(p->dtmfmode & SIP_DTMF_RFC2833))
+       if (f && (f->frametype == AST_FRAME_DTMF) && (ast_test_flag(p, SIP_DTMF) != SIP_DTMF_RFC2833))
                return &null_frame;
        if (p->owner) {
                /* We already hold the channel lock */
@@ -2191,7 +2218,7 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
                                ast_set_read_format(p->owner, p->owner->readformat);
                                ast_set_write_format(p->owner, p->owner->writeformat);
                        }
-            if ((p->dtmfmode & SIP_DTMF_INBAND) && p->vad) {
+            if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
                    f = ast_dsp_process(p->owner,p->vad,f);
                   if (f && (f->frametype == AST_FRAME_DTMF)) 
                        ast_log(LOG_DEBUG, "Detected DTMF '%c'\n", f->subclass);
@@ -2283,16 +2310,16 @@ static struct sip_pvt *sip_alloc(char *callid, struct sockaddr_in *sin, int useg
                ast_rtp_settos(p->vrtp, tos);
        if (useglobal_nat && sin) {
                /* Setup NAT structure according to global settings if we have an address */
-               p->nat = global_nat;
+               ast_copy_flags(p, &global_flags, SIP_NAT);
                memcpy(&p->recv, sin, sizeof(p->recv));
-               ast_rtp_setnat(p->rtp, (p->nat & SIP_NAT_ROUTE));
+               ast_rtp_setnat(p->rtp, (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
                if (p->vrtp)
-                       ast_rtp_setnat(p->vrtp, (p->nat & SIP_NAT_ROUTE));
+                       ast_rtp_setnat(p->vrtp, (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
        }
 
        strncpy(p->fromdomain, default_fromdomain, sizeof(p->fromdomain) - 1);
        /* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
-       if (p->nat != SIP_NAT_NEVER)
+       if (ast_test_flag(p, SIP_NAT) != SIP_NAT_NEVER)
                snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
        else
                snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
@@ -2300,21 +2327,13 @@ static struct sip_pvt *sip_alloc(char *callid, struct sockaddr_in *sin, int useg
                build_callid(p->callid, sizeof(p->callid), p->ourip, p->fromdomain);
        else
                strncpy(p->callid, callid, sizeof(p->callid) - 1);
-       /* Assume reinvite OK and via INVITE */
-       p->canreinvite = global_canreinvite;
+       ast_copy_flags(p, (&global_flags), SIP_PROMISCREDIR | SIP_TRUSTRPID | SIP_DTMF | SIP_REINVITE | SIP_PROG_INBAND | SIP_OSPAUTH);
        /* Assign default music on hold class */
        strncpy(p->musicclass, global_musicclass, sizeof(p->musicclass) - 1);
-       p->dtmfmode = global_dtmfmode;
-       p->promiscredir = global_promiscredir;
-       p->trustrpid = global_trustrpid;
-       p->progressinband = global_progressinband;
-#ifdef OSP_SUPPORT
-       p->ospauth = global_ospauth;
-#endif
        p->rtptimeout = global_rtptimeout;
        p->rtpholdtimeout = global_rtpholdtimeout;
        p->capability = global_capability;
-       if (p->dtmfmode & SIP_DTMF_RFC2833)
+       if (ast_test_flag(p, SIP_DTMF) == SIP_DTMF_RFC2833)
                p->noncodeccapability |= AST_RTP_DTMF;
        strncpy(p->context, default_context, sizeof(p->context) - 1);
        /* Add to list */
@@ -2439,6 +2458,8 @@ static int sip_register(char *value, int lineno)
        reg = malloc(sizeof(struct sip_registry));
        if (reg) {
                memset(reg, 0, sizeof(struct sip_registry));
+               regobjs++;
+               ASTOBJ_INIT(reg);
                strncpy(reg->contact, contact, sizeof(reg->contact) - 1);
                if (username)
                        strncpy(reg->username, username, sizeof(reg->username)-1);
@@ -2454,10 +2475,8 @@ static int sip_register(char *value, int lineno)
                reg->portno = porta ? atoi(porta) : 0;
                reg->callid_valid = 0;
                reg->ocseq = 101;
-               ast_mutex_lock(&regl.lock);
-               reg->next = regl.registrations;
-               regl.registrations = reg;
-               ast_mutex_unlock(&regl.lock);
+               ASTOBJ_CONTAINER_LINK(&regl, reg);
+               ASTOBJ_UNREF(reg,sip_registry_destroy);
        } else {
                ast_log(LOG_ERROR, "Out of memory\n");
                return -1;
@@ -2626,7 +2645,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
                return -1;
        }
        sdpLineNum_iterator_init(&iterator);
-       p->novideo = 1;
+       ast_set_flag(p, SIP_NOVIDEO);   
        while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') {
                if ((sscanf(m, "audio %d RTP/AVP %n", &x, &len) == 1) ||
                    (sscanf(m, "audio %d/%d RTP/AVP %n", &x, &y, &len) == 2)) {
@@ -2651,7 +2670,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
                        ast_rtp_pt_clear(p->vrtp);  /* Must be cleared in case no m=video line exists */
 
                if (p->vrtp && (sscanf(m, "video %d RTP/AVP %n", &x, &len) == 1)) {
-                       p->novideo = 0;
+                       ast_clear_flag(p, SIP_NOVIDEO); 
                        vportno = x;
                        /* Scan through the RTP payload types specified in a "m=" line: */
                        codecs = m + len;
@@ -2762,6 +2781,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
                                ast_moh_stop(ast_bridged_channel(p->owner));
                        } else {
                                ast_moh_start(ast_bridged_channel(p->owner), NULL);
+                               if (sendonly)
+                                       ast_rtp_stop(p->rtp);
                        }
                }
        }
@@ -2903,7 +2924,7 @@ static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, struct s
                                else
                                        *oh = '\0';
                        }
-                       if (!copied && (p->nat == SIP_NAT_ALWAYS)) {
+                       if (!copied && (ast_test_flag(p, SIP_NAT) == SIP_NAT_ALWAYS)) {
                                /* Whoo hoo!  Now we can indicate port address translation too!  Just
                                   another RFC (RFC3581). I'll leave the original comments in for
                                   posterity.  */
@@ -3049,6 +3070,7 @@ static int init_req(struct sip_request *req, char *resp, char *recip)
 }
 
 
+/*--- respprep: Prepare SIP response packet ---*/
 static int respprep(struct sip_request *resp, struct sip_pvt *p, char *msg, struct sip_request *req)
 {
        char newto[256] = "", *ot;
@@ -3056,15 +3078,16 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, char *msg, stru
        memset(resp, 0, sizeof(*resp));
        init_resp(resp, msg, req);
        copy_via_headers(p, resp, req, "Via");
-       if (msg[0] == '2') copy_all_header(resp, req, "Record-Route");
+       if (msg[0] == '2')
+               copy_all_header(resp, req, "Record-Route");
        copy_header(resp, req, "From");
        ot = get_header(req, "To");
        if (!strstr(ot, "tag=")) {
                /* Add the proper tag if we don't have it already.  If they have specified
                   their tag, use it.  Otherwise, use our own tag */
-               if (!ast_strlen_zero(p->theirtag) && p->outgoing)
+               if (!ast_strlen_zero(p->theirtag) && ast_test_flag(p, SIP_OUTGOING))
                        snprintf(newto, sizeof(newto), "%s;tag=%s", ot, p->theirtag);
-               else if (p->tag && !p->outgoing)
+               else if (p->tag && !ast_test_flag(p, SIP_OUTGOING))
                        snprintf(newto, sizeof(newto), "%s;tag=as%08x", ot, p->tag);
                else {
                        strncpy(newto, ot, sizeof(newto) - 1);
@@ -3092,6 +3115,7 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, char *msg, stru
        return 0;
 }
 
+/*--- reqprep: Initialize a SIP request packet ---*/
 static int reqprep(struct sip_request *req, struct sip_pvt *p, char *msg, int seqno, int newbranch)
 {
        struct sip_request *orig = &p->initreq;
@@ -3113,18 +3137,27 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, char *msg, int se
        
        if (newbranch) {
                p->branch ^= rand();
-               if (p->nat & SIP_NAT_RFC3581)
+               if (ast_test_flag(p, SIP_NAT) & SIP_NAT_RFC3581)
                        snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
                else /* Some implementations (e.g. Uniden UIP200) can't handle rport being in the message!! */
                        snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
        }
-       if (!strcasecmp(msg, "CANCEL") || !strcasecmp(msg, "ACK")) {
-               /* MUST use original URI */
-               c = p->initreq.rlPart2;
+       if (!strcasecmp(msg, "CANCEL")) {
+               c = p->initreq.rlPart2; /* Use original URI */
+       } else if (!strcasecmp(msg, "ACK")) {
+               /* Use URI from Contact: in 200 OK (if INVITE) 
+               (we only have the contacturi on INVITEs) */
+               if (!ast_strlen_zero(p->okcontacturi))
+                       c = p->okcontacturi;
+               else
+                       c = p->initreq.rlPart2;
+       } else if (!ast_strlen_zero(p->okcontacturi)) {
+               c = p->okcontacturi; /* Use for BYE or REINVITE */
        } else if (!ast_strlen_zero(p->uri)) {
                c = p->uri;
        } else {
-               if (p->outgoing)
+               /* We have no URI, use To: or From:  header as URI (depending on direction) */
+               if (ast_test_flag(p, SIP_OUTGOING))
                        strncpy(stripped, get_header(orig, "To"), sizeof(stripped) - 1);
                else
                        strncpy(stripped, get_header(orig, "From"), sizeof(stripped) - 1);
@@ -3159,16 +3192,16 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, char *msg, int se
        if (!strstr(ot, "tag=") && strcasecmp(msg, "CANCEL")) {
                /* Add the proper tag if we don't have it already.  If they have specified
                   their tag, use it.  Otherwise, use our own tag */
-               if (p->outgoing && !ast_strlen_zero(p->theirtag))
+               if (ast_test_flag(p, SIP_OUTGOING) && !ast_strlen_zero(p->theirtag))
                        snprintf(newto, sizeof(newto), "%s;tag=%s", ot, p->theirtag);
-               else if (!p->outgoing)
+               else if (!ast_test_flag(p, SIP_OUTGOING))
                        snprintf(newto, sizeof(newto), "%s;tag=as%08x", ot, p->tag);
                else
                        snprintf(newto, sizeof(newto), "%s", ot);
                ot = newto;
        }
 
-       if (p->outgoing) {
+       if (ast_test_flag(p, SIP_OUTGOING)) {
                add_header(req, "From", of);
                add_header(req, "To", ot);
        } else {
@@ -3442,7 +3475,7 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
                                snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(0, x));
                                strncat(a, costr, sizeof(a) - strlen(a) - 1);
                                if (x == AST_RTP_DTMF) {
-                                 /* Indicate we support DTMF...  Not sure about 16, but MSN supports it so dang it, we will too... */
+                                 /* Indicate we support DTMF and FLASH... */
                                  snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n",
                                           codec);
                                  strncat(a, costr, sizeof(a) - strlen(a) - 1);
@@ -3458,7 +3491,7 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
        if ((sizeof(m) <= strlen(m) - 2) || (sizeof(m2) <= strlen(m2) - 2) || (sizeof(a) == strlen(a)) || (sizeof(a2) == strlen(a2)))
                ast_log(LOG_WARNING, "SIP SDP may be truncated due to undersized buffer!!\n");
        len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a);
-       if ((p->vrtp) && (!p->novideo) && (capability & VIDEO_CODEC_MASK)) /* only if video response is appropriate */
+       if ((p->vrtp) && (!ast_test_flag(p, SIP_NOVIDEO)) && (capability & VIDEO_CODEC_MASK)) /* only if video response is appropriate */
                len += strlen(m2) + strlen(a2);
        snprintf(costr, sizeof(costr), "%d", len);
        add_header(resp, "Content-Type", "application/sdp");
@@ -3470,7 +3503,7 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
        add_line(resp, t);
        add_line(resp, m);
        add_line(resp, a);
-       if ((p->vrtp) && (!p->novideo) && (capability & VIDEO_CODEC_MASK)) { /* only if video response is appropriate */
+       if ((p->vrtp) && (!ast_test_flag(p, SIP_NOVIDEO)) && (capability & VIDEO_CODEC_MASK)) { /* only if video response is appropriate */
                add_line(resp, m2);
                add_line(resp, a2);
        }
@@ -3494,7 +3527,7 @@ static void copy_request(struct sip_request *dst,struct sip_request *src)
                dst->line[x] += offset;
 }
 
-/*--- transmit_response_with_sdp: Used for 200 OK ---*/
+/*--- transmit_response_with_sdp: Used for 200 OK and 183 early media ---*/
 static int transmit_response_with_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans)
 {
        struct sip_request resp;
@@ -3555,7 +3588,7 @@ static int determine_firstline_parts( struct sip_request *req ) {
       e++;
       if( !*e ) { return -1; }  
     }
-    req->rlPart2= e;
+    req->rlPart2= e;   /* URI */
     if( ( e= strrchr( req->rlPart2, 'S' ) ) == NULL ) {
       return -1;
     }
@@ -3569,13 +3602,16 @@ static int determine_firstline_parts( struct sip_request *req ) {
   return 1;
 }
 
-/* transmit_reinvite_with_sdp: Transmit reinvite with SDP :-) ---*/
-/*   A re-invite is basically a new INVITE with the same CALL-ID and TAG as the
-     INVITE that opened the SIP dialogue */
+/*--- transmit_reinvite_with_sdp: Transmit reinvite with SDP :-) ---*/
+/*     A re-invite is basically a new INVITE with the same CALL-ID and TAG as the
+       INVITE that opened the SIP dialogue 
+       We reinvite so that the audio stream (RTP) go directly between
+       the SIP UAs. SIP Signalling stays with * in the path.
+*/
 static int transmit_reinvite_with_sdp(struct sip_pvt *p)
 {
        struct sip_request req;
-       if (p->canreinvite == REINVITE_UPDATE)
+       if (ast_test_flag(p, SIP_REINVITE_UPDATE))
                reqprep(&req, p, "UPDATE", 0, 1);
        else 
                reqprep(&req, p, "INVITE", 0, 1);
@@ -3590,7 +3626,7 @@ static int transmit_reinvite_with_sdp(struct sip_pvt *p)
                ast_verbose("%d headers, %d lines\n", p->initreq.headers, p->initreq.lines);
        determine_firstline_parts(&p->initreq);
        p->lastinvite = p->ocseq;
-       p->outgoing = 1;
+       ast_set_flag(p, SIP_OUTGOING);
        return send_request(p, &req, 1, p->ocseq);
 }
 
@@ -3638,7 +3674,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, char *cmd, c
        int x;
        char urioptions[256]="";
 
-       if (p->usereqphone) {
+       if (ast_test_flag(p, SIP_USEREQPHONE)) {
                char onlydigits = 1;
                x=0;
 
@@ -3732,7 +3768,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, char *cmd, c
 }
 
         
-/*--- transmit_invite: Build REFER/INVITE/OPTIONS message and trasmit it ---*/
+/*--- transmit_invite: Build REFER/INVITE/OPTIONS message and transmit it ---*/
 static int transmit_invite(struct sip_pvt *p, char *cmd, int sdp, char *auth, char *authheader, char *vxml_url, char *distinctive_ring, char *osptoken, int addsipheaders, int init)
 {
        struct sip_request req;
@@ -3741,7 +3777,7 @@ static int transmit_invite(struct sip_pvt *p, char *cmd, int sdp, char *auth, ch
        if (init) {
                /* Bump branch even on initial requests */
                p->branch ^= rand();
-               if (p->nat & SIP_NAT_RFC3581)
+               if (ast_test_flag(p, SIP_NAT) & SIP_NAT_RFC3581)
                        snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
                else /* Work around buggy UNIDEN UIP200 firmware */
                        snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
@@ -4032,11 +4068,20 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
 static int sip_reregister(void *data) 
 {
        /* if we are here, we know that we need to reregister. */
-       struct sip_registry *r=(struct sip_registry *)data;
-       ast_mutex_lock(&regl.lock);
+       struct sip_registry *r= ASTOBJ_REF((struct sip_registry *) data);
+
+       /* if we couldn't get a reference to the registry object, punt */
+       if (!r)
+               return 0;
+
+       /* Since registry's are only added/removed by the the monitor thread, this
+          may be overkill to reference/dereference at all here */
+       if (sipdebug)
+               ast_log(LOG_NOTICE, "   -- Re-registration for  %s@%s\n", r->username, r->hostname);
+
        r->expire = -1;
        __sip_do_register(r);
-       ast_mutex_unlock(&regl.lock);
+       ASTOBJ_UNREF(r,sip_registry_destroy);
        return 0;
 }
 
@@ -4051,31 +4096,37 @@ static int __sip_do_register(struct sip_registry *r)
 /*--- sip_reg_timeout: Registration timeout, register again */
 static int sip_reg_timeout(void *data)
 {
+
        /* if we are here, our registration timed out, so we'll just do it over */
-       struct sip_registry *r=data;
+       struct sip_registry *r = ASTOBJ_REF((struct sip_registry *) data);
        struct sip_pvt *p;
        int res;
-       ast_mutex_lock(&regl.lock);
-       ast_log(LOG_NOTICE, "Registration for '%s@%s' timed out, trying again\n", r->username, r->hostname); 
+
+       /* if we couldn't get a reference to the registry object, punt */
+       if (!r)
+               return 0;
+
+       ast_log(LOG_NOTICE, "   -- Registration for '%s@%s' timed out, trying again\n", r->username, r->hostname); 
        if (r->call) {
                /* Unlink us, destroy old call.  Locking is not relevent here because all this happens
                   in the single SIP manager thread. */
                p = r->call;
-               p->registry = NULL;
+               if (p->registry)
+                       ASTOBJ_UNREF(p->registry, sip_registry_destroy);
                r->call = NULL;
-               p->needdestroy = 1;
+               ast_set_flag(p, SIP_NEEDDESTROY);       
                /* Pretend to ACK anything just in case */
                __sip_pretend_ack(p);
        }
        r->regstate=REG_STATE_UNREGISTERED;
-       manager_event(EVENT_FLAG_SYSTEM, "Registry", "Channel: SIP\r\nDomain: %s\r\nStatus: %s\r\n", r->hostname, regstate2str(r->regstate));
+       manager_event(EVENT_FLAG_SYSTEM, "Registry", "Channel: SIP\r\nUser: %s\r\nDomain: %s\r\nStatus: %s\r\n", r->username, r->hostname, regstate2str(r->regstate));
        r->timeout = -1;
        res=transmit_register(r, "REGISTER", NULL, NULL);
-       ast_mutex_unlock(&regl.lock);
+       ASTOBJ_UNREF(r,sip_registry_destroy);
        return 0;
 }
 
-/*--- transmit_register: Transmit register to SIP proxy ---*/
+/*--- transmit_register: Transmit register to SIP proxy or UA ---*/
 static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char *authheader)
 {
        struct sip_request req;
@@ -4103,31 +4154,37 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
                        p->theirtag[0]='\0';    /* forget their old tag, so we don't match tags when getting response */
                }
        } else {
+               /* Build callid for registration if we haven't registred before */
                if (!r->callid_valid) {
                        build_callid(r->callid, sizeof(r->callid), __ourip, default_fromdomain);
                        r->callid_valid = 1;
                }
+               /* Allocate SIP packet for registration */
                p=sip_alloc( r->callid, NULL, 0);
                if (!p) {
                        ast_log(LOG_WARNING, "Unable to allocate registration call\n");
                        return 0;
                }
+               /* Find address to hostname */
                if (create_addr(p,r->hostname)) {
                        sip_destroy(p);
                        return 0;
                }
+
                /* Copy back Call-ID in case create_addr changed it */
                strncpy(r->callid, p->callid, sizeof(r->callid) - 1);
                if (r->portno)
                        p->sa.sin_port = htons(r->portno);
-               p->outgoing = 1;
-               r->call=p;
-               p->registry=r;
-               if (!ast_strlen_zero(r->secret))
+               ast_set_flag(p, SIP_OUTGOING);  /* Registration is outgoing call */
+               r->call=p;                      /* Save pointer to SIP packet */
+               p->registry=ASTOBJ_REF(r);      /* Add pointer to registry in packet */
+               if (!ast_strlen_zero(r->secret))        /* Secret (password) */
                        strncpy(p->peersecret, r->secret, sizeof(p->peersecret)-1);
                if (!ast_strlen_zero(r->md5secret))
                        strncpy(p->peermd5secret, r->md5secret, sizeof(p->peermd5secret)-1);
-               if (!ast_strlen_zero(r->authuser)) {
+               /* User name in this realm  
+               - if authuser is set, use that, otherwise use username */
+               if (!ast_strlen_zero(r->authuser)) {    
                        strncpy(p->peername, r->authuser, sizeof(p->peername)-1);
                        strncpy(p->authname, r->authuser, sizeof(p->authname)-1);
                } else {
@@ -4139,6 +4196,7 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
                }
                if (!ast_strlen_zero(r->username))
                        strncpy(p->username, r->username, sizeof(p->username)-1);
+               /* Save extension in packet */
                strncpy(p->exten, r->contact, sizeof(p->exten) - 1);
 
                /*
@@ -4154,11 +4212,11 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
        /* set up a timeout */
        if (auth==NULL)  {
                if (r->timeout > -1) {
-                       ast_log(LOG_WARNING, "Still have a timeout, %d\n", r->timeout);
+                       ast_log(LOG_WARNING, "Still have a registration timeout, %d\n", r->timeout);
                        ast_sched_del(sched, r->timeout);
                }
-               r->timeout = ast_sched_add(sched, 20*1000, sip_reg_timeout, r);
-               ast_log(LOG_DEBUG, "Scheduled a timeout # %d\n", r->timeout);
+               r->timeout = ast_sched_add(sched, global_reg_timeout*1000, sip_reg_timeout, r);
+               ast_log(LOG_DEBUG, "Scheduled a registration timeout # %d\n", r->timeout);
        }
 
        if (strchr(r->username, '@')) {
@@ -4183,11 +4241,12 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
        memset(&req, 0, sizeof(req));
        init_req(&req, cmd, addr);
 
+       /* Add to CSEQ */
        snprintf(tmp, sizeof(tmp), "%u %s", ++r->ocseq, cmd);
        p->ocseq = r->ocseq;
 
        /* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
-       if (p->nat & SIP_NAT_RFC3581)
+       if (ast_test_flag(p, SIP_NAT) & SIP_NAT_RFC3581)
                snprintf(via, sizeof(via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
        else /* Work around buggy UNIDEN UIP200 firmware */
                snprintf(via, sizeof(via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
@@ -4197,8 +4256,27 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
        add_header(&req, "Call-ID", p->callid);
        add_header(&req, "CSeq", tmp);
        add_header(&req, "User-Agent", default_useragent);
-       if (auth) 
+
+       
+       if (auth)       /* Add auth header */
                add_header(&req, authheader, auth);
+       else if ( !ast_strlen_zero(r->nonce) ) {
+               char digest[1024];
+
+               /* We have auth data to reuse, build a digest header! */
+               if (sipdebug)
+                       ast_log(LOG_DEBUG, "   >>> Re-using Auth data for %s@%s\n", r->username, r->hostname);
+               strncpy(p->realm, r->realm, sizeof(p->realm)-1);
+               strncpy(p->nonce, r->nonce, sizeof(p->nonce)-1);
+               strncpy(p->domain, r->domain, sizeof(p->domain)-1);
+               strncpy(p->opaque, r->opaque, sizeof(p->opaque)-1);
+               strncpy(p->qop, r->qop, sizeof(p->qop)-1);
+
+               memset(digest,0,sizeof(digest));
+               build_reply_digest(p, "REGISTER", digest, sizeof(digest));
+               add_header(&req, "Authorization", digest);
+       
+       }
 
        snprintf(tmp, sizeof(tmp), "%d", default_expiry);
        add_header(&req, "Expires", tmp);
@@ -4231,7 +4309,7 @@ static int transmit_refer(struct sip_pvt *p, char *dest)
        char from[256];
        char *of, *c;
        char referto[256];
-       if (p->outgoing) 
+       if (ast_test_flag(p, SIP_OUTGOING)) 
                of = get_header(&p->initreq, "To");
        else
                of = get_header(&p->initreq, "From");
@@ -4293,6 +4371,7 @@ static int transmit_request_with_auth(struct sip_pvt *p, char *msg, int seqno, i
        if (*p->realm)
        {
                char digest[1024];
+
                memset(digest,0,sizeof(digest));
                build_reply_digest(p, msg, digest, sizeof(digest));
                add_header(&resp, "Proxy-Authorization", digest);
@@ -4313,8 +4392,8 @@ static int expire_register(void *data)
        register_peer_exten(p, 0);
        p->expire = -1;
        ast_device_state_changed("SIP/%s", p->name);
-       if (p->selfdestruct) {
-               p->delme = 1;
+       if (ast_test_flag(p, SIP_SELFDESTRUCT)) {
+               ASTOBJ_MARK(p); 
                prune_peers();
        }
        return 0;
@@ -4387,6 +4466,85 @@ static void reg_source_db(struct sip_peer *p)
        }
 }
 
+/*--- parse_ok_contact: Parse contact header for 200 OK on INVITE ---*/
+static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req)
+{
+       char contact[250]= ""; 
+       char *c, *n, *pt;
+       int port;
+       struct hostent *hp;
+       struct ast_hostent ahp;
+       struct sockaddr_in oldsin;
+
+       /* Look for brackets */
+       strncpy(contact, get_header(req, "Contact"), sizeof(contact) - 1);
+       c = contact;
+       
+       if ((n=strchr(c, '<'))) {
+               c = n + 1;
+               n = strchr(c, '>');
+               /* Lose the part after the > */
+               if (n) 
+                       *n = '\0';
+       }
+
+
+       /* Save full contact to call pvt for later bye or re-invite */
+       strncpy(pvt->fullcontact, c, sizeof(pvt->fullcontact) - 1);     
+
+       /* Save URI for later ACKs, BYE or RE-invites */
+       strncpy(pvt->okcontacturi, c, sizeof(pvt->okcontacturi) - 1);
+       
+       /* Make sure it's a SIP URL */
+       if (strncasecmp(c, "sip:", 4)) {
+               ast_log(LOG_NOTICE, "'%s' is not a valid SIP contact (missing sip:) trying to use anyway\n", c);
+       } else
+               c += 4;
+
+       /* Ditch arguments */
+       n = strchr(c, ';');
+       if (n) 
+               *n = '\0';
+
+       /* Grab host */
+       n = strchr(c, '@');
+       if (!n) {
+               n = c;
+               c = NULL;
+       } else {
+               *n = '\0';
+               n++;
+       }
+       pt = strchr(n, ':');
+       if (pt) {
+               *pt = '\0';
+               pt++;
+               port = atoi(pt);
+       } else
+               port = DEFAULT_SIP_PORT;
+
+       memcpy(&oldsin, &pvt->sa, sizeof(oldsin));
+
+       if (!(ast_test_flag(pvt, SIP_NAT) & SIP_NAT_ROUTE)) {
+               /* XXX This could block for a long time XXX */
+               /* We should only do this if it's a name, not an IP */
+               hp = ast_gethostbyname(n, &ahp);
+               if (!hp)  {
+                       ast_log(LOG_WARNING, "Invalid host '%s'\n", n);
+                       return -1;
+               }
+               pvt->sa.sin_family = AF_INET;
+               memcpy(&pvt->sa.sin_addr, hp->h_addr, sizeof(pvt->sa.sin_addr));
+               pvt->sa.sin_port = htons(port);
+       } else {
+               /* Don't trust the contact field.  Just use what they came to us
+                  with. */
+               memcpy(&pvt->sa, &pvt->recv, sizeof(pvt->sa));
+       }
+       return 0;
+}
+
+
 /*--- parse_contact: Parse contact header and save registration ---*/
 static int parse_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_request *req)
 {
@@ -4468,7 +4626,7 @@ static int parse_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_req
        } else
                port = DEFAULT_SIP_PORT;
        memcpy(&oldsin, &p->addr, sizeof(oldsin));
-       if (!(p->nat & SIP_NAT_ROUTE)) {
+       if (!(ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)) {
                /* XXX This could block for a long time XXX */
                hp = ast_gethostbyname(n, &ahp);
                if (!hp)  {
@@ -4491,7 +4649,7 @@ static int parse_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_req
                ast_sched_del(sched, p->expire);
        if ((expiry < 1) || (expiry > max_expiry))
                expiry = max_expiry;
-       if (!p->temponly)
+       if (!ast_test_flag(p, SIP_REALTIME))
                p->expire = ast_sched_add(sched, (expiry + 10) * 1000, expire_register, p);
        else
                p->expire = -1;
@@ -4670,7 +4828,7 @@ static int check_auth(struct sip_pvt *p, struct sip_request *req, char *randdata
        /* Always OK if no secret */
        if (ast_strlen_zero(secret) && ast_strlen_zero(md5secret)
 #ifdef OSP_SUPPORT
-               && !p->ospauth 
+           && ast_test_flag(p, SIP_OSPAUTH)
 #endif
                )
                return 0;
@@ -4683,7 +4841,7 @@ static int check_auth(struct sip_pvt *p, struct sip_request *req, char *randdata
                respheader = "WWW-Authenticate";
        }
 #ifdef OSP_SUPPORT
-       else if (p->ospauth) {
+       else if (ast_test_flag(p, SIP_OSPAUTH)) {
                ast_log(LOG_DEBUG, "Checking OSP Authentication!\n");
                osptoken = get_header(req, "P-OSP-Auth-Token");
                /* Check for token existence */
@@ -4697,7 +4855,8 @@ static int check_auth(struct sip_pvt *p, struct sip_request *req, char *randdata
                pbx_builtin_setvar_helper(p->owner, "OSPHANDLE", tmp);
 
                /* If ospauth is 'exclusive' don't require further authentication */
-               if ((p->ospauth > 1) || (ast_strlen_zero(secret) && ast_strlen_zero(md5secret)))
+               if ((ast_test_flag(p, SIP_OSPAUTH) == SIP_OSPAUTH_EXCLUSIVE) ||
+                   (ast_strlen_zero(secret) && ast_strlen_zero(md5secret)))
                        return 0;
        }
 #endif 
@@ -4848,21 +5007,16 @@ static int register_verify(struct sip_pvt *p, struct sockaddr_in *sin, struct si
                *c = '\0';
        strncpy(p->exten, name, sizeof(p->exten) - 1);
        build_contact(p);
-       ast_mutex_lock(&peerl.lock);
        peer = find_peer(name, NULL);
        if (!(peer && ast_apply_ha(peer->ha, sin))) {
-               if (peer && peer->temponly) {
-                       destroy_peer(peer);
-               }
-               peer = NULL;
+               if (peer)
+                       ASTOBJ_UNREF(peer,sip_destroy_peer);
        }
-       ast_mutex_unlock(&peerl.lock);
-
        if (peer) {
-                       if (!peer->dynamic) {
+                       if (!ast_test_flag(peer, SIP_DYNAMIC)) {
                                ast_log(LOG_NOTICE, "Peer '%s' is trying to register, but not configured as host=dynamic\n", peer->name);
                        } else {
-                               p->nat = peer->nat;
+                               ast_copy_flags(p, peer, SIP_NAT);
                                transmit_response(p, "100 Trying", req);
                                if (!(res = check_auth(p, req, p->randdata, sizeof(p->randdata), peer->name, peer->secret, peer->md5secret, "REGISTER", uri, 0, ignore))) {
                                        sip_cancel_destroy(p);
@@ -4882,10 +5036,7 @@ static int register_verify(struct sip_pvt *p, struct sockaddr_in *sin, struct si
                /* Create peer if we have autocreate mode enabled */
                peer = temp_peer(name);
                if (peer) {
-                       ast_mutex_lock(&peerl.lock);
-                       peer->next = peerl.peers;
-                       peerl.peers = peer;
-                       ast_mutex_unlock(&peerl.lock);
+                       ASTOBJ_CONTAINER_LINK(&peerl, peer);
                        peer->lastmsgssent = -1;
                        sip_cancel_destroy(p);
                        if (parse_contact(p, peer, req)) {
@@ -4904,9 +5055,8 @@ static int register_verify(struct sip_pvt *p, struct sockaddr_in *sin, struct si
        }
        if (res < 0)
                transmit_response(p, "403 Forbidden", &p->initreq);
-       if (peer && peer->temponly) {
-               destroy_peer(peer);
-       }
+       if (peer)
+               ASTOBJ_UNREF(peer,sip_destroy_peer);
        return res;
 }
 
@@ -5224,9 +5374,9 @@ static int check_via(struct sip_pvt *p, struct sip_request *req)
                p->sa.sin_port = htons(pt ? atoi(pt) : DEFAULT_SIP_PORT);
                c = strstr(via, ";rport");
                if (c && (c[6] != '='))
-                       p->nat |= SIP_NAT_ROUTE;
+                       ast_set_flag(p, SIP_NAT_ROUTE);
                if (sip_debug_test_pvt(p)) {
-                       if (p->nat & SIP_NAT_ROUTE)
+                       if (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)
                                ast_verbose("Sending to %s : %d (NAT)\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), ntohs(p->sa.sin_port));
                        else
                                ast_verbose("Sending to %s : %d (non-NAT)\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), ntohs(p->sa.sin_port));
@@ -5368,10 +5518,10 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
                strncpy(p->cid_name, calleridname, sizeof(p->cid_name) - 1);
        if (ast_strlen_zero(of))
                return 0;
-       ast_mutex_lock(&userl.lock);
        user = find_user(of);
        /* Find user based on user name in the from header */
-       if (user && ast_apply_ha(user->ha, sin)) {
+       if (!mailbox && user && ast_apply_ha(user->ha, sin)) {
+               ast_copy_flags(p, user, SIP_TRUSTRPID | SIP_USECLIENTCODE | SIP_NAT | SIP_PROG_INBAND | SIP_OSPAUTH);
                /* copy vars */
                for (v = user->vars ; v ; v = v->next) {
                        if((tmpvar = ast_new_variable(v->name, v->value))) {
@@ -5380,15 +5530,8 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
                        }
                }
                p->prefs = user->prefs;
-               p->nat = user->nat;
-#ifdef OSP_SUPPORT
-               p->ospauth = user->ospauth;
-#endif
-               p->trustrpid = user->trustrpid;
-               p->useclientcode = user->useclientcode;
-               p->progressinband = user->progressinband;
                /* replace callerid if rpid found, and not restricted */
-               if(!ast_strlen_zero(rpid_num) && p->trustrpid) {
+               if(!ast_strlen_zero(rpid_num) && ast_test_flag(p, SIP_TRUSTRPID)) {
                        if (*calleridname)
                                strncpy(p->cid_name, calleridname, sizeof(p->cid_name) - 1);
                        strncpy(p->cid_num, rpid_num, sizeof(p->cid_num) - 1);
@@ -5396,15 +5539,16 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
                }
 
                if (p->rtp) {
-                       ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (p->nat & SIP_NAT_ROUTE));
-                       ast_rtp_setnat(p->rtp, (p->nat & SIP_NAT_ROUTE));
+                       ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
+                       ast_rtp_setnat(p->rtp, (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
                }
                if (p->vrtp) {
-                       ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (p->nat & SIP_NAT_ROUTE));
-                       ast_rtp_setnat(p->vrtp, (p->nat & SIP_NAT_ROUTE));
+                       ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
+                       ast_rtp_setnat(p->vrtp, (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
                }
                if (!(res = check_auth(p, req, p->randdata, sizeof(p->randdata), user->name, user->secret, user->md5secret, cmd, uri, reliable, ignore))) {
                        sip_cancel_destroy(p);
+                       ast_copy_flags(p, user, SIP_PROMISCREDIR | SIP_DTMF | SIP_REINVITE);
                        if (!ast_strlen_zero(user->context))
                                strncpy(p->context, user->context, sizeof(p->context) - 1);
                        if (!ast_strlen_zero(user->cid_num) && !ast_strlen_zero(p->cid_num))  {
@@ -5419,7 +5563,6 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
                        strncpy(p->accountcode, user->accountcode, sizeof(p->accountcode)  -1);
                        strncpy(p->language, user->language, sizeof(p->language)  -1);
                        strncpy(p->musicclass, user->musicclass, sizeof(p->musicclass)  -1);
-                       p->canreinvite = user->canreinvite;
                        p->amaflags = user->amaflags;
                        p->callgroup = user->callgroup;
                        p->pickupgroup = user->pickupgroup;
@@ -5428,31 +5571,24 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
                        p->jointcapability = user->capability;
                        if (p->peercapability)
                                p->jointcapability &= p->peercapability;
-                       p->promiscredir = user->promiscredir;
-                       if (user->dtmfmode) {
-                               p->dtmfmode = user->dtmfmode;
-                               if (p->dtmfmode & SIP_DTMF_RFC2833)
-                                       p->noncodeccapability |= AST_RTP_DTMF;
-                               else
-                                       p->noncodeccapability &= ~AST_RTP_DTMF;
-                       }
+                       if (ast_test_flag(p, SIP_DTMF) == SIP_DTMF_RFC2833)
+                               p->noncodeccapability |= AST_RTP_DTMF;
+                       else
+                               p->noncodeccapability &= ~AST_RTP_DTMF;
                }
                if (user && debug)
                        ast_verbose("Found user '%s'\n", user->name);
        } else {
                if (user) {
-                       if (debug)
+                       if (!mailbox && debug)
                                ast_verbose("Found user '%s', but fails host access\n", user->name);
-                       if (user->temponly)
-                               destroy_user(user);
+                       ASTOBJ_UNREF(user,sip_destroy_user);
                }
                user = NULL;
        }
-       /* Temp user gets cleaned up at the end */
-       ast_mutex_unlock(&userl.lock);
+
        if (!user) {
                /* If we didn't find a user match, check for peers */
-               ast_mutex_lock(&peerl.lock);
                /* Look for peer based on the IP address we received data from */
                /* If peer is registred from this IP address or have this as a default
                   IP address, this call is from the peer 
@@ -5462,39 +5598,33 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
                        if (debug)
                                ast_verbose("Found peer '%s'\n", peer->name);
                        /* Take the peer */
-                       p->nat = peer->nat;
-                       p->trustrpid = peer->trustrpid;
-                       p->useclientcode = peer->useclientcode;
-                       p->progressinband = peer->progressinband;
+                       ast_copy_flags(p, peer, SIP_TRUSTRPID | SIP_USECLIENTCODE | SIP_NAT | SIP_PROG_INBAND | SIP_OSPAUTH);
                        /* replace callerid if rpid found, and not restricted */
-                       if(!ast_strlen_zero(rpid_num) && p->trustrpid) {
+                       if(!ast_strlen_zero(rpid_num) && ast_test_flag(p, SIP_TRUSTRPID)) {
                                if (*calleridname)
                                        strncpy(p->cid_name, calleridname, sizeof(p->cid_name) - 1);
                                strncpy(p->cid_num, rpid_num, sizeof(p->cid_num) - 1);
                                ast_shrink_phone_number(p->cid_num);
                        }
-#ifdef OSP_SUPPORT
-                       p->ospauth = peer->ospauth;
-#endif
                        if (p->rtp) {
-                               ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (p->nat & SIP_NAT_ROUTE));
-                               ast_rtp_setnat(p->rtp, (p->nat & SIP_NAT_ROUTE));
+                               ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
+                               ast_rtp_setnat(p->rtp, (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
                        }
                        if (p->vrtp) {
-                               ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (p->nat & SIP_NAT_ROUTE));
-                               ast_rtp_setnat(p->vrtp, (p->nat & SIP_NAT_ROUTE));
+                               ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
+                               ast_rtp_setnat(p->vrtp, (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
                        }
                        strncpy(p->peersecret, peer->secret, sizeof(p->peersecret)-1);
                        p->peersecret[sizeof(p->peersecret)-1] = '\0';
                        strncpy(p->peermd5secret, peer->md5secret, sizeof(p->peermd5secret)-1);
                        p->peermd5secret[sizeof(p->peermd5secret)-1] = '\0';
-                       if (peer->insecure > 1) {
+                       if (ast_test_flag(peer, SIP_INSECURE) == SIP_INSECURE_VERY) {
                                /* Pretend there is no required authentication if insecure is "very" */
                                p->peersecret[0] = '\0';
                                p->peermd5secret[0] = '\0';
                        }
                        if (!(res = check_auth(p, req, p->randdata, sizeof(p->randdata), peer->name, p->peersecret, p->peermd5secret, cmd, uri, reliable, ignore))) {
-                               p->canreinvite = peer->canreinvite;
+                               ast_copy_flags(p, peer, SIP_PROMISCREDIR | SIP_DTMF | SIP_REINVITE);
                                strncpy(p->peername, peer->name, sizeof(p->peername) - 1);
                                strncpy(p->authname, peer->name, sizeof(p->authname) - 1);
                                if (mailbox)
@@ -5521,27 +5651,18 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
                                p->jointcapability = peer->capability;
                                if (p->peercapability)
                                        p->jointcapability &= p->peercapability;
-                               p->promiscredir = peer->promiscredir;
-                               if (peer->dtmfmode) {
-                                       p->dtmfmode = peer->dtmfmode;
-                                       if (p->dtmfmode & SIP_DTMF_RFC2833)
-                                               p->noncodeccapability |= AST_RTP_DTMF;
-                                       else
-                                               p->noncodeccapability &= ~AST_RTP_DTMF;
-                               }
+                               if (ast_test_flag(p, SIP_DTMF) == SIP_DTMF_RFC2833)
+                                       p->noncodeccapability |= AST_RTP_DTMF;
+                               else
+                                       p->noncodeccapability &= ~AST_RTP_DTMF;
                        }
-                       if (peer->temponly) 
-                               destroy_peer(peer);
-               } else
-                       if (debug)
-                               ast_verbose("Found no matching peer or user for '%s:%d'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr), ntohs(p->recv.sin_port));
-               ast_mutex_unlock(&peerl.lock);
-
+                       ASTOBJ_UNREF(peer,sip_destroy_peer);
+               } else if (debug)
+                       ast_verbose("Found no matching peer or user for '%s:%d'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr), ntohs(p->recv.sin_port));
        }
 
-       if (user && user->temponly) 
-               destroy_user(user);
-
+       if (user)
+               ASTOBJ_UNREF(user,sip_destroy_user);
        return res;
 }
 
@@ -5602,7 +5723,6 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req)
 static int sip_show_inuse(int fd, int argc, char *argv[]) {
 #define FORMAT  "%-15.15s %-15.15s %-15.15s %-15.15s %-15.15s\n"
 #define FORMAT2 "%-15.15s %-15.15s %-15.15s %-15.15s %-15.15s\n"
-       struct sip_user *user;
        char ilimits[40] = "";
        char olimits[40] = "";
        char iused[40];
@@ -5610,23 +5730,22 @@ static int sip_show_inuse(int fd, int argc, char *argv[]) {
 
        if (argc != 3) 
                return RESULT_SHOWUSAGE;
-       ast_mutex_lock(&userl.lock);
-       user = userl.users;
        ast_cli(fd, FORMAT, "Username", "incoming", "Limit","outgoing","Limit");
-       for(user=userl.users;user;user=user->next) {
-               if (user->incominglimit)
-                       snprintf(ilimits, sizeof(ilimits), "%d", user->incominglimit);
+       ASTOBJ_CONTAINER_TRAVERSE(&userl, do {
+               ASTOBJ_RDLOCK(iterator);
+               if (iterator->incominglimit)
+                       snprintf(ilimits, sizeof(ilimits), "%d", iterator->incominglimit);
                else
                        strncpy(ilimits, "N/A", sizeof(ilimits) - 1);
-               if (user->outgoinglimit)
-                       snprintf(olimits, sizeof(olimits), "%d", user->outgoinglimit);
+               if (iterator->outgoinglimit)
+                       snprintf(olimits, sizeof(olimits), "%d", iterator->outgoinglimit);
                else
                        strncpy(olimits, "N/A", sizeof(olimits) - 1);
-               snprintf(iused, sizeof(iused), "%d", user->inUse);
-               snprintf(oused, sizeof(oused), "%d", user->outUse);
-               ast_cli(fd, FORMAT2, user->name, iused, ilimits,oused,olimits);
-       }
-       ast_mutex_unlock(&userl.lock);
+               snprintf(iused, sizeof(iused), "%d", iterator->inUse);
+               snprintf(oused, sizeof(oused), "%d", iterator->outUse);
+               ast_cli(fd, FORMAT2, iterator->name, iused, ilimits,oused,olimits);
+               ASTOBJ_UNLOCK(iterator);
+       } while (0) );
        return RESULT_SUCCESS;
 #undef FORMAT
 #undef FORMAT2
@@ -5652,20 +5771,20 @@ static char *nat2str(int nat)
 static int sip_show_users(int fd, int argc, char *argv[])
 {
 #define FORMAT  "%-15.15s  %-15.15s  %-15.15s %-15.15s %-5.5s%-5.5s\n"
-       struct sip_user *user;
        if (argc != 3) 
                return RESULT_SHOWUSAGE;
-       ast_mutex_lock(&userl.lock);
        ast_cli(fd, FORMAT, "Username", "Secret", "Accountcode", "Def.Context", "ACL", "NAT");
-       for(user=userl.users;user;user=user->next) {
-               ast_cli(fd, FORMAT, user->name, 
-                               user->secret, 
-                               user->accountcode,
-                               user->context,
-                               user->ha ? "Yes" : "No",
-                               nat2str(user->nat));
-       }
-       ast_mutex_unlock(&userl.lock);
+       ASTOBJ_CONTAINER_TRAVERSE(&userl, do {
+               ASTOBJ_RDLOCK(iterator);
+               ast_cli(fd, FORMAT, iterator->name, 
+                       iterator->secret, 
+                       iterator->accountcode,
+                       iterator->context,
+                       iterator->ha ? "Yes" : "No",
+                       nat2str(ast_test_flag(iterator, SIP_NAT)));
+               ASTOBJ_UNLOCK(iterator);
+       } while (0)
+       );
        return RESULT_SUCCESS;
 #undef FORMAT
 }
@@ -5675,7 +5794,6 @@ static int sip_show_peers(int fd, int argc, char *argv[])
 {
 #define FORMAT2 "%-15.15s  %-15.15s %s %s %s %-15.15s  %-8s %-10s\n"
 #define FORMAT  "%-15.15s  %-15.15s %s %s %s %-15.15s  %-8d %-10s\n"
-       struct sip_peer *peer;
        char name[256] = "";
        char iabuf[INET_ADDRSTRLEN];
        int total_peers = 0;
@@ -5685,33 +5803,34 @@ static int sip_show_peers(int fd, int argc, char *argv[])
        
        if (argc != 3 && argc != 5)
                return RESULT_SHOWUSAGE;
-       ast_mutex_lock(&peerl.lock);
        ast_cli(fd, FORMAT2, "Name/username", "Host", "Dyn", "Nat", "ACL", "Mask", "Port", "Status");
        
-       for (peer = peerl.peers;peer;peer = peer->next) {
+       ASTOBJ_CONTAINER_TRAVERSE(&peerl, do {
                char nm[20] = "";
                char status[20] = "";
                int print_line = -1;
                char srch[2000];
                
-               ast_inet_ntoa(nm, sizeof(nm), peer->mask);
-               if (!ast_strlen_zero(peer->username))
-                       snprintf(name, sizeof(name), "%s/%s", peer->name, peer->username);
+               ASTOBJ_RDLOCK(iterator);
+
+               ast_inet_ntoa(nm, sizeof(nm), iterator->mask);
+               if (!ast_strlen_zero(iterator->username))
+                       snprintf(name, sizeof(name), "%s/%s", iterator->name, iterator->username);
                else
-                       strncpy(name, peer->name, sizeof(name) - 1);
-               if (peer->maxms) {
-                       if (peer->lastms < 0) {
+                       strncpy(name, iterator->name, sizeof(name) - 1);
+               if (iterator->maxms) {
+                       if (iterator->lastms < 0) {
                                strncpy(status, "UNREACHABLE", sizeof(status) - 1);
                                peers_offline++;
-                       } else if (peer->lastms > peer->maxms) {
-                               snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms);
+                       } else if (iterator->lastms > iterator->maxms) {
+                               snprintf(status, sizeof(status), "LAGGED (%d ms)", iterator->lastms);
                                peers_online++;
-                       } else if (peer->lastms) {
-                               snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms);
+                       } else if (iterator->lastms) {
+                               snprintf(status, sizeof(status), "OK (%d ms)", iterator->lastms);
                                peers_online++;
                        } else {
                                /* Checking if port is 0 */
-                               if ( ntohs(peer->addr.sin_port) == 0 ) { 
+                               if ( ntohs(iterator->addr.sin_port) == 0 ) { 
                                        peers_offline++;
                                } else {
                                        peers_online++;
@@ -5721,7 +5840,7 @@ static int sip_show_peers(int fd, int argc, char *argv[])
                } else { 
                        strncpy(status, "Unmonitored", sizeof(status) - 1);
                        /* Checking if port is 0 */
-                       if ( ntohs(peer->addr.sin_port) == 0 ) {
+                       if ( ntohs(iterator->addr.sin_port) == 0 ) {
                                peers_offline++;
                        } else {
                                peers_online++;
@@ -5729,11 +5848,11 @@ static int sip_show_peers(int fd, int argc, char *argv[])
                }                       
                
                snprintf(srch, sizeof(srch), FORMAT, name,
-                       peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)",
-                       peer->dynamic ? " D " : "   ",  /* Dynamic or not? */
-                       (peer->nat & SIP_NAT_ROUTE) ? " Y " : "   ",    /* NAT=yes? */
-                       peer->ha ? " A " : "   ",       /* permit/deny */
-                       nm, ntohs(peer->addr.sin_port), status);
+                       iterator->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), iterator->addr.sin_addr) : "(Unspecified)",
+                       ast_test_flag(iterator, SIP_DYNAMIC) ? " D " : "   ",   /* Dynamic or not? */
+                       (ast_test_flag(iterator, SIP_NAT) & SIP_NAT_ROUTE) ? " N " : "   ",     /* NAT=yes? */
+                       iterator->ha ? " A " : "   ",   /* permit/deny */
+                       nm, ntohs(iterator->addr.sin_port), status);
 
                if (argc == 5) {
                        if (!strcasecmp(argv[3],"include") && strstr(srch,argv[4])) {
@@ -5749,39 +5868,68 @@ static int sip_show_peers(int fd, int argc, char *argv[])
 
                if (print_line) {
                    ast_cli(fd, FORMAT, name, 
-                       peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)",
-                        peer->dynamic ? " D " : "   ",  /* Dynamic or not? */
-                        (peer->nat & SIP_NAT_ROUTE) ? " N " : "   ",   /* NAT=yes? */
-                        peer->ha ? " A " : "   ",       /* permit/deny */
+                       iterator->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), iterator->addr.sin_addr) : "(Unspecified)",
+                        ast_test_flag(iterator, SIP_DYNAMIC) ? " D " : "   ",  /* Dynamic or not? */
+                        (ast_test_flag(iterator, SIP_NAT) & SIP_NAT_ROUTE) ? " N " : "   ",    /* NAT=yes? */
+                        iterator->ha ? " A " : "   ",       /* permit/deny */
                        nm,
-                       ntohs(peer->addr.sin_port), status);
+                       ntohs(iterator->addr.sin_port), status);
                }
+
+               ASTOBJ_UNLOCK(iterator);
+
                total_peers++;
-       }
+       } while(0) );
        ast_cli(fd,"%d sip peers loaded [%d online , %d offline]\n",total_peers,peers_online,peers_offline);
-       ast_mutex_unlock(&peerl.lock);
        return RESULT_SUCCESS;
 #undef FORMAT
 #undef FORMAT2
 }
 
+static int sip_show_objects(int fd, int argc, char *argv[])
+{
+       char tmp[256];
+       if (argc != 3)
+               return RESULT_SHOWUSAGE;
+       ast_cli(fd, "-= User objects: %d static, %d realtime =-\n\n", suserobjs, ruserobjs);
+       ASTOBJ_CONTAINER_DUMP(fd, tmp, sizeof(tmp), &userl);
+       ast_cli(fd, "-= Peer objects: %d static, %d realtime, %d autocreate =-\n\n", speerobjs, rpeerobjs, apeerobjs);
+       ASTOBJ_CONTAINER_DUMP(fd, tmp, sizeof(tmp), &peerl);
+       ast_cli(fd, "-= Registry objects: %d =-\n\n", regobjs);
+       ASTOBJ_CONTAINER_DUMP(fd, tmp, sizeof(tmp), &regl);
+       return RESULT_SUCCESS;
+}
 /*--- print_group: Print call group and pickup group ---*/
 static void  print_group(int fd, unsigned int group) 
 {
-       unsigned int i;
-       int first=1;
+       char buf[256];
+       ast_cli(fd, ast_print_group(buf, sizeof(buf), group) );
+}
 
-       for (i=0; i<=31; i++) { /* Max group is 31 */
-               if (group & (1 << i)) {
-                       if (!first) {
-                               ast_cli(fd, ", ");
-                       } else {
-                               first=0;
-                       }
-                       ast_cli(fd, "%u", i);
-               }
-       }
-       ast_cli(fd, " (%u)\n", group);
+static const char *dtmfmode2str(int mode)
+{
+       switch (mode) {
+       case SIP_DTMF_RFC2833:
+               return "rfc2833";
+       case SIP_DTMF_INFO:
+               return "info";
+       case SIP_DTMF_INBAND:
+               return "inband";
+       }
+       return "<error>";
+}
+
+static const char *insecure2str(int mode)
+{
+       switch (mode) {
+       case SIP_SECURE:
+               return "no";
+       case SIP_INSECURE_NORMAL:
+               return "yes";
+       case SIP_INSECURE_VERY:
+               return "very";
+       }
+       return "<error>";
 }
 
 /*--- sip_show_peer: Show one peer in detail ---*/
@@ -5797,7 +5945,6 @@ static int sip_show_peer(int fd, int argc, char *argv[])
 
        if (argc != 4)
                return RESULT_SHOWUSAGE;
-       ast_mutex_lock(&peerl.lock);
        peer = find_peer(argv[3], NULL);
        if (peer) {
                ast_cli(fd,"\n\n");
@@ -5814,26 +5961,19 @@ static int sip_show_peer(int fd, int argc, char *argv[])
                print_group(fd, peer->pickupgroup);
                ast_cli(fd, "  Mailbox      : %s\n", peer->mailbox);
                ast_cli(fd, "  LastMsgsSent : %d\n", peer->lastmsgssent);
-               ast_cli(fd, "  Dynamic      : %s\n", (peer->dynamic?"Yes":"No"));
+               ast_cli(fd, "  Dynamic      : %s\n", (ast_test_flag(peer, SIP_DYNAMIC)?"Yes":"No"));
                ast_cli(fd, "  Callerid     : %s\n", ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, "<unspecified>"));
                ast_cli(fd, "  Expire       : %d\n", peer->expire);
                ast_cli(fd, "  Expiry       : %d\n", peer->expiry);
-               ast_cli(fd, "  Insecure     : %s\n", (peer->insecure?((peer->insecure == 2)?"Very":"Yes"):"No") );
-               ast_cli(fd, "  Nat          : %s\n", nat2str(peer->nat));
+               ast_cli(fd, "  Insecure     : %s\n", insecure2str(ast_test_flag(peer, SIP_INSECURE)));
+               ast_cli(fd, "  Nat          : %s\n", nat2str(ast_test_flag(peer, SIP_NAT)));
                ast_cli(fd, "  ACL          : %s\n", (peer->ha?"Yes":"No"));
-               ast_cli(fd, "  CanReinvite  : %s\n", (peer->canreinvite?"Yes":"No"));
-               ast_cli(fd, "  PromiscRedir : %s\n", (peer->promiscredir?"Yes":"No"));
-               ast_cli(fd, "  User=Phone   : %s\n", (peer->usereqphone?"Yes":"No"));
+               ast_cli(fd, "  CanReinvite  : %s\n", (ast_test_flag(peer, SIP_CAN_REINVITE)?"Yes":"No"));
+               ast_cli(fd, "  PromiscRedir : %s\n", (ast_test_flag(peer, SIP_PROMISCREDIR)?"Yes":"No"));
+               ast_cli(fd, "  User=Phone   : %s\n", (ast_test_flag(peer, SIP_USEREQPHONE)?"Yes":"No"));
 
                /* - is enumerated */
-               ast_cli(fd, "  DTMFmode     : ");
-               if (peer->dtmfmode == SIP_DTMF_RFC2833)
-                       ast_cli(fd, "rfc2833 ");
-                if (peer->dtmfmode == SIP_DTMF_INFO)
-                       ast_cli(fd, "info ");
-                if (peer->dtmfmode == SIP_DTMF_INBAND)
-                        ast_cli(fd, "inband ");
-                ast_cli(fd, "\n" );
+               ast_cli(fd, "  DTMFmode     : %s\n", dtmfmode2str(ast_test_flag(peer, SIP_DTMF)));
                ast_cli(fd, "  LastMsg      : %d\n", peer->lastmsg);
                ast_cli(fd, "  ToHost       : %s\n", peer->tohost);
                ast_cli(fd, "  Addr->IP     : %s Port %d\n",  peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)", ntohs(peer->addr.sin_port));
@@ -5870,16 +6010,12 @@ static int sip_show_peer(int fd, int argc, char *argv[])
                ast_cli(fd, "  Useragent    : %s\n", peer->useragent);
                ast_cli(fd, "  Full Contact : %s\n", peer->fullcontact);
                ast_cli(fd,"\n");
+               ASTOBJ_UNREF(peer,sip_destroy_peer);
        } else {
                ast_cli(fd,"Peer %s not found.\n", argv[3]);
                ast_cli(fd,"\n");
        }
 
-       ast_mutex_unlock(&peerl.lock);
-
-       if (peer && peer->temponly) {
-               destroy_peer(peer);
-       }
        return RESULT_SUCCESS;
 }
 
@@ -5888,19 +6024,17 @@ static int sip_show_registry(int fd, int argc, char *argv[])
 {
 #define FORMAT2 "%-30.30s  %-12.12s  %8.8s %-20.20s\n"
 #define FORMAT  "%-30.30s  %-12.12s  %8d %-20.20s\n"
-       struct sip_registry *reg;
        char host[80];
 
        if (argc != 3)
                return RESULT_SHOWUSAGE;
-       ast_mutex_lock(&regl.lock);
        ast_cli(fd, FORMAT2, "Host", "Username", "Refresh", "State");
-       for (reg = regl.registrations;reg;reg = reg->next) {
-               snprintf(host, sizeof(host), "%s:%d", reg->hostname, reg->portno ? reg->portno : DEFAULT_SIP_PORT);
-               ast_cli(fd, FORMAT, host,
-                                       reg->username, reg->refresh, regstate2str(reg->regstate));
-       }
-       ast_mutex_unlock(&regl.lock);
+       ASTOBJ_CONTAINER_TRAVERSE(&regl, do {
+               ASTOBJ_RDLOCK(iterator);
+               snprintf(host, sizeof(host), "%s:%d", iterator->hostname, iterator->portno ? iterator->portno : DEFAULT_SIP_PORT);
+               ast_cli(fd, FORMAT, host, iterator->username, iterator->refresh, regstate2str(iterator->regstate));
+               ASTOBJ_UNLOCK(iterator);
+       } while(0));
        return RESULT_SUCCESS;
 #undef FORMAT
 #undef FORMAT2
@@ -5943,7 +6077,7 @@ static int __sip_show_channels(int fd, int argc, char *argv[], int subscriptions
                                ast_strlen_zero(cur->username) ? ( ast_strlen_zero(cur->cid_num) ? "(None)" : cur->cid_num ) : cur->username, 
                                cur->callid, 
                                cur->ocseq, cur->icseq, 
-                               ast_getformatname(cur->owner ? cur->owner->nativeformats : 0), cur->needdestroy ? "(d)" : "" );
+                               ast_getformatname(cur->owner ? cur->owner->nativeformats : 0), ast_test_flag(cur, SIP_NEEDDESTROY) ? "(d)" : "" );
                        numchans++;
                }
                if (cur->subscribed && subscriptions) {
@@ -5991,7 +6125,6 @@ static char *complete_sipch(char *line, char *word, int pos, int state)
 static int sip_show_channel(int fd, int argc, char *argv[])
 {
        struct sip_pvt *cur;
-       char tmp[256];
        char iabuf[INET_ADDRSTRLEN];
        size_t len;
        int found = 0;
@@ -6008,7 +6141,7 @@ static int sip_show_channel(int fd, int argc, char *argv[])
                                ast_cli(fd, "  * Subscription\n");
                        else
                                ast_cli(fd, "  * SIP Call\n");
-                       ast_cli(fd, "  Direction:              %s\n", cur->outgoing?"Outgoing":"Incoming");
+                       ast_cli(fd, "  Direction:              %s\n", ast_test_flag(cur, SIP_OUTGOING)?"Outgoing":"Incoming");
                        ast_cli(fd, "  Call-ID:                %s\n", cur->callid);
                        ast_cli(fd, "  Our Codec Capability:   %d\n", cur->capability);
                        ast_cli(fd, "  Non-Codec Capability:   %d\n", cur->noncodeccapability);
@@ -6017,7 +6150,7 @@ static int sip_show_channel(int fd, int argc, char *argv[])
                        ast_cli(fd, "  Format                  %s\n", ast_getformatname(cur->owner ? cur->owner->nativeformats : 0) );
                        ast_cli(fd, "  Theoretical Address:    %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), cur->sa.sin_addr), ntohs(cur->sa.sin_port));
                        ast_cli(fd, "  Received Address:       %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), cur->recv.sin_addr), ntohs(cur->recv.sin_port));
-                       ast_cli(fd, "  NAT Support:            %s\n", nat2str(cur->nat));
+                       ast_cli(fd, "  NAT Support:            %s\n", nat2str(ast_test_flag(cur, SIP_NAT)));
                        ast_cli(fd, "  Our Tag:                %08d\n", cur->tag);
                        ast_cli(fd, "  Their Tag:              %s\n", cur->theirtag);
                        ast_cli(fd, "  SIP User agent:         %s\n", cur->useragent);
@@ -6029,18 +6162,11 @@ static int sip_show_channel(int fd, int argc, char *argv[])
                                ast_cli(fd, "  Original uri:           %s\n", cur->uri);
                        if (!ast_strlen_zero(cur->cid_num))
                                ast_cli(fd, "  Caller-ID:              %s\n", cur->cid_num);
-                       ast_cli(fd, "  Need Destroy:           %d\n", cur->needdestroy);
+                       ast_cli(fd, "  Need Destroy:           %d\n", ast_test_flag(cur, SIP_NEEDDESTROY));
                        ast_cli(fd, "  Last Message:           %s\n", cur->lastmsg);
-                       ast_cli(fd, "  Promiscuous Redir:      %s\n", cur->promiscredir ? "Yes" : "No");
+                       ast_cli(fd, "  Promiscuous Redir:      %s\n", ast_test_flag(cur, SIP_PROMISCREDIR) ? "Yes" : "No");
                        ast_cli(fd, "  Route:                  %s\n", cur->route ? cur->route->hop : "N/A");
-                       tmp[0] = '\0';
-                       if (cur->dtmfmode & SIP_DTMF_RFC2833)
-                               strncat(tmp, "rfc2833 ", sizeof(tmp) - strlen(tmp) - 1);
-                       if (cur->dtmfmode & SIP_DTMF_INFO)
-                               strncat(tmp, "info ", sizeof(tmp) - strlen(tmp) - 1);
-                       if (cur->dtmfmode & SIP_DTMF_INBAND)
-                               strncat(tmp, "inband ", sizeof(tmp) - strlen(tmp) - 1);
-                       ast_cli(fd, "  DTMF Mode:              %s\n\n", tmp);
+                       ast_cli(fd, "  DTMF Mode:              %s\n\n", dtmfmode2str(ast_test_flag(cur, SIP_DTMF)));
                        found++;
                }
                cur = cur->next;
@@ -6149,12 +6275,12 @@ static void receive_info(struct sip_pvt *p, struct sip_request *req)
                        return;
                } else {
                        transmit_response(p, "481 Call leg/transaction does not exist", req);
-                       p->needdestroy = 1;
+                       ast_set_flag(p, SIP_NEEDDESTROY);
                }
                return;
        } else if ((c = get_header(req, "X-ClientCode"))) {
                /* Client code (from SNOM phone) */
-               if (p->useclientcode) {
+               if (ast_test_flag(p, SIP_USECLIENTCODE)) {
                        if (p->owner && p->owner->cdr)
                                ast_cdr_setuserfield(p->owner, c);
                        if (p->owner && ast_bridged_channel(p->owner) && ast_bridged_channel(p->owner)->cdr)
@@ -6212,13 +6338,7 @@ static int sip_do_debug_peer(int fd, int argc, char *argv[])
        char iabuf[INET_ADDRSTRLEN];
        if (argc != 4)
                return RESULT_SHOWUSAGE;
-       ast_mutex_lock(&peerl.lock);
-       for (peer = peerl.peers;peer;peer = peer->next)
-               if (!strcmp(peer->name, argv[3])) 
-                       break;
-       ast_mutex_unlock(&peerl.lock);
-       if (!peer)
-               peer = realtime_peer(argv[3], NULL);
+       peer = find_peer(argv[3], NULL);
        if (peer) {
                if (peer->addr.sin_addr.s_addr) {
                        debugaddr.sin_family = AF_INET;
@@ -6228,9 +6348,7 @@ static int sip_do_debug_peer(int fd, int argc, char *argv[])
                        sipdebug = 1;
                } else
                        ast_cli(fd, "Unable to get IP address of peer '%s'\n", argv[3]);
-               if (peer->temponly)
-                       destroy_peer(peer);
-               peer = NULL;
+               ASTOBJ_UNREF(peer,sip_destroy_peer);
        } else
                ast_cli(fd, "No such peer '%s'\n", argv[3]);
        return RESULT_SUCCESS;
@@ -6287,27 +6405,34 @@ static int sip_no_debug(int fd, int argc, char *argv[])
 
 static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader, char *digest, int digest_len);
 
-/*--- do_register_auth: Challenge for registration ---*/
+/*--- do_register_auth: Authenticate for outbound registration ---*/
 static int do_register_auth(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader) {
        char digest[1024];
        p->authtries++;
        memset(digest,0,sizeof(digest));
-       if (reply_digest(p,req, header, "REGISTER", digest, sizeof(digest))) {
+       if (reply_digest(p, req, header, "REGISTER", digest, sizeof(digest))) {
                /* There's nothing to use for authentication */
+               /* No digest challenge in request */
+               if (sip_debug_test_pvt(p) && p->registry)
+                       ast_verbose("No authentication challenge, sending blank registration to domain/host name %s\n", p->registry->hostname);
+                       /* No old challenge */
                return -1;
        }
+       if (sip_debug_test_pvt(p) && p->registry)
+               ast_verbose("Responding to challenge, registration to domain/host name %s\n", p->registry->hostname);
        return transmit_register(p->registry,"REGISTER",digest, respheader); 
 }
 
-/*--- do_proxy_auth: Challenge user ---*/
+/*--- do_proxy_auth: Add authentication on outbound SIP packet ---*/
 static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader, char *msg, int init) {
        char digest[1024];
        p->authtries++;
        memset(digest,0,sizeof(digest));
-       if (reply_digest(p,req, header, msg, digest, sizeof(digest) )) {
+       if (reply_digest(p, req, header, msg, digest, sizeof(digest) )) {
                /* No way to authenticate */
                return -1;
        }
+       /* Now we have a reply digest */
        return transmit_invite(p,msg,!strcasecmp(msg, "INVITE"),digest, respheader, NULL,NULL,NULL, 0, init); 
 }
 
@@ -6403,6 +6528,15 @@ static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header
        strncpy(p->domain, domain, sizeof(p->domain)-1);
        strncpy(p->opaque, opaque, sizeof(p->opaque)-1);
        strncpy(p->qop, qop, sizeof(p->qop)-1);
+
+       /* Save auth data for following registrations */
+       if (p->registry) {
+               strncpy(p->registry->realm, realm, sizeof(p->realm)-1);
+               strncpy(p->registry->nonce, nonce, sizeof(p->nonce)-1);
+               strncpy(p->registry->domain, domain, sizeof(p->domain)-1);
+               strncpy(p->registry->opaque, opaque, sizeof(p->opaque)-1);
+               strncpy(p->registry->qop, qop, sizeof(p->qop)-1);
+       }
        build_reply_digest(p, orig_header, digest, digest_len); 
        return 0;
 }
@@ -6519,11 +6653,17 @@ static char show_subscriptions_usage[] =
 "Usage: sip show subscriptions\n" 
 "       Shows active SIP subscriptions for extension states\n";
 
+static char show_objects_usage[] =
+"Usage: sip show objects\n" 
+"       Shows status of known SIP objects\n";
 
+
+static struct ast_cli_entry  cli_show_objects = 
+       { { "sip", "show", "objects", NULL }, sip_show_objects, "Show all SIP object allocations", show_objects_usage };
 static struct ast_cli_entry  cli_show_users = 
        { { "sip", "show", "users", NULL }, sip_show_users, "Show defined SIP users", show_users_usage };
 static struct ast_cli_entry  cli_show_subscriptions =
-        { { "sip", "show", "subscriptions", NULL }, sip_show_subscriptions, "Show active SIP subscriptions", show_subscriptions_usage};
+       { { "sip", "show", "subscriptions", NULL }, sip_show_subscriptions, "Show active SIP subscriptions", show_subscriptions_usage};
 static struct ast_cli_entry  cli_show_channels =
        { { "sip", "show", "channels", NULL }, sip_show_channels, "Show active SIP channels", show_channels_usage};
 static struct ast_cli_entry  cli_show_channel =
@@ -6539,11 +6679,11 @@ static struct ast_cli_entry  cli_show_peer =
 static struct ast_cli_entry  cli_show_peers =
        { { "sip", "show", "peers", NULL }, sip_show_peers, "Show defined SIP peers", show_peers_usage };
 static struct ast_cli_entry  cli_show_peers_include =
-        { { "sip", "show", "peers", "include", NULL }, sip_show_peers, "Show defined SIP peers", show_peers_usage };
+       { { "sip", "show", "peers", "include", NULL }, sip_show_peers, "Show defined SIP peers", show_peers_usage };
 static struct ast_cli_entry  cli_show_peers_exclude =
-        { { "sip", "show", "peers", "exclude", NULL }, sip_show_peers, "Show defined SIP peers", show_peers_usage };
+       { { "sip", "show", "peers", "exclude", NULL }, sip_show_peers, "Show defined SIP peers", show_peers_usage };
 static struct ast_cli_entry  cli_show_peers_begin =
-        { { "sip", "show", "peers", "begin", NULL }, sip_show_peers, "Show defined SIP peers", show_peers_usage };
+       { { "sip", "show", "peers", "begin", NULL }, sip_show_peers, "Show defined SIP peers", show_peers_usage };
 static struct ast_cli_entry  cli_inuse_show =
        { { "sip", "show", "inuse", NULL }, sip_show_inuse, "List all inuse/limit", show_inuse_usage };
 static struct ast_cli_entry  cli_show_registry =
@@ -6567,7 +6707,7 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req)
        e = strchr(s, ';');
        if (e)
                *e = '\0';
-       if (p->promiscredir) {
+       if (ast_test_flag(p, SIP_PROMISCREDIR)) {
                if (!strncasecmp(s, "sip:", 4))
                        s += 4;
                e = strchr(s, '/');
@@ -6591,18 +6731,19 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req)
        }
 }
 
+/*--- check_pendings: Check pending actions on SIP call ---*/
 static void check_pendings(struct sip_pvt *p)
 {
        /* Go ahead and send bye at this point */
-       if (p->pendingbye) {
+       if (ast_test_flag(p, SIP_PENDINGBYE)) {
                transmit_request_with_auth(p, "BYE", 0, 1, 1);
-               p->needdestroy = 1;
-               p->needreinvite = 0;
-       } else if (p->needreinvite) {
+               ast_set_flag(p, SIP_NEEDDESTROY);       
+               ast_clear_flag(p, SIP_NEEDREINVITE);    
+       } else if (ast_test_flag(p, SIP_NEEDREINVITE)) {
                ast_log(LOG_DEBUG, "Sending pending reinvite on '%s'\n", p->callid);
                /* Didn't get to reinvite yet, so do it now */
                transmit_reinvite_with_sdp(p);
-               p->needreinvite = 0;
+               ast_clear_flag(p, SIP_NEEDREINVITE);    
        }
 }
 
@@ -6685,14 +6826,14 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                ast_sched_del(sched, peer->pokeexpire);
                        if (!strcasecmp(msg, "INVITE"))
                                transmit_request(p, "ACK", seqno, 0, 0);
-                       p->needdestroy = 1;
+                       ast_set_flag(p, SIP_NEEDDESTROY);       
                        /* Try again eventually */
                        if ((peer->lastms < 0)  || (peer->lastms > peer->maxms))
                                peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_NOTOK, sip_poke_peer_s, peer);
                        else
                                peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_OK, sip_poke_peer_s, peer);
                }
-       } else if (p->outgoing) {
+       } else if (ast_test_flag(p, SIP_OUTGOING)) {
                /* Acknowledge sequence number */
                if (p->initid > -1) {
                        /* Don't auto congest anymore since we've gotten something useful back */
@@ -6734,7 +6875,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                        ast_queue_hangup(p->owner);
                                } else {
                                        if (!p->subscribed) {
-                                           p->needdestroy = 1;
+                                               ast_set_flag(p, SIP_NEEDDESTROY); 
                                        }
                                }
                        } else if (!strcasecmp(msg, "INVITE")) {
@@ -6742,6 +6883,11 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                sip_cancel_destroy(p);
                                if (!ast_strlen_zero(get_header(req, "Content-Type")))
                                        process_sdp(p, req);
+
+                               /* Parse contact header for continued conversation */
+                               /* When we get 200 OK, we now which device (and IP) to contact for this call */
+                               /* This is important when we have a SIP proxy between us and the phone */
+                               parse_ok_contact(p, req);
                                /* Save Record-Route for any later requests we make on this dialogue */
                                build_route(p, req, 1);
                                if (p->owner) {
@@ -6756,7 +6902,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                        }
                                } else /* It's possible we're getting an ACK after we've tried to disconnect
                                                  by sending CANCEL */
-                                       p->pendingbye = 1;
+                                       ast_set_flag(p, SIP_PENDINGBYE);        
                                p->authtries = 0;
                                /* If I understand this right, the branch is different for a non-200 ACK only */
                                transmit_request(p, "ACK", seqno, 0, 1);
@@ -6777,7 +6923,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                        r->timeout=-1;
                                        r->call = NULL;
                                        p->registry = NULL;
-                                       p->needdestroy = 1;
+                                       ast_set_flag(p, SIP_NEEDDESTROY);       
                                        /* set us up for re-registering */
                                        /* figure out how long we got registered for */
                                        if (r->expire > -1)
@@ -6809,37 +6955,58 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                        if (!expires) expires=atoi(get_header(req, "expires"));
                                        if (!expires) expires=default_expiry;
 
+
                                        expires_ms = expires * 1000;
                                        if (expires <= EXPIRY_GUARD_LIMIT)
                                                expires_ms -= MAX((expires_ms * EXPIRY_GUARD_PCT),EXPIRY_GUARD_MIN);
                                        else
                                                expires_ms -= EXPIRY_GUARD_SECS * 1000;
+                                       if (sipdebug)
+                                               ast_log(LOG_NOTICE, "Outbound Registration: Expiry for %s is %d sec (Scheduling reregistration in %d ms)\n", r->hostname, expires, expires_ms); 
 
                                        r->refresh= (int) expires_ms / 1000;
+
+                                       /* Schedule re-registration before we expire */
                                        r->expire=ast_sched_add(sched, expires_ms, sip_reregister, r); 
+                                       ASTOBJ_UNREF(r, sip_registry_destroy);
                                } else
                                        ast_log(LOG_WARNING, "Got 200 OK on REGISTER that isn't a register\n");
 
                        }
                        break;
-               case 401: /* Not authorized on REGISTER */
+               case 401: /* Not www-authorized on REGISTER */
                        if (!strcasecmp(msg, "INVITE")) {
                                /* First we ACK */
                                transmit_request(p, "ACK", seqno, 0, 0);
                                /* Then we AUTH */
                                if ((p->authtries > 1) || do_proxy_auth(p, req, "WWW-Authenticate", "Authorization", "INVITE", 1)) {
                                        ast_log(LOG_NOTICE, "Failed to authenticate on INVITE to '%s'\n", get_header(&p->initreq, "From"));
-                                       p->needdestroy = 1;
+                                       ast_set_flag(p, SIP_NEEDDESTROY);       
                                }
                        } else if (p->registry && !strcasecmp(msg, "REGISTER")) {
                                if ((p->authtries > 1) || do_register_auth(p, req, "WWW-Authenticate", "Authorization")) {
                                        ast_log(LOG_NOTICE, "Failed to authenticate on REGISTER to '%s'\n", get_header(&p->initreq, "From"));
-                                       p->needdestroy = 1;
+                                       ast_set_flag(p, SIP_NEEDDESTROY);       
                                }
                        } else
-                               p->needdestroy = 1;
+                               ast_set_flag(p, SIP_NEEDDESTROY);       
                        break;
-               case 407:       /* 407 Proxy Authentication Required */
+               case 403: /* Forbidden - we failed authentication */
+                       if (!strcasecmp(msg, "INVITE")) {
+                               /* First we ACK */
+                               transmit_request(p, "ACK", seqno, 0, 0);
+                               ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for INVITE to '%s'\n", get_header(&p->initreq, "From"));
+                               if (owner)
+                                       ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
+                               ast_set_flag(p, SIP_NEEDDESTROY);       
+                       } else if (p->registry && !strcasecmp(msg, "REGISTER")) {
+                               ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for REGISTER for '%s' to '%s'\n", p->registry->username, p->registry->hostname);
+                               ast_set_flag(p, SIP_NEEDDESTROY);       
+                       } else {
+                               ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for %s\n", msg);
+                       }
+                       break;
+               case 407: /* Proxy auth required */
                        if (!strcasecmp(msg, "INVITE")) {
                                /* First we ACK */
                                transmit_request(p, "ACK", seqno, 0, 0);
@@ -6848,7 +7015,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                if(!ignore){
                                        if ((p->authtries > 1) || do_proxy_auth(p, req, "Proxy-Authenticate", "Proxy-Authorization", "INVITE", 1)) {
                                                ast_log(LOG_NOTICE, "Failed to authenticate on INVITE to '%s'\n", get_header(&p->initreq, "From"));
-                                               p->needdestroy = 1;
+                                               ast_set_flag(p, SIP_NEEDDESTROY);       
                                        }
                                }
                        } else if (!strcasecmp(msg, "BYE") || !strcasecmp(msg, "REFER")) {
@@ -6857,15 +7024,15 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                                        msg, ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr), ntohs(p->recv.sin_port));
                                if ((p->authtries > 1) || do_proxy_auth(p, req, "Proxy-Authenticate", "Proxy-Authorization", msg, 0)) {
                                        ast_log(LOG_NOTICE, "Failed to authenticate on %s to '%s'\n", msg, get_header(&p->initreq, "From"));
-                                       p->needdestroy = 1;
+                                       ast_set_flag(p, SIP_NEEDDESTROY);       
                                }
                        } else if (p->registry && !strcasecmp(msg, "REGISTER")) {
                                if ((p->authtries > 1) || do_register_auth(p, req, "Proxy-Authenticate", "Proxy-Authorization")) {
                                        ast_log(LOG_NOTICE, "Failed to authenticate on REGISTER to '%s' (tries '%d')\n", get_header(&p->initreq, "From"), p->authtries);
-                                       p->needdestroy = 1;
+                                       ast_set_flag(p, SIP_NEEDDESTROY);       
                                }
                        } else
-                               p->needdestroy = 1;
+                               ast_set_flag(p, SIP_NEEDDESTROY);       
 
                        break;
                case 501: /* Not Implemented */
@@ -6879,7 +7046,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                        if ((resp >= 300) && (resp < 700)) {
                                if ((option_verbose > 2) && (resp != 487))
                                        ast_verbose(VERBOSE_PREFIX_3 "Got SIP response %d \"%s\" back from %s\n", resp, rest, ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr));
-                               p->alreadygone = 1;
+                               ast_set_flag(p, SIP_ALREADYGONE);       
                                if (p->rtp) {
                                        /* Immediately stop RTP */
                                        ast_rtp_stop(p->rtp);
@@ -6900,7 +7067,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                        break;
                                case 487:
                                        /* channel now destroyed - dec the inUse counter */
-                                       if ( p->outgoing ) {
+                                       if (ast_test_flag(p, SIP_OUTGOING)) {
                                                update_user_counter(p, DEC_OUT_USE);
                                        }
                                        else {
@@ -6939,9 +7106,9 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                /* ACK on invite */
                                if (!strcasecmp(msg, "INVITE"))
                                        transmit_request(p, "ACK", seqno, 0, 0);
-                               p->alreadygone = 1;
+                               ast_set_flag(p, SIP_ALREADYGONE);       
                                if (!p->owner)
-                                       p->needdestroy = 1;
+                                       ast_set_flag(p, SIP_NEEDDESTROY);       
                        } else if ((resp >= 100) && (resp < 200)) {
                                if (!strcasecmp(msg, "INVITE")) {
                                        sip_cancel_destroy(p);
@@ -6971,7 +7138,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                                        msg, ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr), ntohs(p->recv.sin_port));
                                if ((p->authtries > 1) || do_proxy_auth(p, req, "Proxy-Authenticate", "Proxy-Authorization", msg, 0)) {
                                        ast_log(LOG_NOTICE, "Failed to authenticate on %s to '%s'\n", msg, get_header(&p->initreq, "From"));
-                                       p->needdestroy = 1;
+                                       ast_set_flag(p, SIP_NEEDDESTROY);       
                                }
                        }
                        break;
@@ -7201,7 +7368,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                if (p->icseq && (p->icseq > seqno)) {
                        ast_log(LOG_DEBUG, "Ignoring too old packet packet %d (expecting >= %d)\n", seqno, p->icseq);
                        return -1;
-               } else if (p->icseq && (p->icseq == seqno) && (strcasecmp(cmd, "CANCEL") || p->alreadygone)) {
+               } else if (p->icseq && (p->icseq == seqno) && (strcasecmp(cmd, "CANCEL") || ast_test_flag(p, SIP_ALREADYGONE))) {
                        /* ignore means "don't do anything with it" but still have to 
                           respond appropriately.  We do this if we receive a repeat of
                           the last sequence number  */
@@ -7223,7 +7390,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                /* Response to our request -- Do some sanity checks */  
                if (!p->initreq.headers) {
                        ast_log(LOG_DEBUG, "That's odd...  Got a response on a call we dont know about.\n");
-                       p->needdestroy = 1;
+                       ast_set_flag(p, SIP_NEEDDESTROY);       
                        return 0;
                } else if (p->ocseq && (p->ocseq < seqno)) {
                        ast_log(LOG_DEBUG, "Ignoring out of order response %d (expecting %d)\n", seqno, p->ocseq);
@@ -7257,9 +7424,9 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                /* Destroy if this OPTIONS was the opening request, but not if
                   it's in the middle of a normal call flow. */
                if (!p->lastinvite)
-                       p->needdestroy = 1;
+                       ast_set_flag(p, SIP_NEEDDESTROY);       
        } else if (!strcasecmp(cmd, "INVITE")) {
-               if (p->outgoing && p->owner && (p->owner->_state != AST_STATE_UP)) {
+               if (ast_test_flag(p, SIP_OUTGOING) && p->owner && (p->owner->_state != AST_STATE_UP)) {
                        /* This is a call to ourself.  Send ourselves an error code and stop
                           processing immediately, as SIP really has no good mechanism for
                           being able to call yourself */
@@ -7274,7 +7441,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                                ast_verbose("Using latest request as basis request\n");
                        sip_cancel_destroy(p);
                        /* This call is no longer outgoing if it ever was */
-                       p->outgoing = 0;
+                       ast_clear_flag(p, SIP_OUTGOING);
                        /* This also counts as a pending invite */
                        p->pendinginvite = seqno;
                        copy_request(&p->initreq, req);
@@ -7301,7 +7468,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                                                transmit_response(p, "403 Forbidden", req);
                                        else
                                                transmit_response_reliable(p, "403 Forbidden", req, 1);
-                                       p->needdestroy = 1;
+                                       ast_set_flag(p, SIP_NEEDDESTROY);       
                                }
                                return 0;
                        }
@@ -7314,7 +7481,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                        if (res) {
                                if (res < 0) {
                                        ast_log(LOG_DEBUG, "Failed to place call for user %s, too many calls\n", p->username);
-                                       p->needdestroy = 1;
+                                       ast_set_flag(p, SIP_NEEDDESTROY);       
                                }
                                return 0;
                        }
@@ -7338,7 +7505,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                                                transmit_response_reliable(p, "484 Address Incomplete", req, 1);
                                        update_user_counter(p,DEC_IN_USE);
                                }
-                               p->needdestroy = 1;
+                               ast_set_flag(p, SIP_NEEDDESTROY);               
                        } else {
                                /* If no extension was specified, use the s one */
                                if (ast_strlen_zero(p->exten))
@@ -7387,7 +7554,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                                                        transmit_response(p, "503 Unavailable", req);
                                                else
                                                        transmit_response_reliable(p, "503 Unavailable", req, 1);
-                                               p->alreadygone = 1;
+                                               ast_set_flag(p, SIP_ALREADYGONE);       
                                                /* Unlock locks so ast_hangup can do its magic */
                                                ast_mutex_unlock(&p->lock);
                                                ast_hangup(c);
@@ -7416,13 +7583,13 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                                transmit_response(p, "100 Trying", req);
                        }
                } else {
-                       if (p && !p->needdestroy) {
+                       if (p && !ast_test_flag(p, SIP_NEEDDESTROY)) {
                                ast_log(LOG_NOTICE, "Unable to create/find channel\n");
                                if (ignore)
                                        transmit_response(p, "503 Unavailable", req);
                                else
                                        transmit_response_reliable(p, "503 Unavailable", req, 1);
-                               p->needdestroy = 1;
+                               ast_set_flag(p, SIP_NEEDDESTROY);       
                        }
                }
        } else if (!strcasecmp(cmd, "REFER")) {
@@ -7444,7 +7611,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                                                ast_mutex_unlock(&p->refer_call->owner->lock);
                                        ast_mutex_unlock(&p->refer_call->lock);
                                        p->refer_call = NULL;
-                                       p->gotrefer = 1;
+                                       ast_set_flag(p, SIP_GOTREFER);  
                                } else {
                                        ast_log(LOG_DEBUG,"202 Accepted (blind)\n");
                                        c = p->owner;
@@ -7470,20 +7637,20 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                                                        ast_queue_hangup(p->owner);
                                                }
                                        }
-                                       p->gotrefer = 1;
+                                       ast_set_flag(p, SIP_GOTREFER);  
                                }
                                transmit_response(p, "202 Accepted", req);
                                transmit_notify_with_sipfrag(p, seqno);
                                /* Always increment on a BYE */
                                if (!nobye) {
                                        transmit_request_with_auth(p, "BYE", 0, 1, 1);
-                                       p->alreadygone = 1;
+                                       ast_set_flag(p, SIP_ALREADYGONE);       
                                }
                        }
                }
        } else if (!strcasecmp(cmd, "CANCEL")) {
                check_via(p, req);
-               p->alreadygone = 1;
+               ast_set_flag(p, SIP_ALREADYGONE);       
                if (p->rtp) {
                        /* Immediately stop RTP */
                        ast_rtp_stop(p->rtp);
@@ -7495,7 +7662,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                if (p->owner)
                        ast_queue_hangup(p->owner);
                else
-                       p->needdestroy = 1;
+                       ast_set_flag(p, SIP_NEEDDESTROY);       
                if (p->initreq.len > 0) {
                        if (!ignore)
                                transmit_response_reliable(p, "487 Request Terminated", &p->initreq, 1);
@@ -7506,7 +7673,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
        } else if (!strcasecmp(cmd, "BYE")) {
                copy_request(&p->initreq, req);
                check_via(p, req);
-               p->alreadygone = 1;
+               ast_set_flag(p, SIP_ALREADYGONE);       
                if (p->rtp) {
                        /* Immediately stop RTP */
                        ast_rtp_stop(p->rtp);
@@ -7539,7 +7706,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                } else if (p->owner)
                        ast_queue_hangup(p->owner);
                else
-                       p->needdestroy = 1;
+                       ast_set_flag(p, SIP_NEEDDESTROY);       
                transmit_response(p, "200 OK", req);
        } else if (!strcasecmp(cmd, "MESSAGE")) {
                if (!ignore) {
@@ -7554,7 +7721,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                        if (debug)
                                ast_verbose("Using latest SUBSCRIBE request as basis request\n");
                        /* This call is no longer outgoing if it ever was */
-                       p->outgoing = 0;
+                       ast_clear_flag(p, SIP_OUTGOING);
                        copy_request(&p->initreq, req);
                        check_via(p, req);
                } else if (debug)
@@ -7562,14 +7729,14 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
 
                if (!p->lastinvite) {
                        char mailbox[256]="";
-                       char rbox[256];
                        int found = 0;
+
                        /* Handle authentication if this is our first subscribe */
                        res = check_user_full(p, req, cmd, e, 0, sin, ignore, mailbox, sizeof(mailbox));
                        if (res) {
                                if (res < 0) {
                                        ast_log(LOG_NOTICE, "Failed to authenticate user %s for SUBSCRIBE\n", get_header(req, "From"));
-                                       p->needdestroy = 1;
+                                       ast_set_flag(p, SIP_NEEDDESTROY);       
                                }
                                return 0;
                        }
@@ -7584,7 +7751,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                                        transmit_response(p, "404 Not Found", req);
                                else
                                        transmit_response(p, "484 Address Incomplete", req);
-                               p->needdestroy = 1;
+                               ast_set_flag(p, SIP_NEEDDESTROY);       
                        } else {
                                /* Initialize tag */    
                                p->tag = rand();
@@ -7592,19 +7759,28 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                                    p->subscribed = 2;
                                else if (!strcmp(get_header(req, "Accept"), "application/simple-message-summary")) {
                                        /* Looks like they actually want a mailbox */
-                                       snprintf(rbox, sizeof(rbox), ",%s@%s,", p->exten, p->context);
-                                       if (strstr(mailbox, rbox))
+
+                                       /* At this point, we should check if they subscribe to a mailbox that
+                                         has the same extension as the peer or the mailbox id. If we configure
+                                         the context to be the same as a SIP domain, we could check mailbox
+                                         context as well. To be able to securely accept subscribes on mailbox
+                                         IDs, not extensions, we need to check the digest auth user to make
+                                         sure that the user has access to the mailbox.
+                                        
+                                         Since we do not act on this subscribe anyway, we might as well 
+                                         accept any authenticated peer with a mailbox definition in their 
+                                         config section.
+                                       
+                                       */
+                                       if (!ast_strlen_zero(mailbox)) {
                                                found++;
-                                       if (!found) {
-                                               snprintf(rbox, sizeof(rbox), ",%s,", p->exten);
-                                               if (strstr(mailbox, rbox))
-                                                       found++;
                                        }
+
                                        if (found)
                                                transmit_response(p, "200 OK", req);
                                        else {
                                                transmit_response(p, "403 Forbidden", req);
-                                               p->needdestroy = 1;
+                                               ast_set_flag(p, SIP_NEEDDESTROY);       
                                        }
                                        
                                } else
@@ -7618,10 +7794,10 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
 
                if (!ignore && p)
                        p->lastinvite = seqno;
-               if (p && !p->needdestroy) {
+               if (p && !ast_test_flag(p, SIP_NEEDDESTROY)) {
                    if (!(p->expiry = atoi(get_header(req, "Expires")))) {
                        transmit_response(p, "200 OK", req);
-                       p->needdestroy = 1;
+                       ast_set_flag(p, SIP_NEEDDESTROY);       
                        return 0;
                    }
                    /* The next line can be removed if the SNOM200 Expires bug is fixed */
@@ -7645,7 +7821,8 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                /* XXX we get NOTIFY's from some servers. WHY?? Maybe we should
                        look into this someday XXX */
                transmit_response(p, "200 OK", req);
-               if (!p->lastinvite) p->needdestroy = 1;
+               if (!p->lastinvite) 
+                       ast_set_flag(p, SIP_NEEDDESTROY);       
        } else if (!strcasecmp(cmd, "REGISTER")) {
                /* Use this as the basis */
                if (debug)
@@ -7671,7 +7848,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                        check_pendings(p);
                }
                if (!p->lastinvite && ast_strlen_zero(p->randdata))
-                       p->needdestroy = 1;
+                       ast_set_flag(p, SIP_NEEDDESTROY);       
        } else if (!strcasecmp(cmd, "SIP/2.0")) {
                extract_uri(p, req);
                while(*e && (*e < 33)) e++;
@@ -7686,7 +7863,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                        cmd, ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr));
                /* If this is some new method, and we don't have a call, destroy it now */
                if (!p->initreq.headers)
-                       p->needdestroy = 1;
+                       ast_set_flag(p, SIP_NEEDDESTROY);       
        }
        return 0;
 }
@@ -7778,19 +7955,16 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer)
        
        /* Return now if it's the same thing we told them last time */
        if (((newmsgs << 8) | (oldmsgs)) == peer->lastmsgssent) {
-               ast_mutex_unlock(&peerl.lock);
                return 0;
        }
        
        p = sip_alloc(NULL, NULL, 0);
        if (!p) {
                ast_log(LOG_WARNING, "Unable to build sip pvt data for MWI\n");
-               ast_mutex_unlock(&peerl.lock);
                return -1;
        }
        strncpy(name, peer->name, sizeof(name) - 1);
        peer->lastmsgssent = ((newmsgs << 8) | (oldmsgs));
-       ast_mutex_unlock(&peerl.lock);
        if (create_addr(p, name)) {
                /* Maybe they're not registered, etc. */
                sip_destroy(p);
@@ -7800,13 +7974,13 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer)
        if (ast_sip_ouraddrfor(&p->sa.sin_addr,&p->ourip))
                memcpy(&p->ourip, &__ourip, sizeof(p->ourip));
        /* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
-       if (p->nat & SIP_NAT_RFC3581)
+       if (ast_test_flag(p, SIP_NAT) & SIP_NAT_RFC3581)
                snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
        else /* UNIDEN UIP200 bug */
                snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
        build_callid(p->callid, sizeof(p->callid), p->ourip, p->fromdomain);
        /* Send MWI */
-       p->outgoing = 1;
+       ast_set_flag(p, SIP_OUTGOING);
        transmit_notify_with_mwi(p, newmsgs, oldmsgs);
        sip_scheddestroy(p, 15000);
        return 0;
@@ -7817,7 +7991,7 @@ static void *do_monitor(void *data)
 {
        int res;
        struct sip_pvt *sip;
-       struct sip_peer *peer;
+       struct sip_peer *peer = NULL;
        time_t t;
        int fastrestart =0;
        int lastpeernum = -1;
@@ -7874,7 +8048,7 @@ restartsearch:
                                        }
                                }
                        }
-                       if (sip->needdestroy && !sip->packets && !sip->owner) {
+                       if (ast_test_flag(sip, SIP_NEEDDESTROY) && !sip->packets && !sip->owner) {
                                ast_mutex_unlock(&sip->lock);
                                __sip_destroy(sip, 1);
                                goto restartsearch;
@@ -7906,26 +8080,27 @@ restartsearch:
                        ast_sched_runq(sched);
 
                /* needs work to send mwi to realtime peers */
-               ast_mutex_lock(&peerl.lock);
-               peer = peerl.peers;
                time(&t);
                fastrestart = 0;
                curpeernum = 0;
-               while(peer) {
-                       if ((curpeernum > lastpeernum) && !ast_strlen_zero(peer->mailbox) && ((t - peer->lastmsgcheck) > global_mwitime)) {
-                               sip_send_mwi_to_peer(peer);
+               ASTOBJ_CONTAINER_TRAVERSE(&peerl, do {
+                       if ((curpeernum > lastpeernum) && !ast_strlen_zero(iterator->mailbox) && ((t - iterator->lastmsgcheck) > global_mwitime)) {
                                fastrestart = 1;
                                lastpeernum = curpeernum;
+                               peer = ASTOBJ_REF(iterator);
                                break;
-                       }
+                       };
                        curpeernum++;
-                       peer = peer->next;
-               }
-               /* Remember, sip_send_mwi_to_peer releases the lock if we've called it */
-               if (!peer) {
+               } while (0)
+               );
+               if (peer) {
+                       ASTOBJ_WRLOCK(peer);
+                       sip_send_mwi_to_peer(peer);
+                       ASTOBJ_UNLOCK(peer);
+                       ASTOBJ_UNREF(peer,sip_destroy_peer);
+               } else {
                        /* Reset where we come from */
                        lastpeernum = -1;
-                       ast_mutex_unlock(&peerl.lock);
                }
                ast_mutex_unlock(&monlock);
        }
@@ -8030,7 +8205,7 @@ static int sip_poke_peer(struct sip_peer *peer)
        if (ast_sip_ouraddrfor(&p->sa.sin_addr,&p->ourip))
                memcpy(&p->ourip, &__ourip, sizeof(p->ourip));
        /* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
-       if (p->nat & SIP_NAT_RFC3581)
+       if (ast_test_flag(p, SIP_NAT) & SIP_NAT_RFC3581)
                snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
        else
                snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
@@ -8039,7 +8214,7 @@ static int sip_poke_peer(struct sip_peer *peer)
        if (peer->pokeexpire > -1)
                ast_sched_del(sched, peer->pokeexpire);
        p->peerpoke = peer;
-       p->outgoing = 1;
+       ast_set_flag(p, SIP_OUTGOING);
 #ifdef VOCAL_DATA_HACK
        strncpy(p->username, "__VOCAL_DATA_SHOULD_READ_THE_SIP_SPEC__", sizeof(p->username) - 1);
        transmit_invite(p, "INVITE", 0, NULL, NULL, NULL,NULL,NULL, 0, 1);
@@ -8077,7 +8252,6 @@ static int sip_devicestate(void *data)
                ext = NULL;
        }
 
-       ast_mutex_lock(&peerl.lock);
        p = find_peer(host, NULL);
        if (p) {
                found++;
@@ -8088,16 +8262,14 @@ static int sip_devicestate(void *data)
                        res = AST_DEVICE_UNKNOWN;
                }
        }
-       ast_mutex_unlock(&peerl.lock);
        if (!p && !found) {
                hp = ast_gethostbyname(host, &ahp);
                if (hp)
                        res = AST_DEVICE_UNKNOWN;
        }
 
-       if (p && p->temponly) {
-               destroy_peer(p);
-       }
+       if (p)
+               ASTOBJ_UNREF(p,sip_destroy_peer);
        return res;
 }
 
@@ -8157,7 +8329,7 @@ static struct ast_channel *sip_request(const char *type, int format, void *data,
        if (ast_sip_ouraddrfor(&p->sa.sin_addr,&p->ourip))
                memcpy(&p->ourip, &__ourip, sizeof(p->ourip));
        /* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
-       if (p->nat & SIP_NAT_RFC3581)
+       if (ast_test_flag(p, SIP_NAT) & SIP_NAT_RFC3581)
                snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
        else /* UNIDEN bug */
                snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
@@ -8185,6 +8357,82 @@ static struct ast_channel *sip_request(const char *type, int format, void *data,
        return tmpc;
 }
 
+/*--- handle_common_options: Handle flag-type options common to users and peers ---*/
+static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask, struct ast_variable *v)
+{
+       int res = 0;
+
+       if (!strcasecmp(v->name, "trustrpid")) {
+               ast_set_flag(mask, SIP_TRUSTRPID);
+               ast_set2_flag(flags, ast_true(v->value), SIP_TRUSTRPID);
+               res = 1;
+       } else if (!strcasecmp(v->name, "useclientcode")) {
+               ast_set_flag(mask, SIP_USECLIENTCODE);
+               ast_set2_flag(flags, ast_true(v->value), SIP_USECLIENTCODE);
+               res = 1;
+       } else if (!strcasecmp(v->name, "dtmfmode")) {
+               ast_set_flag(mask, SIP_DTMF);
+               ast_clear_flag(flags, SIP_DTMF);
+               if (!strcasecmp(v->value, "inband"))
+                       ast_set_flag(flags, SIP_DTMF_INBAND);
+               else if (!strcasecmp(v->value, "rfc2833"))
+                       ast_set_flag(flags, SIP_DTMF_RFC2833);
+               else if (!strcasecmp(v->value, "info"))
+                       ast_set_flag(flags, SIP_DTMF_INFO);
+               else {
+                       ast_log(LOG_WARNING, "Unknown dtmf mode '%s' on line %d, using rfc2833\n", v->value, v->lineno);
+                       ast_set_flag(flags, SIP_DTMF_RFC2833);
+               }
+       } else if (!strcasecmp(v->name, "nat")) {
+               ast_set_flag(mask, SIP_NAT);
+               ast_clear_flag(flags, SIP_NAT);
+               if (!strcasecmp(v->value, "never"))
+                       ast_set_flag(flags, SIP_NAT_NEVER);
+               else if (!strcasecmp(v->value, "route"))
+                       ast_set_flag(flags, SIP_NAT_ROUTE);
+               else if (ast_true(v->value))
+                       ast_set_flag(flags, SIP_NAT_ALWAYS);
+               else
+                       ast_set_flag(flags, SIP_NAT_RFC3581);
+       } else if (!strcasecmp(v->name, "canreinvite")) {
+               ast_set_flag(mask, SIP_REINVITE);
+               ast_clear_flag(flags, SIP_REINVITE);
+               if (!strcasecmp(v->value, "update"))
+                       ast_set_flag(flags, SIP_REINVITE_UPDATE | SIP_CAN_REINVITE);
+               else
+                       ast_set2_flag(flags, ast_true(v->value), SIP_CAN_REINVITE);
+       } else if (!strcasecmp(v->name, "insecure")) {
+               ast_set_flag(mask, SIP_INSECURE);
+               ast_clear_flag(flags, SIP_INSECURE);
+               if (!strcasecmp(v->value, "very"))
+                       ast_set_flag(flags, SIP_INSECURE_VERY);
+               else
+                       ast_set2_flag(flags, ast_true(v->value), SIP_INSECURE_NORMAL);
+       } else if (!strcasecmp(v->name, "progressinband")) {
+               ast_set_flag(mask, SIP_PROG_INBAND);
+               ast_clear_flag(flags, SIP_PROG_INBAND);
+               if (strcasecmp(v->value, "never"))
+                       ast_set_flag(flags, SIP_PROG_INBAND_NO);
+               else if (ast_true(v->value))
+                       ast_set_flag(flags, SIP_PROG_INBAND_YES);
+#ifdef OSP_SUPPORT
+       } else if (!strcasecmp(v->name, "ospauth")) {
+               ast_set_flag(mask, SIP_OSPAUTH);
+               ast_clear_flag(flags, SIP_OSPAUTH);
+               if (!strcasecmp(v->value, "exclusive"))
+                       ast_set_flag(flags, SIP_OSPAUTH_EXCLUSIVE);
+               else
+                       ast_set2_flag(flags, ast_true(v->value), SIP_OSPAUTH_YES);
+#endif
+       } else if (!strcasecmp(v->name, "promiscredir")) {
+               ast_set_flag(mask, SIP_PROMISCREDIR);
+               ast_set2_flag(flags, ast_true(v->value), SIP_PROMISCREDIR);
+               res = 1;
+       }
+
+       return res;
+}
+
 /*--- build_user: Initiate a SIP user structure from sip.conf ---*/
 static struct sip_user *build_user(const char *name, struct ast_variable *v)
 {
@@ -8196,27 +8444,31 @@ static struct sip_user *build_user(const char *name, struct ast_variable *v)
 
        user = (struct sip_user *)malloc(sizeof(struct sip_user));
        if (user) {
+               struct ast_flags userflags = {(0)};
+               struct ast_flags mask = {(0)};
+
                memset(user, 0, sizeof(struct sip_user));
+               suserobjs++;
+               ASTOBJ_INIT(user);
                strncpy(user->name, name, sizeof(user->name)-1);
                oldha = user->ha;
                user->ha = NULL;
                /* set the usage flag to a sane staring value*/
                user->inUse = 0;
                user->outUse = 0;
+               ast_copy_flags(user, &global_flags, SIP_PROMISCREDIR | SIP_TRUSTRPID | SIP_USECLIENTCODE | SIP_DTMF | SIP_NAT | SIP_REINVITE | SIP_INSECURE | SIP_PROG_INBAND | SIP_OSPAUTH);
                user->capability = global_capability;
-               user->canreinvite = global_canreinvite;
-               user->trustrpid = global_trustrpid;
-               user->dtmfmode = global_dtmfmode;
-               user->progressinband = global_progressinband;
                user->prefs = prefs;
-#ifdef OSP_SUPPORT
-               user->ospauth = global_ospauth;
-#endif
                /* set default context */
                strncpy(user->context, default_context, sizeof(user->context)-1);
                strncpy(user->language, default_language, sizeof(user->language)-1);
                strncpy(user->musicclass, global_musicclass, sizeof(user->musicclass)-1);
                while(v) {
+                       if (handle_common_options(&userflags, &mask, v)) {
+                               v = v->next;
+                               continue;
+                       }
+
                        if (!strcasecmp(v->name, "context")) {
                                strncpy(user->context, v->value, sizeof(user->context) - 1);
                        } else if (!strcasecmp(v->name, "setvar")) {
@@ -8237,33 +8489,6 @@ static struct sip_user *build_user(const char *name, struct ast_variable *v)
                                strncpy(user->secret, v->value, sizeof(user->secret)-1); 
                        } else if (!strcasecmp(v->name, "md5secret")) {
                                strncpy(user->md5secret, v->value, sizeof(user->md5secret)-1);
-                       } else if (!strcasecmp(v->name, "promiscredir")) {
-                               user->promiscredir = ast_true(v->value);
-                       } else if (!strcasecmp(v->name, "dtmfmode")) {
-                               if (!strcasecmp(v->value, "inband"))
-                                       user->dtmfmode=SIP_DTMF_INBAND;
-                               else if (!strcasecmp(v->value, "rfc2833"))
-                                       user->dtmfmode = SIP_DTMF_RFC2833;
-                               else if (!strcasecmp(v->value, "info"))
-                                       user->dtmfmode = SIP_DTMF_INFO;
-                               else {
-                                       ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value);
-                                       user->dtmfmode = SIP_DTMF_RFC2833;
-                               }
-                       } else if (!strcasecmp(v->name, "canreinvite")) {
-                               if (!strcasecmp(v->value, "update"))
-                                       user->canreinvite = REINVITE_UPDATE;
-                               else
-                                       user->canreinvite = ast_true(v->value);
-                       } else if (!strcasecmp(v->name, "nat")) {
-                               if (!strcasecmp(v->value, "never"))
-                                       user->nat = SIP_NAT_NEVER;
-                               else if (!strcasecmp(v->value, "route"))
-                                       user->nat = SIP_NAT_ROUTE;
-                               else if (ast_true(v->value))
-                                       user->nat = SIP_NAT_ALWAYS;
-                               else
-                                       user->nat = SIP_NAT_RFC3581;
                        } else if (!strcasecmp(v->name, "callerid")) {
                                ast_callerid_split(v->value, user->cid_name, sizeof(user->cid_name), user->cid_num, sizeof(user->cid_num));
                        } else if (!strcasecmp(v->name, "callgroup")) {
@@ -8292,39 +8517,18 @@ static struct sip_user *build_user(const char *name, struct ast_variable *v)
                                        user->amaflags = format;
                                }
                        } else if (!strcasecmp(v->name, "allow")) {
-                               ast_parse_allow_deny(&user->prefs, &user->capability, v->value, 1);
+                               ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 1);
                        } else if (!strcasecmp(v->name, "disallow")) {
-                               ast_parse_allow_deny(&user->prefs, &user->capability, v->value, 0);
-                       } else if (!strcasecmp(v->name, "insecure")) {
-                               user->insecure = ast_true(v->value);
+                               ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 0);
                        } else if (!strcasecmp(v->name, "callingpres")) {
                                user->callingpres = atoi(v->value);
-                       } else if (!strcasecmp(v->name, "trustrpid")) {
-                               user->trustrpid = ast_true(v->value);
-                       } else if (!strcasecmp(v->name, "useclientcode")) {
-                               user->useclientcode = ast_true(v->value);
-                       } else if (!strcasecmp(v->name, "progressinband")) {
-                               if (!strcasecmp(v->value, "never"))
-                                       user->progressinband = 0;
-                               else if (ast_true(v->value))
-                                       user->progressinband = 2;
-                               else
-                                       user->progressinband = 1;
-#ifdef OSP_SUPPORT
-                       } else if (!strcasecmp(v->name, "ospauth")) {
-                               if (!strcasecmp(v->value, "exclusive")) {
-                                       user->ospauth = 2;
-                               } else if (ast_true(v->value)) {
-                                       user->ospauth = 1;
-                               } else
-                                       user->ospauth = 0;
-#endif
                        }
                        /*else if (strcasecmp(v->name,"type"))
                         *      ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
                         */
                        v = v->next;
                }
+               ast_copy_flags(user, &userflags, mask.flags);
        }
        ast_free_ha(oldha);
        return user;
@@ -8339,9 +8543,13 @@ static struct sip_peer *temp_peer(char *name)
                return NULL;
 
        memset(peer, 0, sizeof(struct sip_peer));
+       apeerobjs++;
+       ASTOBJ_INIT(peer);
+
        peer->expire = -1;
        peer->pokeexpire = -1;
        strncpy(peer->name, name, sizeof(peer->name)-1);
+       ast_copy_flags(peer, &global_flags, SIP_PROMISCREDIR | SIP_USEREQPHONE | SIP_TRUSTRPID | SIP_USECLIENTCODE | SIP_DTMF | SIP_NAT | SIP_REINVITE | SIP_INSECURE | SIP_PROG_INBAND | SIP_OSPAUTH);
        strncpy(peer->context, default_context, sizeof(peer->context)-1);
        strncpy(peer->language, default_language, sizeof(peer->language)-1);
        strncpy(peer->musicclass, global_musicclass, sizeof(peer->musicclass)-1);
@@ -8349,22 +8557,11 @@ static struct sip_peer *temp_peer(char *name)
        peer->addr.sin_family = AF_INET;
        peer->expiry = expiry;
        peer->capability = global_capability;
-       /* Assume can reinvite */
-       peer->canreinvite = global_canreinvite;
-       peer->dtmfmode = global_dtmfmode;
-       peer->promiscredir = global_promiscredir;
-       peer->usereqphone = global_usereqphone;
-       peer->nat = global_nat;
        peer->rtptimeout = global_rtptimeout;
        peer->rtpholdtimeout = global_rtpholdtimeout;
-       peer->selfdestruct = 1;
-       peer->dynamic = 1;
-       peer->trustrpid = global_trustrpid;
-       peer->progressinband = global_progressinband;
+       ast_set_flag(peer, SIP_SELFDESTRUCT);
+       ast_set_flag(peer, SIP_DYNAMIC);
        peer->prefs = prefs;
-#ifdef OSP_SUPPORT
-       peer->ospauth = global_ospauth;
-#endif
        reg_source_db(peer);
        return peer;
 }
@@ -8372,49 +8569,41 @@ static struct sip_peer *temp_peer(char *name)
 /*--- build_peer: Build peer from config file ---*/
 static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int temponly)
 {
-       struct sip_peer *peer;
-       struct sip_peer *prev;
+       struct sip_peer *peer = NULL;
        struct ast_ha *oldha = NULL;
        int maskfound=0;
        int obproxyfound=0;
        int found=0;
 
-       prev = NULL;
-       ast_mutex_lock(&peerl.lock);
-       if (temponly) {
-               peer = NULL;
-       } else {
-               peer = peerl.peers;
-               while(peer) {
-                       if (!strcasecmp(peer->name, name)) {    
-                               break;
-                       }
-                       prev = peer;
-                       peer = peer->next;
-               }
-       }
+       if (!temponly)
+               /* Note we do NOT use find_peer here, to avoid realtime recursion */
+               peer = ASTOBJ_CONTAINER_FIND_UNLINK(&peerl, name);
+
        if (peer) {
+               /* Already in the list, remove it and it will be added back (or FREE'd)  */
                found++;
-               /* Already in the list, remove it and it will be added back (or FREE'd) */
-               if (prev) {
-                       prev->next = peer->next;
-               } else {
-                       peerl.peers = peer->next;
-               }
-               ast_mutex_unlock(&peerl.lock);
        } else {
-               ast_mutex_unlock(&peerl.lock);
                peer = malloc(sizeof(struct sip_peer));
                if (peer) {
                        memset(peer, 0, sizeof(struct sip_peer));
+                       if (temponly)
+                               rpeerobjs++;
+                       else
+                               speerobjs++;
+                       ASTOBJ_INIT(peer);
                        peer->expire = -1;
                        peer->pokeexpire = -1;
                }
        }
+       /* Note that our peer HAS had its reference count incrased */
        if (peer) {
+               struct ast_flags peerflags = {(0)};
+               struct ast_flags mask = {(0)};
+
                peer->lastmsgssent = -1;
                if (!found) {
-                       strncpy(peer->name, name, sizeof(peer->name)-1);
+                       if (name)
+                               strncpy(peer->name, name, sizeof(peer->name)-1);
                        strncpy(peer->context, default_context, sizeof(peer->context)-1);
                        strncpy(peer->language, default_language, sizeof(peer->language)-1);
                        strncpy(peer->musicclass, global_musicclass, sizeof(peer->musicclass)-1);
@@ -8422,73 +8611,45 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int
                        peer->addr.sin_family = AF_INET;
                        peer->defaddr.sin_family = AF_INET;
                        peer->expiry = expiry;
-                       peer->usereqphone = global_usereqphone;
+                       ast_copy_flags(peer, &global_flags, SIP_USEREQPHONE);
                }
                peer->prefs = prefs;
                oldha = peer->ha;
                peer->ha = NULL;
                peer->addr.sin_family = AF_INET;
+               ast_copy_flags(peer, &global_flags, SIP_PROMISCREDIR | SIP_TRUSTRPID | SIP_USECLIENTCODE | SIP_DTMF | SIP_REINVITE | SIP_INSECURE | SIP_PROG_INBAND | SIP_OSPAUTH);
                peer->capability = global_capability;
-               /* Assume can reinvite */
-               peer->canreinvite = global_canreinvite;
                peer->rtptimeout = global_rtptimeout;
                peer->rtpholdtimeout = global_rtpholdtimeout;
-               peer->dtmfmode = global_dtmfmode;
-               peer->promiscredir = global_promiscredir;
-               peer->trustrpid = global_trustrpid;
-               peer->progressinband = global_progressinband;
-#ifdef OSP_SUPPORT
-               peer->ospauth = global_ospauth;
-#endif
                while(v) {
-                       if (!strcasecmp(v->name, "secret")) 
+                       if (handle_common_options(&peerflags, &mask, v)) {
+                               v = v->next;
+                               continue;
+                       }
+
+                       if (!strcasecmp(v->name, "name"))
+                               strncpy(peer->name, v->value, sizeof(peer->name)-1);
+                       else if (!strcasecmp(v->name, "secret")) 
                                strncpy(peer->secret, v->value, sizeof(peer->secret)-1);
                        else if (!strcasecmp(v->name, "md5secret")) 
                                strncpy(peer->md5secret, v->value, sizeof(peer->md5secret)-1);
-                       else if (!strcasecmp(v->name, "canreinvite")) {
-                               if (!strcasecmp(v->value, "update"))
-                                       peer->canreinvite = REINVITE_UPDATE;
-                               else
-                                       peer->canreinvite = ast_true(v->value);
-                       } else if (!strcasecmp(v->name, "callerid")) {
+                       else if (!strcasecmp(v->name, "callerid")) {
                                ast_callerid_split(v->value, peer->cid_name, sizeof(peer->cid_name), peer->cid_num, sizeof(peer->cid_num));
-                       } else if (!strcasecmp(v->name, "nat")) {
-                               if (!strcasecmp(v->value, "rfc3581"))
-                                       peer->nat = SIP_NAT_RFC3581;
-                               else if (!strcasecmp(v->value, "route")) 
-                                       peer->nat = SIP_NAT_ROUTE;
-                               else if (ast_true(v->value))
-                                       peer->nat = SIP_NAT_ALWAYS;
-                               else
-                                       peer->nat = SIP_NAT_NEVER;
                        } else if (!strcasecmp(v->name, "context"))
                                strncpy(peer->context, v->value, sizeof(peer->context)-1);
                        else if (!strcasecmp(v->name, "fromdomain"))
                                strncpy(peer->fromdomain, v->value, sizeof(peer->fromdomain)-1);
                        else if (!strcasecmp(v->name, "usereqphone"))
-                               peer->usereqphone = ast_true(v->value);
-                       else if (!strcasecmp(v->name, "promiscredir"))
-                               peer->promiscredir = ast_true(v->value);
+                               ast_set2_flag(peer, ast_true(v->value), SIP_USEREQPHONE);
                        else if (!strcasecmp(v->name, "fromuser"))
                                strncpy(peer->fromuser, v->value, sizeof(peer->fromuser)-1);
-            else if (!strcasecmp(v->name, "dtmfmode")) {
-                               if (!strcasecmp(v->value, "inband"))
-                                       peer->dtmfmode=SIP_DTMF_INBAND;
-                               else if (!strcasecmp(v->value, "rfc2833"))
-                                       peer->dtmfmode = SIP_DTMF_RFC2833;
-                               else if (!strcasecmp(v->value, "info"))
-                                       peer->dtmfmode = SIP_DTMF_INFO;
-                               else {
-                                       ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value);
-                                       peer->dtmfmode = SIP_DTMF_RFC2833;
-                               }
-                       } else if (!strcasecmp(v->name, "host") || !strcasecmp(v->name, "outboundproxy")) {
+                       else if (!strcasecmp(v->name, "host") || !strcasecmp(v->name, "outboundproxy")) {
                                if (!strcasecmp(v->value, "dynamic")) {
                                        if (!strcasecmp(v->name, "outboundproxy") || obproxyfound) {
                                                ast_log(LOG_WARNING, "You can't have a dynamic outbound proxy, you big silly head at line %d.\n", v->lineno);
                                        } else {
                                                /* They'll register with us */
-                                               peer->dynamic = 1;
+                                               ast_set_flag(peer, SIP_DYNAMIC);
                                                if (!found) {
                                                        /* Initialize stuff iff we're not found, otherwise
                                                           we keep going with what we had */
@@ -8505,10 +8666,10 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int
                                        if (peer->expire > -1)
                                                ast_sched_del(sched, peer->expire);
                                        peer->expire = -1;
-                                       peer->dynamic = 0;
+                                       ast_clear_flag(peer, SIP_DYNAMIC);      
                                        if (!obproxyfound || !strcasecmp(v->name, "outboundproxy")) {
                                                if (ast_get_ip_or_srv(&peer->addr, v->value, "_sip._udp")) {
-                                                       destroy_peer(peer);
+                                                       ASTOBJ_DESTROY(peer, sip_destroy_peer);
                                                        return NULL;
                                                }
                                        }
@@ -8521,7 +8682,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int
                                        inet_aton("255.255.255.255", &peer->mask);
                        } else if (!strcasecmp(v->name, "defaultip")) {
                                if (ast_get_ip(&peer->defaddr, v->value)) {
-                                       destroy_peer(peer);
+                                       ASTOBJ_DESTROY(peer, sip_destroy_peer);
                                        return NULL;
                                }
                        } else if (!strcasecmp(v->name, "permit") ||
@@ -8531,7 +8692,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int
                                maskfound++;
                                inet_aton(v->value, &peer->mask);
                        } else if (!strcasecmp(v->name, "port")) {
-                               if (peer->dynamic)
+                               if (ast_test_flag(peer, SIP_DYNAMIC))
                                        peer->defaddr.sin_port = htons(atoi(v->value));
                                else
                                        peer->addr.sin_port = htons(atoi(v->value));
@@ -8550,16 +8711,9 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int
                        } else if (!strcasecmp(v->name, "pickupgroup")) {
                                peer->pickupgroup = ast_get_group(v->value);
                        } else if (!strcasecmp(v->name, "allow")) {
-                               ast_parse_allow_deny(&peer->prefs, &peer->capability, v->value, 1);
+                               ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 1);
                        } else if (!strcasecmp(v->name, "disallow")) {
-                               ast_parse_allow_deny(&peer->prefs, &peer->capability, v->value, 0);
-                       } else if (!strcasecmp(v->name, "insecure")) {
-                               if (!strcasecmp(v->value, "very")) {
-                                       peer->insecure = 2;
-                               } else if (ast_true(v->value))
-                                       peer->insecure = 1;
-                               else
-                                       peer->insecure = 0;
+                               ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 0);
                        } else if (!strcasecmp(v->name, "rtptimeout")) {
                                if ((sscanf(v->value, "%d", &peer->rtptimeout) != 1) || (peer->rtptimeout < 0)) {
                                        ast_log(LOG_WARNING, "'%s' is not a valid RTP hold time at line %d.  Using default.\n", v->value, v->lineno);
@@ -8579,35 +8733,16 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int
                                        ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of sip.conf\n", peer->name, v->lineno);
                                        peer->maxms = 0;
                                }
-                       } else if (!strcasecmp(v->name, "useclientcode")) {
-                               peer->useclientcode = ast_true(v->value);
-                       } else if (!strcasecmp(v->name, "trustrpid")) {
-                               peer->trustrpid = ast_true(v->value);
-                       } else if (!strcasecmp(v->name, "progressinband")) {
-                               if (!strcasecmp(v->value, "never"))
-                                       peer->progressinband = 0;
-                               else if (ast_true(v->value))
-                                       peer->progressinband = 2;
-                               else
-                                       peer->progressinband = 1;
-#ifdef OSP_SUPPORT
-                       } else if (!strcasecmp(v->name, "ospauth")) {
-                               if (!strcasecmp(v->value, "exclusive")) {
-                                       peer->ospauth = 2;
-                               } else if (ast_true(v->value)) {
-                                       peer->ospauth = 1;
-                               } else
-                                       peer->ospauth = 0;
-#endif
                        }
                        /* else if (strcasecmp(v->name,"type"))
                         *      ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
                         */
                        v=v->next;
                }
-               if (!found && peer->dynamic)
+               ast_copy_flags(peer, &peerflags, mask.flags);
+               if (!found && ast_test_flag(peer, SIP_DYNAMIC))
                        reg_source_db(peer);
-               peer->delme = 0;
+               ASTOBJ_UNMARK(peer);
        }
        ast_free_ha(oldha);
        return peer;
@@ -8632,7 +8767,7 @@ static int reload_config(void)
        int format;
        int oldport = ntohs(bindaddr.sin_port);
        char iabuf[INET_ADDRSTRLEN];
-
+       struct ast_flags dummy;
        
        if (gethostname(ourhost, sizeof(ourhost))) {
                ast_log(LOG_WARNING, "Unable to get hostname, SIP disabled\n");
@@ -8654,10 +8789,12 @@ static int reload_config(void)
        memset(&prefs, 0 , sizeof(struct ast_codec_pref));
 
        /* Initialize some reasonable defaults at SIP reload */
-       global_nat = SIP_NAT_RFC3581;
        strncpy(default_context, DEFAULT_CONTEXT, sizeof(default_context) - 1);
        default_language[0] = '\0';
        default_fromdomain[0] = '\0';
+       externhost[0] = '\0';
+       externexpire = 0;
+       externrefresh = 10;
        strncpy(default_useragent, DEFAULT_USERAGENT, sizeof(default_useragent) - 1);
        strncpy(default_notifymime, DEFAULT_NOTIFYMIME, sizeof(default_notifymime) - 1);
        global_realm[sizeof(global_realm)-1] = '\0';
@@ -8666,7 +8803,6 @@ static int reload_config(void)
        memset(&outboundproxyip, 0, sizeof(outboundproxyip));
        outboundproxyip.sin_port = htons(DEFAULT_SIP_PORT);
        outboundproxyip.sin_family = AF_INET;   /* Type of address: IPv4 */
-       global_canreinvite = REINVITE_INVITE;
        videosupport = 0;
        compactheaders = 0;
        relaxdtmf = 0;
@@ -8674,10 +8810,10 @@ static int reload_config(void)
        global_rtptimeout = 0;
        global_rtpholdtimeout = 0;
        pedanticsipchecking = 0;
-       global_dtmfmode = SIP_DTMF_RFC2833;
-       global_promiscredir = 0;
-       global_trustrpid = 0;
-       global_progressinband = 0;
+       ast_clear_flag(&global_flags, AST_FLAGS_ALL);
+       ast_set_flag(&global_flags, SIP_DTMF_RFC2833);
+       ast_set_flag(&global_flags, SIP_NAT_RFC3581);
+       ast_set_flag(&global_flags, SIP_CAN_REINVITE);
        global_mwitime = DEFAULT_MWITIME;
        srvlookup = 0;
        autocreatepeer = 0;
@@ -8685,13 +8821,14 @@ static int reload_config(void)
        tos = 0;
        expiry = DEFAULT_EXPIRY;
 
-#ifdef OSP_SUPPORT
-       global_ospauth = 0;             /* OSP = Open Settlement Protocol */
-#endif
-       
        /* Read the [general] config section of sip.conf (or from realtime config) */
        v = ast_variable_browse(cfg, "general");
        while(v) {
+               if (handle_common_options(&global_flags, &dummy, v)) {
+                       v = v->next;
+                       continue;
+               }
+
                /* Create the interface list */
                if (!strcasecmp(v->name, "context")) {
                        strncpy(default_context, v->value, sizeof(default_context)-1);
@@ -8703,22 +8840,9 @@ static int reload_config(void)
                        ast_log(LOG_DEBUG, "Setting User Agent Name to %s\n",
                                default_useragent);
                } else if (!strcasecmp(v->name, "usereqphone")) {
-                       global_usereqphone = ast_true(v->value);
+                       ast_set2_flag((&global_flags), ast_true(v->value), SIP_USEREQPHONE);    
                } else if (!strcasecmp(v->name, "relaxdtmf")) {
                        relaxdtmf = ast_true(v->value);
-               } else if (!strcasecmp(v->name, "promiscredir")) {
-                       global_promiscredir = ast_true(v->value);
-               } else if (!strcasecmp(v->name, "dtmfmode")) {
-                       if (!strcasecmp(v->value, "inband"))
-                               global_dtmfmode=SIP_DTMF_INBAND;
-                       else if (!strcasecmp(v->value, "rfc2833"))
-                               global_dtmfmode = SIP_DTMF_RFC2833;
-                       else if (!strcasecmp(v->value, "info"))
-                               global_dtmfmode = SIP_DTMF_INFO;
-                       else {
-                               ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value);
-                               global_dtmfmode = SIP_DTMF_RFC2833;
-                       }
                } else if (!strcasecmp(v->name, "checkmwi")) {
                        if ((sscanf(v->value, "%d", &global_mwitime) != 1) || (global_mwitime < 0)) {
                                ast_log(LOG_WARNING, "'%s' is not a valid MWI time setting at line %d.  Using default (10).\n", v->value, v->lineno);
@@ -8753,15 +8877,6 @@ static int reload_config(void)
                        strncpy(default_callerid, v->value, sizeof(default_callerid)-1);
                } else if (!strcasecmp(v->name, "fromdomain")) {
                        strncpy(default_fromdomain, v->value, sizeof(default_fromdomain)-1);
-               } else if (!strcasecmp(v->name, "nat")) {
-                       if (!strcasecmp(v->value, "rfc3581"))
-                               global_nat = SIP_NAT_RFC3581;
-                       else if (!strcasecmp(v->value, "route"))
-                               global_nat = SIP_NAT_ROUTE;
-                       else if (ast_true(v->value))
-                               global_nat = SIP_NAT_ALWAYS;
-                       else
-                               global_nat = SIP_NAT_NEVER;
                } else if (!strcasecmp(v->name, "outboundproxy")) {
                        if (ast_get_ip_or_srv(&outboundproxyip, v->value, "_sip._udp") < 0)
                                ast_log(LOG_WARNING, "Unable to locate host '%s'\n", v->value);
@@ -8773,31 +8888,8 @@ static int reload_config(void)
                        autocreatepeer = ast_true(v->value);
                } else if (!strcasecmp(v->name, "srvlookup")) {
                        srvlookup = ast_true(v->value);
-               } else if (!strcasecmp(v->name, "trustrpid")) {
-                       global_trustrpid = ast_true(v->value);
-               } else if (!strcasecmp(v->name, "progressinband")) {
-                       if (!strcasecmp(v->value, "never"))
-                               global_progressinband = 0;
-                       else if (ast_true(v->value))
-                               global_progressinband = 2;
-                       else
-                               global_progressinband = 1;
-#ifdef OSP_SUPPORT
-               } else if (!strcasecmp(v->name, "ospauth")) {
-                       if (!strcasecmp(v->value, "exclusive")) {
-                               global_ospauth = 2;
-                       } else if (ast_true(v->value)) {
-                               global_ospauth = 1;
-                       } else
-                               global_ospauth = 0;
-#endif
                } else if (!strcasecmp(v->name, "pedantic")) {
                        pedanticsipchecking = ast_true(v->value);
-               } else if (!strcasecmp(v->name, "canreinvite")) {
-                       if (!strcasecmp(v->value, "update"))
-                               global_canreinvite = REINVITE_UPDATE;
-                       else
-                               global_canreinvite = ast_true(v->value);
                } else if (!strcasecmp(v->name, "maxexpirey") || !strcasecmp(v->name, "maxexpiry")) {
                        max_expiry = atoi(v->value);
                        if (max_expiry < 1)
@@ -8806,6 +8898,10 @@ static int reload_config(void)
                        default_expiry = atoi(v->value);
                        if (default_expiry < 1)
                                default_expiry = DEFAULT_DEFAULT_EXPIRY;
+               } else if (!strcasecmp(v->name, "registertimeout")){
+                       global_reg_timeout = atoi(v->value);
+                       if (global_reg_timeout < 1)
+                               global_reg_timeout = DEFAULT_REGISTRATION_TIMEOUT;
                } else if (!strcasecmp(v->name, "bindaddr")) {
                        if (!(hp = ast_gethostbyname(v->value, &ahp))) {
                                ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
@@ -8825,10 +8921,23 @@ static int reload_config(void)
                                ast_log(LOG_WARNING, "Invalid address for externip keyword: %s\n", v->value);
                        else
                                memcpy(&externip.sin_addr, hp->h_addr, sizeof(externip.sin_addr));
+                       externexpire = 0;
+               } else if (!strcasecmp(v->name, "externhost")) {
+                       strncpy(externhost, v->value, sizeof(externhost) - 1);
+                       if (!(hp = ast_gethostbyname(externhost, &ahp))) 
+                               ast_log(LOG_WARNING, "Invalid address for externhost keyword: %s\n", externhost);
+                       else
+                               memcpy(&externip.sin_addr, hp->h_addr, sizeof(externip.sin_addr));
+                       time(&externexpire);
+               } else if (!strcasecmp(v->name, "externrefresh")) {
+                       if (sscanf(v->value, "%i", &externrefresh) != 1) {
+                               ast_log(LOG_WARNING, "Invalid externrefresh value '%s', must be an integer >0 at line %d\n", v->value, v->lineno);
+                               externrefresh = 10;
+                       }
                } else if (!strcasecmp(v->name, "allow")) {
-                       ast_parse_allow_deny(&prefs, &global_capability, v->value, 1);
+                       ast_parse_allow_disallow(&prefs, &global_capability, v->value, 1);
                } else if (!strcasecmp(v->name, "disallow")) {
-                       ast_parse_allow_deny(&prefs, &global_capability, v->value, 0);
+                       ast_parse_allow_disallow(&prefs, &global_capability, v->value, 0);
                } else if (!strcasecmp(v->name, "register")) {
                        sip_register(v->value, v->lineno);
                } else if (!strcasecmp(v->name, "recordhistory")) {
@@ -8870,19 +8979,15 @@ static int reload_config(void)
                                if (!strcasecmp(utype, "user") || !strcasecmp(utype, "friend")) {
                                        user = build_user(cat, ast_variable_browse(cfg, cat));
                                        if (user) {
-                                               ast_mutex_lock(&userl.lock);
-                                               user->next = userl.users;
-                                               userl.users = user;
-                                               ast_mutex_unlock(&userl.lock);
+                                               ASTOBJ_CONTAINER_LINK(&userl,user);
+                                               ASTOBJ_UNREF(user, sip_destroy_user);
                                        }
                                }
                                if (!strcasecmp(utype, "peer") || !strcasecmp(utype, "friend")) {
                                        peer = build_peer(cat, ast_variable_browse(cfg, cat), 0);
                                        if (peer) {
-                                               ast_mutex_lock(&peerl.lock);
-                                               peer->next = peerl.peers;
-                                               peerl.peers = peer;
-                                               ast_mutex_unlock(&peerl.lock);
+                                               ASTOBJ_CONTAINER_LINK(&peerl,peer);
+                                               ASTOBJ_UNREF(peer, sip_destroy_peer);
                                        }
                                } else if (strcasecmp(utype, "user")) {
                                        ast_log(LOG_WARNING, "Unknown type '%s' for '%s' in %s\n", utype, cat, "sip.conf");
@@ -8950,6 +9055,7 @@ static int reload_config(void)
        return 0;
 }
 
+/*--- sip_get_rtp_peer: Returns null if we can't reinvite */
 static struct ast_rtp *sip_get_rtp_peer(struct ast_channel *chan)
 {
        struct sip_pvt *p;
@@ -8957,7 +9063,7 @@ static struct ast_rtp *sip_get_rtp_peer(struct ast_channel *chan)
        p = chan->pvt->pvt;
        if (p) {
                ast_mutex_lock(&p->lock);
-               if (p->rtp && p->canreinvite)
+               if (p->rtp && ast_test_flag(p, SIP_CAN_REINVITE))
                        rtp =  p->rtp;
                ast_mutex_unlock(&p->lock);
        }
@@ -8971,13 +9077,14 @@ static struct ast_rtp *sip_get_vrtp_peer(struct ast_channel *chan)
        p = chan->pvt->pvt;
        if (p) {
                ast_mutex_lock(&p->lock);
-               if (p->vrtp && p->canreinvite)
+               if (p->vrtp && ast_test_flag(p, SIP_CAN_REINVITE))
                        rtp = p->vrtp;
                ast_mutex_unlock(&p->lock);
        }
        return rtp;
 }
 
+/*--- sip_set_rtp_peer: Set the RTP peer for this call ---*/
 static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs)
 {
        struct sip_pvt *p;
@@ -8993,12 +9100,12 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struc
                else
                        memset(&p->vredirip, 0, sizeof(p->vredirip));
                p->redircodecs = codecs;
-               if (!p->gotrefer) {
+               if (!ast_test_flag(p, SIP_GOTREFER)) {
                        if (!p->pendinginvite)
                                transmit_reinvite_with_sdp(p);
-                       else if (!p->pendingbye) {
+                       else if (!ast_test_flag(p, SIP_PENDINGBYE)) {
                                ast_log(LOG_DEBUG, "Deferring reinvite on '%s'\n", p->callid);
-                               p->needreinvite = 1;
+                               ast_set_flag(p, SIP_NEEDREINVITE);      
                        }
                }
                /* Reset lastrtprx timer */
@@ -9055,20 +9162,26 @@ static int sip_dtmfmode(struct ast_channel *chan, void *data)
        p = chan->pvt->pvt;
        if (p) {
                ast_mutex_lock(&p->lock);
-               if (!strcasecmp(mode,"info"))
-                       p->dtmfmode = SIP_DTMF_INFO;
-               else if (!strcasecmp(mode,"rfc2833"))
-                       p->dtmfmode = SIP_DTMF_RFC2833;
-               else if (!strcasecmp(mode,"inband"))
-                       p->dtmfmode = SIP_DTMF_INBAND;
+               if (!strcasecmp(mode,"info")) {
+                       ast_clear_flag(p, SIP_DTMF);
+                       ast_set_flag(p, SIP_DTMF_INFO);
+               }
+               else if (!strcasecmp(mode,"rfc2833")) {
+                       ast_clear_flag(p, SIP_DTMF);
+                       ast_set_flag(p, SIP_DTMF_RFC2833);
+               }
+               else if (!strcasecmp(mode,"inband")) { 
+                       ast_clear_flag(p, SIP_DTMF);
+                       ast_set_flag(p, SIP_DTMF_INBAND);
+               }
                else
                        ast_log(LOG_WARNING, "I don't know about this dtmf mode: %s\n",mode);
-        if (p->dtmfmode & SIP_DTMF_INBAND) {
-                               if (!p->vad) {
-                      p->vad = ast_dsp_new();
-                      ast_dsp_set_features(p->vad, DSP_FEATURE_DTMF_DETECT);
-                               }
-        } else {
+               if (ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) {
+                       if (!p->vad) {
+                               p->vad = ast_dsp_new();
+                               ast_dsp_set_features(p->vad, DSP_FEATURE_DTMF_DETECT);
+                       }
+               } else {
                        if (p->vad) {
                                ast_dsp_free(p->vad);
                                p->vad = NULL;
@@ -9128,7 +9241,7 @@ static int sip_getheader(struct ast_channel *chan, void *data)
        struct sip_pvt *p;
        char *argv, *varname = NULL, *header = NULL, *content;
        
-       argv = strdupa(data);
+       argv = ast_strdupa(data);
        if (!argv) {
                ast_log(LOG_DEBUG, "Memory allocation failed\n");
                return 0;
@@ -9165,12 +9278,14 @@ static int sip_getheader(struct ast_channel *chan, void *data)
        return 0;
 }
 
+/*--- sip_get_codec: Return peers codec ---*/
 static int sip_get_codec(struct ast_channel *chan)
 {
        struct sip_pvt *p = chan->pvt->pvt;
        return p->peercapability;       
 }
 
+/*--- sip_rtp: Interface structure with callbacks used to connect to rtp module --*/
 static struct ast_rtp_protocol sip_rtp = {
        get_rtp_info: sip_get_rtp_peer,
        get_vrtp_info: sip_get_vrtp_peer,
@@ -9182,88 +9297,49 @@ static struct ast_rtp_protocol sip_rtp = {
 /*      Also, check registations with other SIP proxies */
 static void delete_users(void)
 {
-       struct sip_user *user, *userlast;
-       struct sip_peer *peer;
-       struct sip_registry *reg, *regn;
-
        /* Delete all users */
-       ast_mutex_lock(&userl.lock);
-       for (user=userl.users;user;) {
-               userlast = user;
-               user=user->next;
-               destroy_user(userlast);
-       }
-       userl.users=NULL;
-       ast_mutex_unlock(&userl.lock);
-
-       ast_mutex_lock(&regl.lock);
-       for (reg = regl.registrations;reg;) {
-               regn = reg->next;
-               /* Really delete */
-               if (reg->call) {
-                       /* Clear registry before destroying to ensure
-                          we don't get reentered trying to grab the registry lock */
-                       reg->call->registry = NULL;
-                       sip_destroy(reg->call);
-               }
-               if (reg->expire > -1)
-                       ast_sched_del(sched, reg->expire);
-               if (reg->timeout > -1)
-                       ast_sched_del(sched, reg->timeout);
-               free(reg);
-               reg = regn;
-       }
-       regl.registrations = NULL;
-       ast_mutex_unlock(&regl.lock);
-       
-       ast_mutex_lock(&peerl.lock);
-       for (peer=peerl.peers;peer;) {
-               /* Assume all will be deleted, and we'll find out for sure later */
-               peer->delme = 1;
-               peer = peer->next;
-       }
-       ast_mutex_unlock(&peerl.lock);
+       ASTOBJ_CONTAINER_DESTROYALL(&userl,sip_destroy_user);
+       ASTOBJ_CONTAINER_DESTROYALL(&regl,sip_registry_destroy);
+       ASTOBJ_CONTAINER_MARKALL(&peerl);
 }
 
 /*--- prune_peers: Delete all peers marked for deletion ---*/
 static void prune_peers(void)
 {
        /* Prune peers who still are supposed to be deleted */
-       struct sip_peer *peer, *peerlast, *peernext;
-       ast_mutex_lock(&peerl.lock);
-       peerlast = NULL;
-       for (peer=peerl.peers;peer;) {
-               peernext = peer->next;
-               if (peer->delme) {
-                       destroy_peer(peer);
-                       if (peerlast)
-                               peerlast->next = peernext;
-                       else
-                               peerl.peers = peernext;
-               } else
-                       peerlast = peer;
-               peer=peernext;
-       }
-       ast_mutex_unlock(&peerl.lock);
+       ASTOBJ_CONTAINER_PRUNE_MARKED(&peerl,sip_destroy_peer);
+}
+
+/*--- sip_poke_all_peers: Send a poke to all known peers */
+static void sip_poke_all_peers(void)
+{
+       ASTOBJ_CONTAINER_TRAVERSE(&peerl, do {
+               ASTOBJ_WRLOCK(iterator);
+               sip_poke_peer(iterator);
+               ASTOBJ_UNLOCK(iterator);
+       } while (0)
+       );
+}
+
+/*--- sip_send_all_registers: Send all known registrations */
+static void sip_send_all_registers(void)
+{
+       ASTOBJ_CONTAINER_TRAVERSE(&regl, do {
+               ASTOBJ_WRLOCK(iterator);
+               __sip_do_register(iterator);
+               ASTOBJ_UNLOCK(iterator);
+       } while (0)
+       );
 }
 
 /*--- sip_do_reload: Reload module */
 static int sip_do_reload(void)
 {
-       struct sip_registry *reg;
-       struct sip_peer *peer;
        delete_users();
        reload_config();
        prune_peers();
-       /* And start the monitor for the first time */
-       ast_mutex_lock(&regl.lock);
-       for (reg = regl.registrations; reg; reg = reg->next) 
-               __sip_do_register(reg);
-       ast_mutex_unlock(&regl.lock);
-       ast_mutex_lock(&peerl.lock);
-       for (peer = peerl.peers; peer; peer = peer->next)
-               sip_poke_peer(peer);
-       ast_mutex_unlock(&peerl.lock);
+       sip_poke_all_peers();
+       sip_send_all_registers();
 
        return 0;
 }
@@ -9294,12 +9370,10 @@ static struct ast_cli_entry  cli_sip_reload =
 int load_module()
 {
        int res;
-       struct sip_peer *peer;
-       struct sip_registry *reg;
 
-       ast_mutex_init(&userl.lock);
-       ast_mutex_init(&peerl.lock);
-       ast_mutex_init(&regl.lock);
+       ASTOBJ_CONTAINER_INIT(&userl);
+       ASTOBJ_CONTAINER_INIT(&peerl);
+       ASTOBJ_CONTAINER_INIT(&regl);
        sched = sched_context_create();
        if (!sched) {
                ast_log(LOG_WARNING, "Unable to create schedule context\n");
@@ -9318,6 +9392,7 @@ int load_module()
                        return -1;
                }
                ast_cli_register(&cli_show_users);
+               ast_cli_register(&cli_show_objects);
                ast_cli_register(&cli_show_subscriptions);
                ast_cli_register(&cli_show_channels);
                ast_cli_register(&cli_show_channel);
@@ -9341,15 +9416,8 @@ int load_module()
                ast_register_application(app_dtmfmode, sip_dtmfmode, synopsis_dtmfmode, descrip_dtmfmode);
                ast_register_application(app_sipaddheader, sip_addheader, synopsis_sipaddheader, descrip_sipaddheader);
                ast_register_application(app_sipgetheader, sip_getheader, synopsis_sipgetheader, descrip_sipgetheader);
-               ast_mutex_lock(&peerl.lock);
-               for (peer = peerl.peers; peer; peer = peer->next)
-                       sip_poke_peer(peer);
-               ast_mutex_unlock(&peerl.lock);
-
-               ast_mutex_lock(&regl.lock);
-               for (reg = regl.registrations; reg; reg = reg->next) 
-                       __sip_do_register(reg);
-               ast_mutex_unlock(&regl.lock);
+               sip_poke_all_peers();
+               sip_send_all_registers();
                
                /* And start the monitor for the first time */
                restart_monitor();
@@ -9366,6 +9434,7 @@ int unload_module()
        ast_unregister_application(app_sipaddheader);
        ast_unregister_application(app_sipgetheader);
        ast_cli_unregister(&cli_show_users);
+       ast_cli_unregister(&cli_show_objects);
        ast_cli_unregister(&cli_show_channels);
        ast_cli_unregister(&cli_show_channel);
        ast_cli_unregister(&cli_show_history);
@@ -9435,9 +9504,9 @@ int unload_module()
        }
        /* Free memory for local network address mask */
        ast_free_ha(localaddr);
-       ast_mutex_destroy(&userl.lock);
-       ast_mutex_destroy(&peerl.lock);
-       ast_mutex_destroy(&regl.lock);
+       ASTOBJ_CONTAINER_DESTROY(&userl);
+       ASTOBJ_CONTAINER_DESTROY(&peerl);
+       ASTOBJ_CONTAINER_DESTROY(&regl);
                
        return 0;
 }