Merge OEJ's print groups feature (bug #3228, with changes)
[asterisk/asterisk.git] / channels / chan_sip.c
index 5e37ce4..2b36e1a 100755 (executable)
@@ -18,6 +18,7 @@
 #include <asterisk/lock.h>
 #include <asterisk/channel.h>
 #include <asterisk/channel_pvt.h>
+#include <asterisk/config_pvt.h>
 #include <asterisk/config.h>
 #include <asterisk/logger.h>
 #include <asterisk/module.h>
@@ -41,6 +42,8 @@
 #include <asterisk/astdb.h>
 #include <asterisk/causes.h>
 #include <asterisk/utils.h>
+#include <asterisk/file.h>
+#include <asterisk/astobj.h>
 #ifdef OSP_SUPPORT
 #include <asterisk/astosp.h>
 #endif
 #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 */
 #define EXPIRY_GUARD_SECS      15      /* How long before expiry do we reregister */
-#define EXPIRY_GUARD_LIMIT      30     /* Below here, we use EXPIRY_GUARD_PCT instead of EXPIRY_GUARD_SECS */
-#define EXPIRY_GUARD_MIN       500     /* This is the minimum guard time applied. If GUARD_PCT turns out
-                                       to be lower than this, it will use this time instead. This is in
-                                       milliseconds. */
-#define EXPIRY_GUARD_PCT        0.20   /* Percentage of expires timeout to use when below EXPIRY_GUARD_LIMIT */
+#define EXPIRY_GUARD_LIMIT      30     /* Below here, we use EXPIRY_GUARD_PCT instead of 
+                                          EXPIRY_GUARD_SECS */
+#define EXPIRY_GUARD_MIN       500     /* This is the minimum guard time applied. If 
+                                          GUARD_PCT turns out to be lower than this, it 
+                                          will use this time instead.
+                                          This is in milliseconds. */
+#define EXPIRY_GUARD_PCT        0.20   /* Percentage of expires timeout to use when 
+                                          below EXPIRY_GUARD_LIMIT */
+
+static int max_expiry = DEFAULT_MAX_EXPIRY;
+static int default_expiry = DEFAULT_DEFAULT_EXPIRY;
 
 #ifndef MAX
 #define MAX(a,b) ((a) > (b) ? (a) : (b))
 
 #define CALLERID_UNKNOWN       "Unknown"
 
-/* --- Choices for DTMF support in SIP channel */
-#define SIP_DTMF_RFC2833       (1 << 0)
-#define SIP_DTMF_INBAND                (1 << 1)
-#define SIP_DTMF_INFO          (1 << 2)
 
-static int max_expiry = DEFAULT_MAX_EXPIRY;
-static int default_expiry = DEFAULT_DEFAULT_EXPIRY;
 
 #define DEFAULT_MAXMS          2000            /* Must be faster than 2 seconds by default */
-#define DEFAULT_FREQ_OK                60 * 1000               /* How often to check for the host to be up */
-#define DEFAULT_FREQ_NOTOK     10 * 1000               /* How often to check, if the host is down... */
+#define DEFAULT_FREQ_OK                60 * 1000       /* How often to check for the host to be up */
+#define DEFAULT_FREQ_NOTOK     10 * 1000       /* How often to check, if the host is down... */
 
-#define DEFAULT_RETRANS                1000                    /* How frequently to retransmit */
-#define MAX_RETRANS            5                       /* Try only 5 times for retransmissions */
+#define DEFAULT_RETRANS                1000            /* How frequently to retransmit */
+#define MAX_RETRANS            5               /* Try only 5 times for retransmissions */
 
-                                                       /* SIP Debug            */
-#define DEBUG_READ     0                               /* Recieved data        */
-#define DEBUG_SEND     1                               /* Transmit data        */
+                                               /* SIP Debug            */
+#define DEBUG_READ     0                       /* Recieved data        */
+#define DEBUG_SEND     1                       /* Transmit data        */
 
 static char *desc = "Session Initiation Protocol (SIP)";
-static char *type = "SIP";
+static char *channeltype = "SIP";
 static char *tdesc = "Session Initiation Protocol (SIP)";
 static char *config = "sip.conf";
 
 #define DEFAULT_SIP_PORT       5060    /* From RFC 2543 */
-#define SIP_MAX_PACKET 4096            /* Also from RFC 2543, should sub headers tho */
+#define SIP_MAX_PACKET         4096    /* Also from RFC 2543, should sub headers tho */
 
 #define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER"
 
 static char default_useragent[AST_MAX_EXTENSION] = DEFAULT_USERAGENT;
 
-static char default_context[AST_MAX_EXTENSION] = "default";
+#define DEFAULT_CONTEXT "default"
+static char default_context[AST_MAX_EXTENSION] = DEFAULT_CONTEXT;
 
 static char default_language[MAX_LANGUAGE] = "";
 
-static char default_callerid[AST_MAX_EXTENSION] = "asterisk";
+#define DEFAULT_CALLERID "asterisk"
+static char default_callerid[AST_MAX_EXTENSION] = DEFAULT_CALLERID;
 
 static char default_fromdomain[AST_MAX_EXTENSION] = "";
 
-static char notifymime[AST_MAX_EXTENSION] = "application/simple-message-summary";
+#define DEFAULT_NOTIFYMIME "application/simple-message-summary"
+static char default_notifymime[AST_MAX_EXTENSION] = DEFAULT_NOTIFYMIME;
 
-static int srvlookup = 0;
+static struct ast_flags global_flags = {0};            /* global SIP_ flags */
 
-static int pedanticsipchecking = 0;
+static int srvlookup = 0;              /* SRV Lookup on or off. Default is off, RFC behavior is on */
 
-static int autocreatepeer = 0;         
+static int pedanticsipchecking = 0;    /* Extra checking ?  Default off */
+
+static int autocreatepeer = 0;         /* Auto creation of peers at registration? Default off. */
 
 static int relaxdtmf = 0;
 
@@ -141,17 +150,23 @@ static int global_rtptimeout = 0;
 
 static int global_rtpholdtimeout = 0;
 
-static int global_trustrpid = 0;
+static int global_reg_timeout = DEFAULT_REGISTRATION_TIMEOUT;
 
-static int global_progressinband = 0;
+/* 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;
 
-#ifdef OSP_SUPPORT
-static int global_ospauth = 0;
-#endif
+#define DEFAULT_MWITIME 10
+static int global_mwitime = DEFAULT_MWITIME;   /* Time between MWI checks for peers */
 
 static int usecnt =0;
 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
 
+
 /* Protect the interface list (of sip_pvt's) */
 AST_MUTEX_DEFINE_STATIC(iflock);
 
@@ -173,6 +188,7 @@ static int noncodeccapability = AST_RTP_DTMF;
 
 static char ourhost[256];
 static struct in_addr __ourip;
+static struct sockaddr_in outboundproxyip;
 static int ourport;
 
 static int sipdebug = 0;
@@ -182,16 +198,17 @@ static int tos = 0;
 
 static int videosupport = 0;
 
-static int global_dtmfmode = SIP_DTMF_RFC2833;         /* DTMF mode default */
-static int recordhistory = 0;
-static int global_promiscredir;
+static int compactheaders = 0;                                                 /* send compact sip headers */
+
+static int recordhistory = 0;                          /* Record SIP history. Off by default */
 
 static char global_musicclass[MAX_LANGUAGE] = "";      /* Global music on hold class */
 static char global_realm[AST_MAX_EXTENSION] = "asterisk";      /* Default realm */
-static char regcontext[AST_MAX_EXTENSION] = "";
+static char regcontext[AST_MAX_EXTENSION] = "";                /* Context for auto-extensions */
 
 /* Expire slowly */
-static int expiry = 900;
+#define DEFAULT_EXPIRY 900
+static int expiry = DEFAULT_EXPIRY;
 
 static struct sched_context *sched;
 static struct io_context *io;
@@ -206,17 +223,15 @@ static struct io_context *io;
 #define DEC_OUT_USE    2
 #define INC_OUT_USE    3
 
-static struct sip_codec_pref {
-       int codec;
-       struct sip_codec_pref *next;
-} *prefs;
+static struct ast_codec_pref prefs;
+
 
 /* sip_request: The data grabbed from the UDP socket */
 struct sip_request {
-  char *rlPart1; /* SIP Method Name or "SIP/2.0" protocol version */
-  char *rlPart2; /* The Request URI or Response Status */
-       int len;
-       int headers;                                    /* SIP Headers */
+       char *rlPart1;          /* SIP Method Name or "SIP/2.0" protocol version */
+       char *rlPart2;          /* The Request URI or Response Status */
+       int len;                /* Length */
+       int headers;            /* # of SIP Headers */
        char *header[SIP_MAX_HEADERS];
        int lines;                                              /* SDP Content */
        char *line[SIP_MAX_LINES];
@@ -235,41 +250,81 @@ 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 */
        char callid[80];                        /* Global CallID */
        char randdata[80];                      /* Random data */
+       struct ast_codec_pref prefs; /* codec prefs */
        unsigned int ocseq;                     /* Current outgoing seqno */
        unsigned int icseq;                     /* Current incoming seqno */
        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 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 */
        struct sockaddr_in redirip;             /* Where our RTP should be going if not to us */
        struct sockaddr_in vredirip;            /* Where our Video RTP should be going if not to us */
-       int redircodecs;                                /* Redirect codecs */
+       int redircodecs;                        /* Redirect codecs */
        struct sockaddr_in recv;                /* Received as */
        struct in_addr ourip;                   /* Our IP */
        struct ast_channel *owner;              /* Who owns us */
@@ -294,27 +349,24 @@ static struct sip_pvt {
        char peername[256];
        char authname[256];                     /* Who we use for authentication */
        char uri[256];                          /* Original requested URI */
-       char peersecret[256];
+       char okcontacturi[256];                 /* URI from the 200 OK on INVITE */
+       char peersecret[256];                   /* Password */
        char peermd5secret[256];
        char cid_num[256];                      /* Caller*ID */
        char cid_name[256];                     /* Caller*ID */
-       char via[256];
-       char fullcontact[128];          /* Extra parameters to go in the "To" header */
+       char via[256];                          /* Via: header */
+       char fullcontact[128];                  /* The Contact: that the UA registers with us */
        char accountcode[20];                   /* Account code */
        char our_contact[256];                  /* Our contact header */
        char realm[256];                        /* Authorization realm */
        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
@@ -327,15 +379,10 @@ static struct sip_pvt {
        int rtptimeout;                         /* RTP timeout time */
        int rtpholdtimeout;                     /* RTP timeout when on hold */
 
-       int subscribed;
+       int subscribed;                         /* Is this call a subscription?  */
        int stateid;
        int dialogver;
-       int promiscredir;                       /* Promiscuous redirection */
        
-       int trustrpid;
-       int progressinband;
-       
-       int dtmfmode;
        struct ast_dsp *vad;
        
        struct sip_peer *peerpoke;              /* If this calls is to poke a peer, which one */
@@ -343,7 +390,8 @@ static struct sip_pvt {
        struct ast_rtp *rtp;                    /* RTP Session */
        struct ast_rtp *vrtp;                   /* Video RTP session */
        struct sip_pkt *packets;                /* Packets scheduled for re-transmission */
-       struct sip_history *history;    /* History of this SIP dialog */
+       struct sip_history *history;            /* History of this SIP dialog */
+       struct ast_variable *vars;
        struct sip_pvt *next;                   /* Next call in chain */
 } *iflist = NULL;
 
@@ -353,130 +401,107 @@ static struct sip_pvt {
 /* sip packet - read in sipsock_read, transmitted in send_request */
 struct sip_pkt {
        struct sip_pkt *next;                           /* Next packet */
-       int retrans;                                            /* Retransmission number */
-       int seqno;                                                      /* Sequence number */
-       int flags;                                                      /* non-zero if this is a response packet (e.g. 200 OK) */
+       int retrans;                                    /* Retransmission number */
+       int seqno;                                      /* Sequence number */
+       int flags;                                      /* non-zero if this is a response packet (e.g. 200 OK) */
        struct sip_pvt *owner;                          /* Owner call */
-       int retransid;                                          /* Retransmission ID */
-       int packetlen;                                          /* Length of packet */
+       int retransid;                                  /* Retransmission ID */
+       int packetlen;                                  /* Length of packet */
        char data[0];
 };     
 
 /* Structure for SIP user data. User's place calls to us */
 struct sip_user {
        /* Users who can access various contexts */
-       char name[80];
-       char secret[80];
-        char md5secret[80];
-       char context[80];
-       char cid_num[80];
-       char cid_name[80];
-       char accountcode[20];
-       char language[MAX_LANGUAGE];
+       ASTOBJ_COMPONENTS(struct sip_user);
+       char secret[80];                /* Password */
+       char md5secret[80];             /* Password in md5 */
+       char context[80];               /* Default context for incoming calls */
+       char cid_num[80];               /* Caller ID num */
+       char cid_name[80];              /* Caller ID name */
+       char accountcode[20];           /* Account code */
+       char language[MAX_LANGUAGE];    /* Default language for this user */
        char musicclass[MAX_LANGUAGE];  /* Music on Hold class */
        char useragent[256];            /* User agent in SIP request */
-       unsigned int callgroup;
-       unsigned int pickupgroup;
-       int nat;
-       int hascallerid;
-       int amaflags;
-       int callingpres;
-       int insecure;
-       int canreinvite;
-       int capability;
-#ifdef OSP_SUPPORT
-       int ospauth;                            /* Allow OSP Authentication */
-#endif
-       int dtmfmode;
+       struct ast_codec_pref prefs; /* codec prefs */
+       unsigned int callgroup;         /* Call group */
+       unsigned int pickupgroup;       /* Pickup Group */
+       int flags;                      /* SIP_ flags */        
+       int amaflags;                   /* AMA flags for billing */
+       int callingpres;                /* Calling id presentation */
+       int capability;                 /* Codec capability */
        int inUse;
        int incominglimit;
        int outUse;
        int outgoinglimit;
-       int promiscredir;
-       int trustrpid;
-       int progressinband;
-       struct ast_ha *ha;
-       int temponly;
-       struct sip_user *next;
+       struct ast_ha *ha;              /* ACL setting */
+       struct ast_variable *vars;
 };
 
 /* Structure for SIP peer data, we place calls to peers if registred  or fixed IP address (host) */
 struct sip_peer {
-       char name[80];
-       char secret[80];
-       char md5secret[80];
-       char context[80];               /* JK02: peers need context too to allow parking etc */
-       char username[80];
-       char tohost[80];
-       char regexten[AST_MAX_EXTENSION];       /* Extension to register (if regcontext is used) */
-       char fromuser[80];
-       char fromdomain[80];
-       char fullcontact[128];
-       char mailbox[AST_MAX_EXTENSION];
-       char language[MAX_LANGUAGE];
+       ASTOBJ_COMPONENTS(struct sip_peer);
+       char secret[80];                /* Password */
+       char md5secret[80];             /* Password in MD5 */
+       char context[80];               /* Default context for incoming calls */
+       char username[80];              /* Temporary username until registration */
+       char tohost[80];                /* If not dynamic, IP address */
+       char regexten[AST_MAX_EXTENSION]; /* Extension to register (if regcontext is used) */
+       char fromuser[80];              /* From: user when calling this peer */
+       char fromdomain[80];            /* From: domain when calling this peer */
+       char fullcontact[128];          /* Contact registred with us (not in sip.conf) */
+       char cid_num[80];               /* Caller ID num */
+       char cid_name[80];              /* Caller ID name */
+       char mailbox[AST_MAX_EXTENSION]; /* Mailbox setting for MWI checks */
+       char language[MAX_LANGUAGE];    /* Default language for prompts */
        char musicclass[MAX_LANGUAGE];  /* Music on Hold class */
-       char useragent[256];            /* User agent in SIP request */
+       char useragent[256];            /* User agent in SIP request (saved from registration) */
+       struct ast_codec_pref prefs; /* codec prefs */
        int lastmsgssent;
-       time_t  lastmsgcheck;
-       int dynamic;
-       int expire;
+       time_t  lastmsgcheck;           /* Last time we checked for MWI */
+       int flags;                      /* SIP_ flags */        
+       int expire;                     /* Registration expiration */
        int expiry;
-       int capability;
+       int capability;                 /* Codec capability */
        int rtptimeout;
        int rtpholdtimeout;
-       int insecure;
-#ifdef OSP_SUPPORT
-       int ospauth;                            /* Allow OSP Authentication */
-#endif 
-       int nat;
-       int canreinvite;
-       unsigned int callgroup;
-       unsigned int pickupgroup;
-       int promiscredir;
-       int dtmfmode;
-       int trustrpid;
-       int progressinband;
-       struct sockaddr_in addr;
+       unsigned int callgroup;         /* Call group */
+       unsigned int pickupgroup;       /* Pickup group */
+       struct sockaddr_in addr;        /* IP address of peer */
        struct in_addr mask;
 
        /* Qualification */
        struct sip_pvt *call;           /* Call pointer */
-       int pokeexpire;                         /* When to expire poke */
-       int lastms;                                     /* How long last response took (in ms), or -1 for no response */
-       int maxms;                                      /* Max ms we will accept for the host to be up, 0 to not monitor */
-       struct timeval ps;                      /* Ping send time */
+       int pokeexpire;                 /* When to expire poke (qualify= checking) */
+       int lastms;                     /* How long last response took (in ms), or -1 for no response */
+       int maxms;                      /* Max ms we will accept for the host to be up, 0 to not monitor */
+       struct timeval ps;              /* Ping send time */
        
-       struct sockaddr_in defaddr;
-       struct ast_ha *ha;
-       int delme;
-       int selfdestruct;
+       struct sockaddr_in defaddr;     /* Default IP address, used until registration */
+       struct ast_ha *ha;              /* Access control list */
        int lastmsg;
-       int temponly;
-       struct sip_peer *next;
 };
 
 AST_MUTEX_DEFINE_STATIC(sip_reload_lock);
 static int sip_reloading = 0;
 
-#define REG_STATE_UNREGISTERED 0
-#define REG_STATE_REGSENT         1
-#define REG_STATE_AUTHSENT        2
-#define REG_STATE_REGISTERED   3
-#define REG_STATE_REJECTED        4
-#define REG_STATE_TIMEOUT         5
-#define REG_STATE_NOAUTH          6
+/* States for outbound registrations (with register= lines in sip.conf */
+#define REG_STATE_UNREGISTERED         0
+#define REG_STATE_REGSENT              1
+#define REG_STATE_AUTHSENT             2
+#define REG_STATE_REGISTERED                   3
+#define REG_STATE_REJECTED             4
+#define REG_STATE_TIMEOUT              5
+#define REG_STATE_NOAUTH               6
 
-#define SIP_NAT_NEVER          0
-#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 {
-       int portno;                             /* Optional port override */
+       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 */
-       char hostname[80];
+       char hostname[80];              /* Domain or host we register to */
        char secret[80];                /* Password or key name in []'s */      
        char md5secret[80];
        char contact[80];               /* Contact extension */
@@ -485,46 +510,49 @@ struct sip_registry {
        int timeout;                    /* sched id of sip_reg_timeout */
        int refresh;                    /* How often to refresh */
        struct sip_pvt *call;           /* create a sip_pvt structure for each outbound "registration call" in progress */
-       int regstate;
+       int regstate;                   /* Registration state (see above) */
        int callid_valid;               /* 0 means we haven't chosen callid for this registry yet. */
        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);
@@ -533,7 +561,7 @@ static int transmit_response_with_sdp(struct sip_pvt *p, char *msg, struct sip_r
 static int transmit_response_with_auth(struct sip_pvt *p, char *msg, struct sip_request *req, char *rand, int reliable, char *header);
 static int transmit_request(struct sip_pvt *p, char *msg, int inc, int reliable, int newbranch);
 static int transmit_request_with_auth(struct sip_pvt *p, char *msg, int inc, int reliable, int newbranch);
-static int transmit_invite(struct sip_pvt *p, char *msg, int sendsdp, char *auth, char *authheader, char *vxml_url,char *distinctive_ring, char *osptoken,int init);
+static int transmit_invite(struct sip_pvt *p, char *msg, int sendsdp, char *auth, char *authheader, char *vxml_url, char *distinctive_ring, char *osptoken, int addsipheaders, int init);
 static int transmit_reinvite_with_sdp(struct sip_pvt *p);
 static int transmit_info_with_digit(struct sip_pvt *p, char digit);
 static int transmit_message_with_text(struct sip_pvt *p, char *text);
@@ -565,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));
 }
 
 
@@ -574,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));
@@ -597,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];
@@ -653,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));
@@ -672,11 +710,12 @@ static int retrans_pkt(void *data)
                                ast_mutex_lock(&pkt->owner->lock);
                        }
                        if (pkt->owner->owner) {
+                               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 */
@@ -862,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));
@@ -895,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));
@@ -1014,14 +1053,14 @@ static void register_peer_exten(struct sip_peer *peer, int onoff)
                stringp = multi;
                while((ext = strsep(&stringp, "&"))) {
                        if (onoff)
-                               ast_add_extension(regcontext, 1, ext, 1, NULL, NULL, "Noop", strdup(peer->name), free, type);
+                               ast_add_extension(regcontext, 1, ext, 1, NULL, NULL, "Noop", strdup(peer->name), free, channeltype);
                        else
                                ast_context_remove_extension(regcontext, ext, 1, NULL);
                }
        }
 }
 
-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)
@@ -1032,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);
 }
 
@@ -1063,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;
                                        } 
@@ -1098,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);
@@ -1135,9 +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);
 }
 
@@ -1152,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;
                                        } 
@@ -1170,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);
        }
@@ -1213,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);
@@ -1250,22 +1299,16 @@ 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;
+                       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)))) {
+                               (!p->maxms || ((p->lastms >= 0)  && (p->lastms <= p->maxms)))) {
                                if (p->addr.sin_addr.s_addr) {
                                        r->sa.sin_addr = p->addr.sin_addr;
                                        r->sa.sin_port = p->addr.sin_port;
@@ -1275,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)
@@ -1313,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;
        }
 }
@@ -1337,71 +1374,8 @@ static int auto_congest(void *nothing)
        return 0;
 }
 
-/*--- sip_prefs_free: Free codec list in preference structure ---*/
-static void sip_prefs_free(void)
-{
-       struct sip_codec_pref *cur, *next;
-       cur = prefs;
-       while(cur) {
-               next = cur->next;
-               free(cur);
-               cur = next;
-       }
-       prefs = NULL;
-}
-
-/*--- sip_pref_remove: Remove codec from pref list ---*/
-static void sip_pref_remove(int format)
-{
-       struct sip_codec_pref *cur, *prev=NULL;
-       cur = prefs;
-       while(cur) {
-               if (cur->codec == format) {
-                       if (prev)
-                               prev->next = cur->next;
-                       else
-                               prefs = cur->next;
-                       free(cur);
-                       return;
-               }
-               prev = cur;
-               cur = cur->next;
-       }
-}
 
-/*--- sip_pref_append: Append codec to list ---*/
-static int sip_pref_append(int format)
-{
-       struct sip_codec_pref *cur, *tmp;
-       sip_pref_remove(format);
-       tmp = (struct sip_codec_pref *)malloc(sizeof(struct sip_codec_pref));
-       if (!tmp)
-               return -1;
-       memset(tmp, 0, sizeof(struct sip_codec_pref));
-       tmp->codec = format;
-       if (prefs) {
-               cur = prefs;
-               while(cur->next)
-                       cur = cur->next;
-               cur->next = tmp;
-       } else
-               prefs = tmp;
-       return 0;
-}
 
-/*--- sip_codec_choose: Pick a codec ---*/
-static int sip_codec_choose(int formats)
-{
-       struct sip_codec_pref *cur;
-       formats &= ((AST_FORMAT_MAX_AUDIO << 1) - 1);
-       cur = prefs;
-       while(cur) {
-               if (formats & cur->codec)
-                       return cur->codec;
-               cur = cur->next;
-       }
-       return ast_best_codec(formats);
-}
 
 /*--- sip_call: Initiate SIP call from PBX ---*/
 /*      used from the dial() application      */
@@ -1417,6 +1391,7 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
 #endif 
        struct varshead *headp;
        struct ast_var_t *current;
+       int addsipheaders = 0;
        
        p = ast->pvt->pvt;
        if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
@@ -1428,26 +1403,28 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
        headp=&ast->varshead;
        AST_LIST_TRAVERSE(headp,current,entries) {
                /* Check whether there is a VXML_URL variable */
-               if (strcasecmp(ast_var_name(current),"VXML_URL")==0)
-               {
+               if (!vxml_url && !strcasecmp(ast_var_name(current),"VXML_URL")) {
                        vxml_url = ast_var_value(current);
-               } else
-               /* Check whether there is a ALERT_INFO variable */
-               if (strcasecmp(ast_var_name(current),"ALERT_INFO")==0)
-               {
+               } else if (!distinctive_ring && !strcasecmp(ast_var_name(current),"ALERT_INFO")) {
+                       /* Check whether there is a ALERT_INFO variable */
                        distinctive_ring = ast_var_value(current);
+               } else if (!addsipheaders && !strncasecmp(ast_var_name(current),"SIPADDHEADER",strlen("SIPADDHEADER"))) {
+                       /* Check whether there is a variable with a name starting with SIPADDHEADER */
+                       addsipheaders = 1;
                }
+
+               
 #ifdef OSP_SUPPORT
-               else if (!strcasecmp(ast_var_name(current), "OSPTOKEN")) {
+                 else if (!osptoken && !strcasecmp(ast_var_name(current), "OSPTOKEN")) {
                        osptoken = ast_var_value(current);
-               } else if (!strcasecmp(ast_var_name(current), "OSPHANDLE")) {
+               } else if (!osphandle && !strcasecmp(ast_var_name(current), "OSPHANDLE")) {
                        osphandle = ast_var_value(current);
                }
 #endif
        }
        
        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 */
@@ -1461,7 +1438,7 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
        if ( res != -1 ) {
                p->callingpres = ast->cid.cid_pres;
                p->jointcapability = p->capability;
-               transmit_invite(p, "INVITE", 1, NULL, NULL, vxml_url,distinctive_ring, osptoken, 1);
+               transmit_invite(p, "INVITE", 1, NULL, NULL, vxml_url,distinctive_ring, osptoken, addsipheaders, 1);
                if (p->maxtime) {
                        /* Initialize auto-congest time */
                        p->initid = ast_sched_add(sched, p->maxtime * 4, auto_congest, p);
@@ -1470,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)
 {
@@ -1497,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) {
@@ -1547,6 +1535,10 @@ static void __sip_destroy(struct sip_pvt *p, int lockowner)
                        free(cp);
                }
                ast_mutex_destroy(&p->lock);
+               if(p->vars) {
+                       ast_destroy_realtime(p->vars);
+                       p->vars = NULL;
+               }
                free(p);
        }
 }
@@ -1558,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) {
@@ -1584,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; 
                                }
                        }
@@ -1619,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;
 }
 
@@ -1680,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) {
@@ -1693,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 {
@@ -1721,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 {
@@ -1755,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;
 }
@@ -1814,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);
                        }
@@ -1826,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);
                        }
@@ -1865,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;
 }
 
 
@@ -1883,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;
 }
 
@@ -1893,50 +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) {
+                       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)
+                               ast_set_flag(p, SIP_RINGING);
+                               if (ast_test_flag(p, SIP_PROG_INBAND) != SIP_PROG_INBAND_YES)
                                        break;
                        } else {
-                               /* Oops, we've sent progress tones.  Let Asterisk do it instead */
+                               /* 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;
 }
 
 
@@ -1946,8 +1950,9 @@ static int sip_indicate(struct ast_channel *ast, int condition)
 static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
 {
        struct ast_channel *tmp;
+       struct ast_variable *v = NULL;
        int fmt;
-
+       
        ast_mutex_unlock(&i->lock);
        /* Don't hold a sip pvt lock while we allocate a channel */
        tmp = ast_channel_alloc(1);
@@ -1955,12 +1960,14 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
        if (tmp) {
                /* Select our native format based on codec preference until we receive
                   something from another device to the contrary. */
+               ast_mutex_lock(&i->lock);
                if (i->jointcapability)
-                       tmp->nativeformats = sip_codec_choose(i->jointcapability);
+                       tmp->nativeformats = ast_codec_choose(&i->prefs, i->jointcapability, 1);
                else if (i->capability)
-                       tmp->nativeformats = sip_codec_choose(i->capability);
+                       tmp->nativeformats = ast_codec_choose(&i->prefs, i->capability, 1);
                else
-                       tmp->nativeformats = sip_codec_choose(global_capability);
+                       tmp->nativeformats = ast_codec_choose(&i->prefs, global_capability, 1);
+               ast_mutex_unlock(&i->lock);
                fmt = ast_best_codec(tmp->nativeformats);
                if (title)
                        snprintf(tmp->name, sizeof(tmp->name), "SIP/%s-%04x", title, rand() & 0xffff);
@@ -1973,8 +1980,8 @@ 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 = type;
-                if (i->dtmfmode & SIP_DTMF_INBAND) {
+               tmp->type = channeltype;
+                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)
@@ -2034,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);
                }
@@ -2051,6 +2061,9 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
                                tmp = NULL;
                        }
                }
+               for (v = i->vars ; v ; v = v->next)
+                       pbx_builtin_setvar_helper(tmp,v->name,v->value);
+                               
        } else
                ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
        return tmp;
@@ -2194,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 */
@@ -2205,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);
@@ -2259,9 +2272,11 @@ static struct sip_pvt *sip_alloc(char *callid, struct sockaddr_in *sin, int useg
        /* Keep track of stuff */
        memset(p, 0, sizeof(struct sip_pvt));
         ast_mutex_init(&p->lock);
+
        p->initid = -1;
        p->autokillid = -1;
        p->stateid = -1;
+       p->prefs = prefs;
 #ifdef OSP_SUPPORT
        p->osphandle = -1;
 #endif 
@@ -2283,6 +2298,10 @@ static struct sip_pvt *sip_alloc(char *callid, struct sockaddr_in *sin, int useg
        if (!p->rtp) {
                ast_log(LOG_WARNING, "Unable to create RTP session: %s\n", strerror(errno));
                 ast_mutex_destroy(&p->lock);
+               if(p->vars) {
+                       ast_destroy_realtime(p->vars);
+                       p->vars = NULL;
+               }
                free(p);
                return NULL;
        }
@@ -2291,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);
@@ -2308,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 */
@@ -2447,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);
@@ -2462,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;
@@ -2488,33 +2499,32 @@ static int lws2sws(char *msgbuf, int len)
                } 
                /* Check for end-of-line */ 
                if (msgbuf[h] == '\n') { 
-               /* Check for end-of-message */ 
+                       /* Check for end-of-message */ 
                        if (h + 1 == len) 
-                       break; 
-               /* Check for a continuation line */ 
-               if (msgbuf[h + 1] == ' ') { 
-               /* Merge continuation line */ 
-                       h++; 
+                               break; 
+                       /* Check for a continuation line */ 
+                       if (msgbuf[h + 1] == ' ' || msgbuf[h + 1] == '\t') { 
+                               /* Merge continuation line */ 
+                               h++; 
+                               continue; 
+                       } 
+                       /* Propagate LF and start new line */ 
+                       msgbuf[t++] = msgbuf[h++]; 
+                       lws = 0;
                        continue; 
                } 
-               /* Propagate LF and start new line */ 
-               msgbuf[t++] = msgbuf[h++]; 
-               lws = 0;
-               continue; 
-       } 
-
-       if (msgbuf[h] == ' ' || msgbuf[h] == '\t') { 
-               if (lws) { 
-                       h++; 
+               if (msgbuf[h] == ' ' || msgbuf[h] == '\t') { 
+                       if (lws) { 
+                               h++; 
+                               continue; 
+                       } 
+                       msgbuf[t++] = msgbuf[h++]; 
+                       lws = 1; 
                        continue; 
                } 
                msgbuf[t++] = msgbuf[h++]; 
-               lws = 1; 
-               continue; 
-       } 
-       msgbuf[t++] = msgbuf[h++]; 
-       if (lws) 
-               lws = 0; 
+               if (lws) 
+                       lws = 0; 
        } 
        msgbuf[t] = '\0'; 
        return t; 
@@ -2607,7 +2617,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
        int codec;
        int iterator;
        int sendonly = 0;
-       int x;
+       int x,y;
        int debug=sip_debug_test_pvt(p);
 
        /* Update our last rtprx when we receive an SDP, too */
@@ -2635,9 +2645,10 @@ 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)) {
+               if ((sscanf(m, "audio %d RTP/AVP %n", &x, &len) == 1) ||
+                   (sscanf(m, "audio %d/%d RTP/AVP %n", &x, &y, &len) == 2)) {
                        portno = x;
                        /* Scan through the RTP payload types specified in a "m=" line: */
                        ast_rtp_pt_clear(p->rtp);
@@ -2659,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;
@@ -2734,7 +2745,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
        p->noncodeccapability = noncodeccapability & peernoncodeccapability;
        
        if (debug) {
-               const unsigned slen=80;
+               /* shame on whoever coded this.... */
+               const unsigned slen=512;
                char s1[slen], s2[slen], s3[slen], s4[slen];
 
                ast_verbose("Capabilities: us - %s, peer - audio=%s/video=%s, combined - %s\n",
@@ -2754,21 +2766,23 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
        }
        if (p->owner) {
                if (!(p->owner->nativeformats & p->jointcapability)) {
-                       const unsigned slen=80;
+                       const unsigned slen=512;
                        char s1[slen], s2[slen];
                        ast_log(LOG_DEBUG, "Oooh, we need to change our formats since our peer supports only %s and not %s\n", 
                                        ast_getformatname_multiple(s1, slen, p->jointcapability),
                                        ast_getformatname_multiple(s2, slen, p->owner->nativeformats));
-                       p->owner->nativeformats = sip_codec_choose(p->jointcapability);
+                       p->owner->nativeformats = ast_codec_choose(&p->prefs, p->jointcapability, 1);
                        ast_set_read_format(p->owner, p->owner->readformat);
                        ast_set_write_format(p->owner, p->owner->writeformat);
                }
-               if (p->owner->bridge) {
+               if (ast_bridged_channel(p->owner)) {
                        /* Turn on/off music on hold if we are holding/unholding */
                        if (sin.sin_addr.s_addr && !sendonly) {
-                               ast_moh_stop(p->owner->bridge);
+                               ast_moh_stop(ast_bridged_channel(p->owner));
                        } else {
-                               ast_moh_start(p->owner->bridge, NULL);
+                               ast_moh_start(ast_bridged_channel(p->owner), NULL);
+                               if (sendonly)
+                                       ast_rtp_stop(p->rtp);
                        }
                }
        }
@@ -2779,6 +2793,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
 /*--- add_header: Add header to SIP message */
 static int add_header(struct sip_request *req, char *var, char *value)
 {
+       int x = 0;
+       char *shortname = "";
        if (req->len >= sizeof(req->data) - 4) {
                ast_log(LOG_WARNING, "Out of space, can't add anymore (%s:%s)\n", var, value);
                return -1;
@@ -2787,8 +2803,18 @@ static int add_header(struct sip_request *req, char *var, char *value)
                ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
                return -1;
        }
+
        req->header[req->headers] = req->data + req->len;
-       snprintf(req->header[req->headers], sizeof(req->data) - req->len - 4, "%s: %s\r\n", var, value);
+       if (compactheaders) {
+               for (x=0;x<sizeof(aliases) / sizeof(aliases[0]); x++)
+                       if (!strcasecmp(aliases[x].fullname, var))
+                               shortname = aliases[x].shortname;
+       }
+       if(!ast_strlen_zero(shortname)) {
+               snprintf(req->header[req->headers], sizeof(req->data) - req->len - 4, "%s: %s\r\n", shortname, value);
+       } else {
+               snprintf(req->header[req->headers], sizeof(req->data) - req->len - 4, "%s: %s\r\n", var, value);
+       }
        req->len += strlen(req->header[req->headers]);
        if (req->headers < SIP_MAX_HEADERS)
                req->headers++;
@@ -2898,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.  */
@@ -3044,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;
@@ -3051,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);
@@ -3087,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;
@@ -3108,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);
@@ -3154,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 {
@@ -3288,13 +3326,13 @@ static int add_digit(struct sip_request *req, char digit)
 /*--- add_sdp: Add Session Description Protocol message ---*/
 static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
 {
-       int len;
-       int codec;
+       int len = 0;
+       int codec = 0;
+       int pref_codec = 0;
        int alreadysent = 0;
        char costr[80];
        struct sockaddr_in sin;
        struct sockaddr_in vsin;
-       struct sip_codec_pref *cur;
        char v[256] = "";
        char s[256] = "";
        char o[256] = "";
@@ -3305,11 +3343,13 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
        char a[1024] = "";
        char a2[1024] = "";
        char iabuf[INET_ADDRSTRLEN];
-       int x;
-       int capability;
+       int x = 0;
+       int capability = 0 ;
        struct sockaddr_in dest;
        struct sockaddr_in vdest = { 0, };
-       int debug=sip_debug_test_pvt(p);
+       int debug=0;
+       
+       debug = sip_debug_test_pvt(p);
 
        /* XXX We break with the "recommendation" and send our IP, in order that our
               peer doesn't have to ast_gethostbyname() us XXX */
@@ -3361,6 +3401,7 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
        snprintf(t, sizeof(t), "t=0 0\r\n");
        snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port));
        snprintf(m2, sizeof(m2), "m=video %d RTP/AVP", ntohs(vdest.sin_port));
+       /* Prefer the codec we were requested to use, first, no matter what */
        if (capability & p->prefcodec) {
                if (debug)
                        ast_verbose("Answering/Requesting with root capability %d\n", p->prefcodec);
@@ -3380,33 +3421,34 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
                alreadysent |= p->prefcodec;
        }
        /* Start by sending our preferred codecs */
-       cur = prefs;
-       while(cur) {
-               if ((capability & cur->codec) && !(alreadysent & cur->codec)) {
+       for (x = 0 ; x < 32 ; x++) {
+               if(!(pref_codec = ast_codec_pref_index(&p->prefs,x)))
+                       break; 
+               if ((capability & pref_codec) && !(alreadysent & pref_codec)) {
                        if (debug)
-                               ast_verbose("Answering with preferred capability 0x%x(%s)\n", cur->codec, ast_getformatname(cur->codec));
-                       codec = ast_rtp_lookup_code(p->rtp, 1, cur->codec);
+                               ast_verbose("Answering with preferred capability 0x%x (%s)\n", pref_codec, ast_getformatname(pref_codec));
+                       codec = ast_rtp_lookup_code(p->rtp, 1, pref_codec);
                        if (codec > -1) {
                                snprintf(costr, sizeof(costr), " %d", codec);
-                               if (cur->codec <= AST_FORMAT_MAX_AUDIO) {
+                               if (pref_codec <= AST_FORMAT_MAX_AUDIO) {
                                        strncat(m, costr, sizeof(m) - strlen(m) - 1);
-                                       snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(1, cur->codec));
+                                       snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(1, pref_codec));
                                        strncat(a, costr, sizeof(a) - strlen(a) - 1);
                                } else {
                                        strncat(m2, costr, sizeof(m2) - strlen(m2) - 1);
-                                       snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/90000\r\n", codec, ast_rtp_lookup_mime_subtype(1, cur->codec));
+                                       snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/90000\r\n", codec, ast_rtp_lookup_mime_subtype(1, pref_codec));
                                        strncat(a2, costr, sizeof(a2) - strlen(a) - 1);
                                }
                        }
                }
-               alreadysent |= cur->codec;
-               cur = cur->next;
+               alreadysent |= pref_codec;
        }
+
        /* Now send any other common codecs, and non-codec formats: */
        for (x = 1; x <= ((videosupport && p->vrtp) ? AST_FORMAT_MAX_VIDEO : AST_FORMAT_MAX_AUDIO); x <<= 1) {
                if ((capability & x) && !(alreadysent & x)) {
                        if (debug)
-                               ast_verbose("Answering with capability 0x%x(%s)\n", x, ast_getformatname(x));
+                               ast_verbose("Answering with capability 0x%x (%s)\n", x, ast_getformatname(x));
                        codec = ast_rtp_lookup_code(p->rtp, 1, x);
                        if (codec > -1) {
                                snprintf(costr, sizeof(costr), " %d", codec);
@@ -3425,7 +3467,7 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
        for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
                if (p->noncodeccapability & x) {
                        if (debug)
-                               ast_verbose("Answering with non-codec capability 0x%x(%s)\n", x, ast_getformatname(x));
+                               ast_verbose("Answering with non-codec capability 0x%x (%s)\n", x, ast_rtp_lookup_mime_subtype(0, x));
                        codec = ast_rtp_lookup_code(p->rtp, 0, x);
                        if (codec > -1) {
                                snprintf(costr, sizeof(costr), " %d", codec);
@@ -3433,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);
@@ -3449,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");
@@ -3461,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);
        }
@@ -3485,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;
@@ -3546,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;
     }
@@ -3560,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);
@@ -3581,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);
 }
 
@@ -3626,6 +3671,34 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, char *cmd, c
        char tmp[80];
        char iabuf[INET_ADDRSTRLEN];
        char *l = default_callerid, *n=NULL;
+       int x;
+       char urioptions[256]="";
+
+       if (ast_test_flag(p, SIP_USEREQPHONE)) {
+               char onlydigits = 1;
+               x=0;
+
+               /* Test p->username against allowed characters in AST_DIGIT_ANY
+               If it matches the allowed characters list, then sipuser = ";user=phone"
+
+               If not, then sipuser = ""
+               */
+               /* + is allowed in first position in a tel: uri */
+               if (p->username && p->username[0] == '+')
+                       x=1;
+
+               for (;x<strlen(p->username);x++) {
+                       if (!strchr(AST_DIGIT_ANY, p->username[x])) {
+                               onlydigits = 0;
+                               break;
+                       }
+               }
+
+               /* If we have only digits, add ;user=phone to the uri */
+               if (onlydigits)
+                       strcpy(urioptions, ";user=phone");
+       }
+
 
        snprintf(p->lastmsg, sizeof(p->lastmsg), "Init: %s", cmd);
 
@@ -3658,14 +3731,14 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, char *cmd, c
        /* Otherwise, use the username while waiting for registration */
        } else if (!ast_strlen_zero(p->username)) {
                if (ntohs(p->sa.sin_port) != DEFAULT_SIP_PORT) {
-                       snprintf(invite, sizeof(invite), "sip:%s@%s:%d",p->username, p->tohost, ntohs(p->sa.sin_port));
+                       snprintf(invite, sizeof(invite), "sip:%s@%s:%d%s",p->username, p->tohost, ntohs(p->sa.sin_port), urioptions);
                } else {
-                       snprintf(invite, sizeof(invite), "sip:%s@%s",p->username, p->tohost);
+                       snprintf(invite, sizeof(invite), "sip:%s@%s%s",p->username, p->tohost, urioptions);
                }
        } else if (ntohs(p->sa.sin_port) != DEFAULT_SIP_PORT) {
-               snprintf(invite, sizeof(invite), "sip:%s:%d", p->tohost, ntohs(p->sa.sin_port));
+               snprintf(invite, sizeof(invite), "sip:%s:%d%s", p->tohost, ntohs(p->sa.sin_port), urioptions);
        } else {
-               snprintf(invite, sizeof(invite), "sip:%s", p->tohost);
+               snprintf(invite, sizeof(invite), "sip:%s%s", p->tohost, urioptions);
        }
        strncpy(p->uri, invite, sizeof(p->uri) - 1);
        /* If there is a VXML URL append it to the SIP URL */
@@ -3695,8 +3768,8 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, char *cmd, c
 }
 
         
-/*--- transmit_invite: Build REFER/INVITE/OPTIONS message and trasmit 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 init)
+/*--- 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;
        char iabuf[INET_ADDRSTRLEN];
@@ -3704,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);
@@ -3731,6 +3804,47 @@ static int transmit_invite(struct sip_pvt *p, char *cmd, int sdp, char *auth, ch
                add_header(&req, "Alert-info",distinctive_ring);
        }
        add_header(&req, "Allow", ALLOWED_METHODS);
+       if (addsipheaders && init) {
+               struct ast_channel *ast;
+               char *header = (char *) NULL;
+               char *content = (char *) NULL;
+               char *end = (char *) NULL;
+               struct varshead *headp = (struct varshead *) NULL;
+               struct ast_var_t *current;
+
+               ast = p->owner; /* The owner channel */
+               if (ast) {
+                       headp=&ast->varshead;
+                       if (!headp)
+                               ast_log(LOG_WARNING,"No Headp for the channel...ooops!\n");
+                       else {
+                               AST_LIST_TRAVERSE(headp,current,entries) {  
+                                       /* SIPADDHEADER: Add SIP header to outgoing call        */
+                                       if (!strncasecmp(ast_var_name(current),"SIPADDHEADER",strlen("SIPADDHEADER"))) {
+                                               header = ast_var_value(current);
+                                               /* Strip of the starting " (if it's there) */
+                                               if (*header == '"')
+                                                       header++;
+                                       if ((content = strchr(header, ':'))) {
+                                                       *content = '\0';
+                                                       content++;      /* Move pointer ahead */
+                                                       /* Skip white space */
+                                                       while (*content == ' ')
+                                                               content++;
+                                                       /* Strip the ending " (if it's there) */
+                                                       end = content + strlen(content) -1;     
+                                                       if (*end == '"')
+                                                               *end = '\0';
+                                               
+                                                       add_header(&req, header, content);
+                                                       if (sipdebug)
+                                                               ast_log(LOG_DEBUG, "Adding SIP Header \"%s\" with content :%s: \n", header, content);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
        if (sdp) {
                ast_rtp_offered_from_local(p->rtp, 1);
                add_sdp(&req, p);
@@ -3872,10 +3986,10 @@ static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs)
        char clen[20];
        initreqprep(&req, p, "NOTIFY", NULL);
        add_header(&req, "Event", "message-summary");
-       add_header(&req, "Content-Type", notifymime);
+       add_header(&req, "Content-Type", default_notifymime);
 
        snprintf(tmp, sizeof(tmp), "Messages-Waiting: %s\r\n", newmsgs ? "yes" : "no");
-       snprintf(tmp2, sizeof(tmp2), "Voicemail: %d/%d\r\n", newmsgs, oldmsgs);
+       snprintf(tmp2, sizeof(tmp2), "Voice-Message: %d/%d\r\n", newmsgs, oldmsgs);
        snprintf(clen, sizeof(clen), "%d", (int)(strlen(tmp) + strlen(tmp2)));
        add_header(&req, "Content-Length", clen);
        add_line(&req, tmp);
@@ -3954,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;
 }
 
@@ -3973,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;
@@ -4019,44 +4148,55 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
                if (!auth) {
                        ast_log(LOG_WARNING, "Already have a call??\n");
                        return 0;
-               } else
+               } else {
                        p = r->call;
+                       p->tag = rand();        /* create a new local tag for every register attempt */
+                       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 {
                        if (!ast_strlen_zero(r->username)) {
                                strncpy(p->peername, r->username, sizeof(p->peername)-1);
                                strncpy(p->authname, r->username, sizeof(p->authname)-1);
+                               strncpy(p->fromuser, r->username, sizeof(p->fromuser)-1);
                        }
                }
                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);
 
                /*
@@ -4072,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, '@')) {
@@ -4101,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);
@@ -4115,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);
@@ -4149,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");
@@ -4211,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);
@@ -4231,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;
@@ -4279,8 +4440,9 @@ static void reg_source_db(struct sip_peer *p)
                                                strncpy(p->username, u, sizeof(p->username) - 1);
                                                
                                        }
-                                       ast_verbose(VERBOSE_PREFIX_3 "SIP Seeding '%s' at %s@%s:%d for %d\n", p->name, 
-                                               p->username, ast_inet_ntoa(iabuf, sizeof(iabuf), in), atoi(c), atoi(d));
+                                       if (option_verbose > 2)
+                                               ast_verbose(VERBOSE_PREFIX_3 "SIP Seeding '%s' at %s@%s:%d for %d\n", p->name, 
+                                                                       p->username, ast_inet_ntoa(iabuf, sizeof(iabuf), in), atoi(c), atoi(d));
                                        expiry = atoi(d);
                                        memset(&p->addr, 0, sizeof(p->addr));
                                        p->addr.sin_family = AF_INET;
@@ -4304,30 +4466,16 @@ static void reg_source_db(struct sip_peer *p)
        }
 }
 
-/*--- parse_contact: Parse contact header and save registration ---*/
-static int parse_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_request *req)
+/*--- 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[80]= ""; 
-       char data[256];
-       char iabuf[INET_ADDRSTRLEN];
-       char *expires = get_header(req, "Expires");
-       int expiry = atoi(expires);
+       char contact[250]= ""; 
        char *c, *n, *pt;
        int port;
-       char *useragent;
        struct hostent *hp;
        struct ast_hostent ahp;
        struct sockaddr_in oldsin;
-       if (ast_strlen_zero(expires)) {
-               expires = strstr(get_header(req, "Contact"), "expires=");
-               if (expires) {
-                       if (sscanf(expires + 8, "%d;", &expiry) != 1)
-                               expiry = default_expiry;
-               } else {
-                       /* Nothing has been specified */
-                       expiry = default_expiry;
-               }
-       }
+
        /* Look for brackets */
        strncpy(contact, get_header(req, "Contact"), sizeof(contact) - 1);
        c = contact;
@@ -4339,35 +4487,25 @@ static int parse_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_req
                if (n) 
                        *n = '\0';
        }
-       if (!strcasecmp(c, "*") || !expiry) {
-               /* This means remove all registrations and return OK */
-               memset(&p->addr, 0, sizeof(p->addr));
-               if (p->expire > -1)
-                       ast_sched_del(sched, p->expire);
-               p->expire = -1;
-               ast_db_del("SIP/Registry", p->name);
-               register_peer_exten(p, 0);
-               p->fullcontact[0] = '\0';
-               p->useragent[0] = '\0';
-               p->lastms = 0;
-               if (option_verbose > 2)
-                       ast_verbose(VERBOSE_PREFIX_3 "Unregistered SIP '%s'\n", p->name);
-                       manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Unregistered\r\n", p->name);
-               return 0;
-       }
-       strncpy(p->fullcontact, c, sizeof(p->fullcontact) - 1);
-       /* For the 200 OK, we should use the received contact */
-       snprintf(pvt->our_contact, sizeof(pvt->our_contact) - 1, "<%s>", c);
+
+
+       /* 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 q */
+
+       /* Ditch arguments */
        n = strchr(c, ';');
-       if (n) {
+       if (n) 
                *n = '\0';
-       }
+
        /* Grab host */
        n = strchr(c, '@');
        if (!n) {
@@ -4384,15 +4522,118 @@ static int parse_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_req
                port = atoi(pt);
        } else
                port = DEFAULT_SIP_PORT;
-       memcpy(&oldsin, &p->addr, sizeof(oldsin));
-       if (!(p->nat & SIP_NAT_ROUTE)) {
+
+       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;
                }
-               p->addr.sin_family = AF_INET;
+               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)
+{
+       char contact[80]= ""; 
+       char data[256];
+       char iabuf[INET_ADDRSTRLEN];
+       char *expires = get_header(req, "Expires");
+       int expiry = atoi(expires);
+       char *c, *n, *pt;
+       int port;
+       char *useragent;
+       struct hostent *hp;
+       struct ast_hostent ahp;
+       struct sockaddr_in oldsin;
+       if (ast_strlen_zero(expires)) {
+               expires = strstr(get_header(req, "Contact"), "expires=");
+               if (expires) {
+                       if (sscanf(expires + 8, "%d;", &expiry) != 1)
+                               expiry = default_expiry;
+               } else {
+                       /* Nothing has been specified */
+                       expiry = default_expiry;
+               }
+       }
+       /* 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';
+       }
+       if (!strcasecmp(c, "*") || !expiry) {
+               /* This means remove all registrations and return OK */
+               memset(&p->addr, 0, sizeof(p->addr));
+               if (p->expire > -1)
+                       ast_sched_del(sched, p->expire);
+               p->expire = -1;
+               ast_db_del("SIP/Registry", p->name);
+               register_peer_exten(p, 0);
+               p->fullcontact[0] = '\0';
+               p->useragent[0] = '\0';
+               p->lastms = 0;
+               if (option_verbose > 2)
+                       ast_verbose(VERBOSE_PREFIX_3 "Unregistered SIP '%s'\n", p->name);
+                       manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Unregistered\r\n", p->name);
+               return 0;
+       }
+       strncpy(p->fullcontact, c, sizeof(p->fullcontact) - 1);
+       /* For the 200 OK, we should use the received contact */
+       snprintf(pvt->our_contact, sizeof(pvt->our_contact) - 1, "<%s>", c);
+       /* 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 q */
+       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, &p->addr, sizeof(oldsin));
+       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)  {
+                       ast_log(LOG_WARNING, "Invalid host '%s'\n", n);
+                       return -1;
+               }
+               p->addr.sin_family = AF_INET;
                memcpy(&p->addr.sin_addr, hp->h_addr, sizeof(p->addr.sin_addr));
                p->addr.sin_port = htons(port);
        } else {
@@ -4408,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;
@@ -4458,7 +4699,7 @@ static void list_route(struct sip_route *route)
        }
 }
 
-/*--- build_route: Build route headers ---*/
+/*--- build_route: Build route list from Record-Route header ---*/
 static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards)
 {
        struct sip_route *thishop, *head, *tail;
@@ -4587,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;
@@ -4600,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 */
@@ -4614,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 
@@ -4765,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);
@@ -4799,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)) {
@@ -4821,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;
 }
 
@@ -5141,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));
@@ -5220,7 +5453,8 @@ static int get_rpid_num(char *input,char *output, int maxlen)
        end = strchr(output,'@');
        if (end)
                *end = '\0';
-
+       else
+               output[0] = '\0';
        if(strstr(input,"privacy=full") || strstr(input,"privacy=uri"))
                return AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
 
@@ -5240,6 +5474,7 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
        char *t;
        char calleridname[50];
        int debug=sip_debug_test_addr(sin);
+       struct ast_variable *tmpvar = NULL, *v = NULL;
 
        /* Terminate URI */
        t = uri;
@@ -5254,7 +5489,7 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
        rpid = get_header(req, "Remote-Party-ID");
        memset(rpid_num,0,sizeof(rpid_num));
        if(!ast_strlen_zero(rpid)) 
-         p->callingpres = get_rpid_num(rpid,rpid_num, sizeof(rpid_num));
+               p->callingpres = get_rpid_num(rpid,rpid_num, sizeof(rpid_num));
 
        of = ditch_braces(from);
        if (ast_strlen_zero(p->exten)) {
@@ -5282,35 +5517,38 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
        if (*calleridname)
                strncpy(p->cid_name, calleridname, sizeof(p->cid_name) - 1);
        if (ast_strlen_zero(of))
-                       return 0;
-       ast_mutex_lock(&userl.lock);
+               return 0;
        user = find_user(of);
        /* Find user based on user name in the from header */
-       if (user && ast_apply_ha(user->ha, sin)) {
-               p->nat = user->nat;
-#ifdef OSP_SUPPORT
-               p->ospauth = user->ospauth;
-#endif
-               p->trustrpid = user->trustrpid;
-               p->progressinband = user->progressinband;
+       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))) {
+                               tmpvar->next = p->vars; 
+                               p->vars = tmpvar;
+                       }
+               }
+               p->prefs = user->prefs;
                /* replace callerid if rpid found, and not restricted */
-               if(!ast_strlen_zero(rpid_num) && p->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);
+               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);
                }
 
                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))  {
@@ -5325,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;
@@ -5334,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 
@@ -5368,38 +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->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 (*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);
+                       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)
@@ -5408,45 +5633,46 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
                                        strncpy(p->username, peer->username, sizeof(p->username) - 1);
                                        strncpy(p->authname, peer->username, sizeof(p->authname) - 1);
                                }
+                               if (!ast_strlen_zero(peer->cid_num) && !ast_strlen_zero(p->cid_num))  {
+                                       strncpy(p->cid_num, peer->cid_num, sizeof(p->cid_num) - 1);
+                                       ast_shrink_phone_number(p->cid_num);
+                               }
+                               if (!ast_strlen_zero(peer->cid_name) && !ast_strlen_zero(p->cid_name)) 
+                                       strncpy(p->cid_name, peer->cid_name, sizeof(p->cid_name) - 1);
                                strncpy(p->fullcontact, peer->fullcontact, sizeof(p->fullcontact) - 1);
                                if (!ast_strlen_zero(peer->context))
                                        strncpy(p->context, peer->context, sizeof(p->context) - 1);
                                strncpy(p->peersecret, peer->secret, sizeof(p->peersecret) - 1);
                                strncpy(p->peermd5secret, peer->md5secret, sizeof(p->peermd5secret) - 1);
+                               strncpy(p->language, peer->language, sizeof(p->language)  -1);
                                p->callgroup = peer->callgroup;
                                p->pickupgroup = peer->pickupgroup;
                                p->capability = peer->capability;
                                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;
 }
+
+/*--- check_user: Find user ---*/
 static int check_user(struct sip_pvt *p, struct sip_request *req, char *cmd, char *uri, int reliable, struct sockaddr_in *sin, int ignore)
 {
        return check_user_full(p, req, cmd, uri, reliable, sin, ignore, NULL, 0);
 }
-/*--- get_msg_text: Get text out of a SIP MESSAGE ---*/
+
+/*--- get_msg_text: Get text out of a SIP MESSAGE packet ---*/
 static int get_msg_text(char *buf, int len, struct sip_request *req)
 {
        int x;
@@ -5474,6 +5700,7 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req)
 {
        char buf[1024];
        struct ast_frame f;
+
        if (get_msg_text(buf, sizeof(buf), req)) {
                ast_log(LOG_WARNING, "Unable to retrieve text from %s\n", p->callid);
                return;
@@ -5481,13 +5708,13 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req)
        if (p->owner) {
                if (sip_debug_test_pvt(p))
                        ast_verbose("Message received: '%s'\n", buf);
-                 memset(&f, 0, sizeof(f));
-                 f.frametype = AST_FRAME_TEXT;
-                 f.subclass = 0;
-                 f.offset = 0;
-                 f.data = buf;
-                 f.datalen = strlen(buf);
-                 ast_queue_frame(p->owner, &f);
+               memset(&f, 0, sizeof(f));
+               f.frametype = AST_FRAME_TEXT;
+               f.subclass = 0;
+               f.offset = 0;
+               f.data = buf;
+               f.datalen = strlen(buf);
+               ast_queue_frame(p->owner, &f);
        }
 }
 
@@ -5496,30 +5723,29 @@ 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];
        char oused[40];
+
        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
@@ -5545,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
 }
@@ -5568,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;
@@ -5578,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++;
@@ -5614,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++;
@@ -5622,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) ? " N " : "   ",    /* 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])) {
@@ -5642,51 +5868,83 @@ 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) );
+}
+
+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>";
+}
 
- 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);
+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";
        }
-    }
- ast_cli(fd, " (%u)\n", group);
+       return "<error>";
 }
 
 /*--- sip_show_peer: Show one peer in detail ---*/
 static int sip_show_peer(int fd, int argc, char *argv[])
 {
        char status[30] = "";
+       char cbuf[256];
        char iabuf[INET_ADDRSTRLEN];
        struct sip_peer *peer;
+       char codec_buf[512];
+       struct ast_codec_pref *pref;
+       int x = 0, codec = 0;
 
        if (argc != 4)
                return RESULT_SHOWUSAGE;
-       ast_mutex_lock(&peerl.lock);
        peer = find_peer(argv[3], NULL);
        if (peer) {
                ast_cli(fd,"\n\n");
@@ -5703,62 +5961,42 @@ 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, "  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));
                ast_cli(fd, "  Defaddr->IP  : %s Port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port));
                ast_cli(fd, "  Username     : %s\n", peer->username);
                ast_cli(fd, "  Codecs       : ");
-               /* This should really be a function in frame.c */
-               if (peer->capability & AST_FORMAT_G723_1)
-                               ast_cli(fd, "G723 ");
-               if (peer->capability & AST_FORMAT_GSM)
-                       ast_cli(fd, "GSM ");
-               if (peer->capability & AST_FORMAT_ULAW)
-                       ast_cli(fd, "ULAW ");
-               if (peer->capability & AST_FORMAT_ALAW)
-                       ast_cli(fd, "ALAW ");
-               if (peer->capability & AST_FORMAT_G726)
-                       ast_cli(fd, "G.726 ");
-               if (peer->capability & AST_FORMAT_SLINEAR)
-                       ast_cli(fd, "SLINR ");
-               if (peer->capability & AST_FORMAT_LPC10)
-                       ast_cli(fd, "LPC10 ");
-               if (peer->capability & AST_FORMAT_ADPCM)
-                       ast_cli(fd, "ADPCM ");
-               if (peer->capability & AST_FORMAT_G729A)
-                       ast_cli(fd, "G.729A ");
-               if (peer->capability & AST_FORMAT_SPEEX)
-                       ast_cli(fd, "SPEEX ");
-               if (peer->capability & AST_FORMAT_ILBC)
-                       ast_cli(fd, "ILBC ");
-               if (peer->capability & AST_FORMAT_JPEG)
-                       ast_cli(fd, "JPEG ");
-               if (peer->capability & AST_FORMAT_PNG)
-                       ast_cli(fd, "PNG ");
-               if (peer->capability & AST_FORMAT_H261)
-                       ast_cli(fd, "H.261 ");
-               if (peer->capability & AST_FORMAT_H263)   
-                       ast_cli(fd, "H.263 ");
-               ast_cli(fd, "\n");
+               ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability);
+               ast_cli(fd, "%s\n", codec_buf);
+               ast_cli(fd, "  Codec Order  : (");
+               pref = &peer->prefs;
+               for(x = 0; x < 32 ; x++) {
+                       codec = ast_codec_pref_index(pref,x);
+                       if(!codec)
+                               break;
+                       ast_cli(fd, "%s", ast_getformatname(codec));
+                       if(x < 31 && ast_codec_pref_index(pref,x+1))
+                               ast_cli(fd, "|");
+               }
+
+               if (!x)
+                       ast_cli(fd, "none");
+               ast_cli(fd, ")\n");
+
                ast_cli(fd, "  Status       : ");
                if (peer->lastms < 0)
                        strncpy(status, "UNREACHABLE", sizeof(status) - 1);
@@ -5772,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;
 }
 
@@ -5790,18 +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
@@ -5835,31 +6068,31 @@ static int __sip_show_channels(int fd, int argc, char *argv[], int subscriptions
        ast_mutex_lock(&iflock);
        cur = iflist;
        if (!subscriptions)
-          ast_cli(fd, FORMAT2, "Peer", "User/ANR", "Call ID", "Seq (Tx/Rx)",  "Format");
+               ast_cli(fd, FORMAT2, "Peer", "User/ANR", "Call ID", "Seq (Tx/Rx)",  "Format");
        else
-           ast_cli(fd, FORMAT3, "Peer", "User", "Call ID", "URI");
+               ast_cli(fd, FORMAT3, "Peer", "User", "Call ID", "URI");
        while (cur) {
                if (!cur->subscribed && !subscriptions) {
-                  ast_cli(fd, FORMAT, ast_inet_ntoa(iabuf, sizeof(iabuf), cur->sa.sin_addr), 
-                       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)" : "" );
-               numchans++;
+                       ast_cli(fd, FORMAT, ast_inet_ntoa(iabuf, sizeof(iabuf), cur->sa.sin_addr), 
+                               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), ast_test_flag(cur, SIP_NEEDDESTROY) ? "(d)" : "" );
+                       numchans++;
                }
                if (cur->subscribed && subscriptions) {
-                   ast_cli(fd, FORMAT3, ast_inet_ntoa(iabuf, sizeof(iabuf), cur->sa.sin_addr),
-                       ast_strlen_zero(cur->username) ? ( ast_strlen_zero(cur->cid_num) ? "(None)" : cur->cid_num ) : cur->username, 
-                        cur->callid, cur->uri);
+                       ast_cli(fd, FORMAT3, ast_inet_ntoa(iabuf, sizeof(iabuf), cur->sa.sin_addr),
+                               ast_strlen_zero(cur->username) ? ( ast_strlen_zero(cur->cid_num) ? "(None)" : cur->cid_num ) : cur->username, 
+                               cur->callid, cur->uri);
 
                 }
                cur = cur->next;
        }
        ast_mutex_unlock(&iflock);
        if (!subscriptions)
-          ast_cli(fd, "%d active SIP channel(s)\n", numchans);
+               ast_cli(fd, "%d active SIP channel(s)\n", numchans);
        else
-          ast_cli(fd, "%d active SIP subscriptions(s)\n", numchans);
+               ast_cli(fd, "%d active SIP subscriptions(s)\n", numchans);
        return RESULT_SUCCESS;
 #undef FORMAT
 #undef FORMAT2
@@ -5872,6 +6105,7 @@ static char *complete_sipch(char *line, char *word, int pos, int state)
        int which=0;
        struct sip_pvt *cur;
        char *c = NULL;
+
        ast_mutex_lock(&iflock);
        cur = iflist;
        while(cur) {
@@ -5891,10 +6125,10 @@ 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;
+
        if (argc != 4)
                return RESULT_SHOWUSAGE;
        len = strlen(argv[3]);
@@ -5904,10 +6138,10 @@ static int sip_show_channel(int fd, int argc, char *argv[])
                if (!strncasecmp(cur->callid, argv[3],len)) {
                        ast_cli(fd,"\n");
                        if (cur->subscribed)
-                          ast_cli(fd, "  * Subscription\n");
+                               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, "  * SIP Call\n");
+                       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);
@@ -5916,30 +6150,23 @@ 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);
                        if (!ast_strlen_zero(cur->username))
-                          ast_cli(fd, "  Username:               %s\n", cur->username);
+                               ast_cli(fd, "  Username:               %s\n", cur->username);
                        if (!ast_strlen_zero(cur->peername))
-                          ast_cli(fd, "  Peername:               %s\n", cur->peername);
+                               ast_cli(fd, "  Peername:               %s\n", cur->peername);
                        if (!ast_strlen_zero(cur->uri))
-                          ast_cli(fd, "  Original uri:           %s\n", cur->uri);
+                               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, "  Caller-ID:              %s\n", cur->cid_num);
+                       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;
@@ -5958,6 +6185,7 @@ static int sip_show_history(int fd, int argc, char *argv[])
        size_t len;
        int x;
        int found = 0;
+
        if (argc != 4)
                return RESULT_SHOWUSAGE;
        if (!recordhistory)
@@ -5969,9 +6197,9 @@ static int sip_show_history(int fd, int argc, char *argv[])
                if (!strncasecmp(cur->callid, argv[3],len)) {
                        ast_cli(fd,"\n");
                        if (cur->subscribed)
-                          ast_cli(fd, "  * Subscription\n");
+                               ast_cli(fd, "  * Subscription\n");
                        else
-                          ast_cli(fd, "  * SIP Call\n");
+                               ast_cli(fd, "  * SIP Call\n");
                        x = 0;
                        hist = cur->history;
                        while(hist) {
@@ -6008,46 +6236,58 @@ static void receive_info(struct sip_pvt *p, struct sip_request *req)
 
                /* Try getting the "signal=" part */
                if (ast_strlen_zero(c = get_sdp(req, "Signal")) && ast_strlen_zero(c = get_sdp(req, "d"))) {
-                  ast_log(LOG_WARNING, "Unable to retrieve DTMF signal from INFO message from %s\n", p->callid);
-                  transmit_response(p, "200 OK", req); /* Should return error */
-                  return;
+                       ast_log(LOG_WARNING, "Unable to retrieve DTMF signal from INFO message from %s\n", p->callid);
+                       transmit_response(p, "200 OK", req); /* Should return error */
+                       return;
                } else {
-                  strncpy(buf, c, sizeof(buf) - 1);
+                       strncpy(buf, c, sizeof(buf) - 1);
                }
        
                if (p->owner) { /* PBX call */
-                  if (!ast_strlen_zero(buf)) {
-                       if (sipdebug)
-                               ast_verbose("* DTMF received: '%c'\n", buf[0]);
-                       if (buf[0] == '*')
-                               event = 10;
-                       else if (buf[0] == '#')
-                               event = 11;
-                       else
-                               event = atoi(buf);
-                        if (event < 10) {
-                                resp = '0' + event;
-                        } else if (event < 11) {
-                                resp = '*';
-                        } else if (event < 12) {
-                                resp = '#';
-                        } else if (event < 16) {
-                                resp = 'A' + (event - 12);
-                        }
-                       /* Build DTMF frame and deliver to PBX for transmission to other call leg*/
-                        memset(&f, 0, sizeof(f));
-                        f.frametype = AST_FRAME_DTMF;
-                        f.subclass = resp;
-                        f.offset = 0;
-                        f.data = NULL;
-                        f.datalen = 0;
-                        ast_queue_frame(p->owner, &f);
-                  }
-                  transmit_response(p, "200 OK", req);
-                  return;
+                       if (!ast_strlen_zero(buf)) {
+                               if (sipdebug)
+                                       ast_verbose("* DTMF received: '%c'\n", buf[0]);
+                               if (buf[0] == '*')
+                                       event = 10;
+                               else if (buf[0] == '#')
+                                       event = 11;
+                               else
+                                       event = atoi(buf);
+                               if (event < 10) {
+                                       resp = '0' + event;
+                               } else if (event < 11) {
+                                       resp = '*';
+                               } else if (event < 12) {
+                                       resp = '#';
+                               } else if (event < 16) {
+                                       resp = 'A' + (event - 12);
+                               }
+                               /* Build DTMF frame and deliver to PBX for transmission to other call leg*/
+                               memset(&f, 0, sizeof(f));
+                               f.frametype = AST_FRAME_DTMF;
+                               f.subclass = resp;
+                               f.offset = 0;
+                               f.data = NULL;
+                               f.datalen = 0;
+                               ast_queue_frame(p->owner, &f);
+                       }
+                       transmit_response(p, "200 OK", 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 (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)
+                               ast_cdr_setuserfield(ast_bridged_channel(p->owner), c);
+                       transmit_response(p, "200 OK", req);
+               } else {
+                       transmit_response(p, "403 Unauthorized", req);
                }
                return;
        }
@@ -6067,6 +6307,7 @@ static int sip_do_debug_ip(int fd, int argc, char *argv[])
        char iabuf[INET_ADDRSTRLEN];
        int port = 0;
        char *p, *arg;
+
        if (argc != 4)
                return RESULT_SHOWUSAGE;
        arg = argv[3];
@@ -6097,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;
@@ -6113,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;
@@ -6138,6 +6371,7 @@ static int sip_do_debug(int fd, int argc, char *argv[])
        return RESULT_SUCCESS;
 }
 
+/*--- sip_do_history: Enable SIP History logging (CLI) ---*/
 static int sip_do_history(int fd, int argc, char *argv[])
 {
        if (argc != 2) {
@@ -6148,6 +6382,7 @@ static int sip_do_history(int fd, int argc, char *argv[])
        return RESULT_SUCCESS;
 }
 
+/*--- sip_no_history: Disable SIP History logging (CLI) ---*/
 static int sip_no_history(int fd, int argc, char *argv[])
 {
        if (argc != 3) {
@@ -6170,28 +6405,35 @@ 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;
        }
-       return transmit_invite(p,msg,!strcasecmp(msg, "INVITE"),digest, respheader, NULL,NULL,NULL, init); 
+       /* Now we have a reply digest */
+       return transmit_invite(p,msg,!strcasecmp(msg, "INVITE"),digest, respheader, NULL,NULL,NULL, 0, init); 
 }
 
 /*--- reply_digest: reply to authentication for outbound registrations ---*/
@@ -6286,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;
 }
@@ -6402,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 =
@@ -6422,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 =
@@ -6450,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, '/');
@@ -6474,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);    
        }
 }
 
@@ -6500,6 +6758,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
        struct timeval tv;
        int seqno=0;
        char iabuf[INET_ADDRSTRLEN];
+
        c = get_header(req, "Cseq");
        if (sscanf(c, "%d ", &seqno) != 1) {
                ast_log(LOG_WARNING, "Unable to determine sequence number\n");
@@ -6567,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 */
@@ -6582,12 +6841,12 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                        p->initid = -1;
                }
                switch(resp) {
-               case 100:
+               case 100:       /* 100 Trying */
                        if (!strcasecmp(msg, "INVITE")) {
                                sip_cancel_destroy(p);
                        }
                        break;
-               case 183:       
+               case 183:       /* 183 Session Progress */
                        if (!strcasecmp(msg, "INVITE")) {
                                sip_cancel_destroy(p);
                                if (!ast_strlen_zero(get_header(req, "Content-Type")))
@@ -6598,7 +6857,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                }
                        }
                        break;
-               case 180:
+               case 180:       /* 180 Ringing */
                        if (!strcasecmp(msg, "INVITE")) {
                                sip_cancel_destroy(p);
                                if (p->owner) {
@@ -6608,7 +6867,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                }
                        }
                        break;
-               case 200:
+               case 200:       /* 200 OK */
                        if (!strcasecmp(msg, "NOTIFY")) {
                                /* They got the notify, this is the end */
                                if (p->owner) {
@@ -6616,13 +6875,19 @@ 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")) {
+                               /* 200 OK on invite - someone's answering our call */
                                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) {
@@ -6637,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);
@@ -6658,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)
@@ -6690,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:
+               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);
@@ -6729,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")) {
@@ -6738,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 */
@@ -6760,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);
@@ -6781,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 {
@@ -6820,9 +7106,19 @@ 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);
+                                       if (!ast_strlen_zero(get_header(req, "Content-Type")))
+                                               process_sdp(p, req);
+                                       if (p->owner) {
+                                               /* Queue a progress frame */
+                                               ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
+                                       }
+                               }
                        } else
                                ast_log(LOG_NOTICE, "Dunno anything about a %d %s response from %s\n", resp, rest, p->owner ? p->owner->name : ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr));
                }
@@ -6842,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;
@@ -6878,6 +7174,7 @@ static void *sip_park_thread(void *stuff)
        return NULL;
 }
 
+/*--- sip_park: Park a call ---*/
 static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req)
 {
        struct sip_dual *d;
@@ -6936,54 +7233,80 @@ static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct
        return -1;
 }
 
+static void ast_quiet_chan(struct ast_channel *chan) 
+{
+       if (chan && chan->_state == AST_STATE_UP) {
+               if (chan->generatordata)
+                       ast_deactivate_generator(chan);
+       }
+}
 
 /*--- attempt_transfer: Attempt transfer of SIP call ---*/
 static int attempt_transfer(struct sip_pvt *p1, struct sip_pvt *p2)
 {
+       int res = 0;
+       struct ast_channel 
+               *chana = NULL,
+               *chanb = NULL,
+               *bridgea = NULL,
+               *bridgeb = NULL,
+               *peera = NULL,
+               *peerb = NULL,
+               *peerc = NULL,
+               *peerd = NULL;
+
        if (!p1->owner || !p2->owner) {
                ast_log(LOG_WARNING, "Transfer attempted without dual ownership?\n");
                return -1;
        }
-       if (p1->owner->bridge) {
-               if (p2->owner->bridge)
-                       ast_moh_stop(p2->owner->bridge);
-               ast_moh_stop(p1->owner->bridge);
-               ast_moh_stop(p1->owner);
-               ast_moh_stop(p2->owner);
-               if (p1->owner->cdr) {
-                       p2->owner->cdr = ast_cdr_append(p2->owner->cdr, p1->owner->cdr);
-                       p1->owner->cdr = NULL;
-               }
-               if (p1->owner->bridge->cdr) {
-                       p2->owner->cdr = ast_cdr_append(p2->owner->cdr, p1->owner->bridge->cdr);
-                       p1->owner->bridge->cdr = NULL;
-               }
-               if (ast_channel_masquerade(p2->owner, p1->owner->bridge)) {
-                       ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", p2->owner->name, p1->owner->bridge->name);
-                       return -1;
-               }
-       } else if (p2->owner->bridge) {
-               ast_moh_stop(p2->owner->bridge);
-               ast_moh_stop(p2->owner);
-               ast_moh_stop(p1->owner);
-               if (p2->owner->cdr) {
-                       p1->owner->cdr = ast_cdr_append(p1->owner->cdr, p2->owner->cdr);
-                       p2->owner->cdr = NULL;
+       chana = p1->owner;
+       chanb = p2->owner;
+       bridgea = ast_bridged_channel(chana);
+       bridgeb = ast_bridged_channel(chanb);
+       
+       if (bridgea) {
+               peera = chana;
+               peerb = chanb;
+               peerc = bridgea;
+               peerd = bridgeb;
+       } else if (bridgeb) {
+               peera = chanb;
+               peerb = chana;
+               peerc = bridgeb;
+               peerd = bridgea;
+       }
+       
+       if (peera && peerb && peerc) {
+               ast_quiet_chan(peera);
+               ast_quiet_chan(peerb);
+               ast_quiet_chan(peerc);
+               ast_quiet_chan(peerd);
+
+               if (peera->cdr && peerb->cdr) {
+                       peerb->cdr = ast_cdr_append(peerb->cdr, peera->cdr);
+               } else if(peera->cdr) {
+                       peerb->cdr = peera->cdr;
                }
-               if (p2->owner->bridge->cdr) {
-                       p1->owner->cdr = ast_cdr_append(p1->owner->cdr, p2->owner->bridge->cdr);
-                       p2->owner->bridge->cdr = NULL;
+               peera->cdr = NULL;
+
+               if (peerb->cdr && peerc->cdr) {
+                       peerb->cdr = ast_cdr_append(peerb->cdr, peerc->cdr);
+               } else if(peerc->cdr) {
+                       peerb->cdr = peerc->cdr;
                }
-               if (ast_channel_masquerade(p1->owner, p2->owner->bridge)) {
-                       ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", p1->owner->name, p2->owner->bridge->name);
-                       return -1;
+               peerc->cdr = NULL;
+               
+               if (ast_channel_masquerade(peerb, peerc)) {
+                       ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", peerb->name, peerc->name);
+                       res = -1;
                }
+               return res;
        } else {
                ast_log(LOG_NOTICE, "Transfer attempted with no bridged calls to transfer\n");
-               if (p1->owner)
-                       ast_softhangup_nolock(p1->owner, AST_SOFTHANGUP_DEV);
-               if (p2->owner)
-                       ast_softhangup_nolock(p2->owner, AST_SOFTHANGUP_DEV);
+               if (chana)
+                       ast_softhangup_nolock(chana, AST_SOFTHANGUP_DEV);
+               if (chanb)
+                       ast_softhangup_nolock(chanb, AST_SOFTHANGUP_DEV);
                return -1;
        }
        return 0;
@@ -7020,7 +7343,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
        cmd = req->header[0];
        /* Must have Cseq */
        if (ast_strlen_zero(cmd) || ast_strlen_zero(cseq))
-                       return -1;
+               return -1;
        if (sscanf(cseq, "%i%n", &seqno, &len) != 1) {
                ast_log(LOG_DEBUG, "No seqno in '%s'\n", cmd);
                return -1;
@@ -7045,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)) {
+               } 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  */
@@ -7067,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);
@@ -7101,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 */
@@ -7118,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);
@@ -7135,7 +7458,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                                ast_queue_frame(p->owner, &af);
                } else if (debug)
                        ast_verbose("Ignoring this request\n");
-               if (!p->lastinvite) {
+               if (!p->lastinvite && !ignore && !p->owner) {
                        /* Handle authentication if this is our first invite */
                        res = check_user(p, req, cmd, e, 1, sin, ignore);
                        if (res) {
@@ -7145,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;
                        }
@@ -7158,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;
                        }
@@ -7182,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))
@@ -7231,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);
@@ -7260,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")) {
@@ -7288,12 +7611,12 @@ 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;
                                        if (c) {
-                                               transfer_to = c->bridge;
+                                               transfer_to = ast_bridged_channel(c);
                                                if (transfer_to) {
                                                        ast_moh_stop(transfer_to);
                                                        if (!strcmp(p->refer_to, ast_parking_ext())) {
@@ -7314,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);
@@ -7339,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);
@@ -7350,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);
@@ -7368,7 +7691,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                        if (!res) {
                                c = p->owner;
                                if (c) {
-                                       transfer_to = c->bridge;
+                                       transfer_to = ast_bridged_channel(c);
                                        if (transfer_to) {
                                                /* Don't actually hangup here... */
                                                ast_moh_stop(transfer_to);
@@ -7383,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) {
@@ -7398,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)
@@ -7406,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;
                        }
@@ -7428,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();
@@ -7436,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
@@ -7462,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 */
@@ -7489,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)
@@ -7515,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++;
@@ -7530,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;
 }
@@ -7614,6 +7947,7 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer)
        char name[256] = "";
        char iabuf[INET_ADDRSTRLEN];
        int newmsgs, oldmsgs;
+
        /* Check for messages */
        ast_app_messagecount(peer->mailbox, &newmsgs, &oldmsgs);
        
@@ -7621,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);
@@ -7643,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;
@@ -7660,12 +7991,13 @@ 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;
        int curpeernum;
        int reloading;
+
        /* Add an I/O event to our UDP socket */
        if (sipsock > -1) 
                ast_io_add(io, sipsock, sipsock_read, AST_IO_IN, NULL);
@@ -7716,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;
@@ -7746,27 +8078,29 @@ restartsearch:
                ast_mutex_lock(&monlock);
                if (res >= 0) 
                        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) > 10)) {
-                               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);
        }
@@ -7829,6 +8163,8 @@ static int sip_poke_noanswer(void *data)
 }
 
 /*--- sip_poke_peer: Check availability of peer, also keep NAT open ---*/
+/*     This is done with the interval in qualify= option in sip.conf */
+/*     Default is 2 seconds */
 static int sip_poke_peer(struct sip_peer *peer)
 {
        struct sip_pvt *p;
@@ -7854,6 +8190,12 @@ static int sip_poke_peer(struct sip_peer *peer)
        }
        memcpy(&p->sa, &peer->addr, sizeof(p->sa));
        memcpy(&p->recv, &peer->addr, sizeof(p->sa));
+
+       /* Send options to peer's fullcontact */
+       if (!ast_strlen_zero(peer->fullcontact)) {
+               strncpy (p->fullcontact, peer->fullcontact, sizeof(p->fullcontact));
+       }
+
        if (!ast_strlen_zero(p->tohost))
                strncpy(p->tohost, peer->tohost, sizeof(p->tohost) - 1);
        else
@@ -7863,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);
@@ -7872,12 +8214,12 @@ 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, 1);
+       transmit_invite(p, "INVITE", 0, NULL, NULL, NULL,NULL,NULL, 0, 1);
 #else
-       transmit_invite(p, "OPTIONS", 0, NULL, NULL, NULL,NULL,NULL, 1);
+       transmit_invite(p, "OPTIONS", 0, NULL, NULL, NULL,NULL,NULL, 0, 1);
 #endif
        gettimeofday(&peer->ps, NULL);
        peer->pokeexpire = ast_sched_add(sched, DEFAULT_MAXMS * 2, sip_poke_noanswer, peer);
@@ -7910,7 +8252,6 @@ static int sip_devicestate(void *data)
                ext = NULL;
        }
 
-       ast_mutex_lock(&peerl.lock);
        p = find_peer(host, NULL);
        if (p) {
                found++;
@@ -7921,22 +8262,20 @@ 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;
 }
 
 /*--- sip_request: PBX interface function -build SIP pvt structure ---*/
 /* SIP calls initiated by the PBX arrive here */
-static struct ast_channel *sip_request(const char *type, int format, void *data)
+static struct ast_channel *sip_request(const char *type, int format, void *data, int *cause)
 {
        int oldformat;
        struct sip_pvt *p;
@@ -7980,6 +8319,7 @@ static struct ast_channel *sip_request(const char *type, int format, void *data)
        p->capability = global_capability;
 
        if (create_addr(p, host)) {
+               *cause = AST_CAUSE_UNREGISTERED;
                sip_destroy(p);
                return NULL;
        }
@@ -7989,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);
@@ -8017,36 +8357,131 @@ 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)
 {
        struct sip_user *user;
        int format;
        struct ast_ha *oldha = NULL;
+       char *varname = NULL, *varval = NULL;
+       struct ast_variable *tmpvar = NULL;
+
        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;
-#ifdef OSP_SUPPORT
-               user->ospauth = global_ospauth;
-#endif
+               user->prefs = prefs;
                /* 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")) {
+                               varname = ast_strdupa(v->value);
+                               if (varname && (varval = strchr(varname,'='))) {
+                                       *varval = '\0';
+                                       varval++;
+                                       if((tmpvar = ast_new_variable(varname, varval))) {
+                                               tmpvar->next = user->vars;
+                                               user->vars = tmpvar;
+                                       }
+
+                               }
                        } else if (!strcasecmp(v->name, "permit") ||
                                           !strcasecmp(v->name, "deny")) {
                                user->ha = ast_append_ha(v->name, v->value, user->ha);
@@ -8054,36 +8489,8 @@ 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));
-                               user->hascallerid=1;
                        } else if (!strcasecmp(v->name, "callgroup")) {
                                user->callgroup = ast_get_group(v->value);
                        } else if (!strcasecmp(v->name, "pickupgroup")) {
@@ -8110,40 +8517,18 @@ static struct sip_user *build_user(const char *name, struct ast_variable *v)
                                        user->amaflags = format;
                                }
                        } else if (!strcasecmp(v->name, "allow")) {
-                               format = ast_getformatbyname(v->value);
-                               if (format < 1) 
-                                       ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
-                               else
-                                       user->capability |= format;
+                               ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 1);
                        } else if (!strcasecmp(v->name, "disallow")) {
-                               format = ast_getformatbyname(v->value);
-                               if (format < 1) 
-                                       ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
-                               else
-                                       user->capability &= ~format;
-                       } 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, "progressinband")) {
-                               user->progressinband = ast_true(v->value);
-#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;
@@ -8154,10 +8539,17 @@ static struct sip_peer *temp_peer(char *name)
 {
        struct sip_peer *peer;
        peer = malloc(sizeof(struct sip_peer));
+       if (!peer)
+               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);
@@ -8165,20 +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->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;
-#ifdef OSP_SUPPORT
-       peer->ospauth = global_ospauth;
-#endif
+       ast_set_flag(peer, SIP_SELFDESTRUCT);
+       ast_set_flag(peer, SIP_DYNAMIC);
+       peer->prefs = prefs;
        reg_source_db(peer);
        return peer;
 }
@@ -8186,46 +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 format;
+       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));
-               memset(peer, 0, sizeof(struct sip_peer));
-               peer->expire = -1;
-               peer->pokeexpire = -1;
+               if (peer) {
+                       memset(peer, 0, sizeof(struct sip_peer));
+                       if (temponly)
+                               rpeerobjs++;
+                       else
+                               speerobjs++;
+                       ASTOBJ_INIT(peer);
+                       peer->expire = -1;
+                       peer->pokeexpire = -1;
+               }
        }
-       peer->lastmsgssent = -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);
@@ -8233,72 +8611,54 @@ 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;
+                       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, "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, "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, "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, "promiscredir"))
-                               peer->promiscredir = ast_true(v->value);
+                       else if (!strcasecmp(v->name, "usereqphone"))
+                               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")) {
+                       else if (!strcasecmp(v->name, "host") || !strcasecmp(v->name, "outboundproxy")) {
                                if (!strcasecmp(v->value, "dynamic")) {
-                                       /* They'll register with us */
-                                       peer->dynamic = 1;
-                                       if (!found) {
-                                               /* Initialize stuff iff we're not found, otherwise
-                                                  we keep going with what we had */
-                                               memset(&peer->addr.sin_addr, 0, 4);
-                                               if (peer->addr.sin_port) {
-                                                       /* If we've already got a port, make it the default rather than absolute */
-                                                       peer->defaddr.sin_port = peer->addr.sin_port;
-                                                       peer->addr.sin_port = 0;
+                                       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 */
+                                               ast_set_flag(peer, SIP_DYNAMIC);
+                                               if (!found) {
+                                                       /* Initialize stuff iff we're not found, otherwise
+                                                          we keep going with what we had */
+                                                       memset(&peer->addr.sin_addr, 0, 4);
+                                                       if (peer->addr.sin_port) {
+                                                               /* If we've already got a port, make it the default rather than absolute */
+                                                               peer->defaddr.sin_port = peer->addr.sin_port;
+                                                               peer->addr.sin_port = 0;
+                                                       }
                                                }
                                        }
                                } else {
@@ -8306,18 +8666,23 @@ 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;
-                                       if (ast_get_ip(&peer->addr, v->value)) {
-                                               destroy_peer(peer);
-                                               return NULL;
+                                       ast_clear_flag(peer, SIP_DYNAMIC);      
+                                       if (!obproxyfound || !strcasecmp(v->name, "outboundproxy")) {
+                                               if (ast_get_ip_or_srv(&peer->addr, v->value, "_sip._udp")) {
+                                                       ASTOBJ_DESTROY(peer, sip_destroy_peer);
+                                                       return NULL;
+                                               }
                                        }
-                                       strncpy(peer->tohost, v->value, sizeof(peer->tohost) - 1);
+                                       if (!strcasecmp(v->name, "outboundproxy"))
+                                               obproxyfound=1;
+                                       else
+                                               strncpy(peer->tohost, v->value, sizeof(peer->tohost) - 1);
                                }
                                if (!maskfound)
                                        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") ||
@@ -8327,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));
@@ -8346,24 +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")) {
-                               format = ast_getformatbyname(v->value);
-                               if (format < 1) 
-                                       ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
-                               else
-                                       peer->capability |= format;
+                               ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 1);
                        } else if (!strcasecmp(v->name, "disallow")) {
-                               format = ast_getformatbyname(v->value);
-                               if (format < 1) 
-                                       ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
-                               else
-                                       peer->capability &= ~format;
-                       } 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);
@@ -8383,34 +8733,27 @@ 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, "trustrpid")) {
-                               peer->trustrpid = ast_true(v->value);
-                       } else if (!strcasecmp(v->name, "progressinband")) {
-                               peer->progressinband = ast_true(v->value);
-#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;
 }
 
 /*--- reload_config: Re-read SIP.conf config file ---*/
+/*     This function reloads all config data, except for
+       active peers (with registrations). They will only
+       change configuration data at restart, not at reload.
+       SIP debug and recordhistory state will not change
+ */
 static int reload_config(void)
 {
        struct ast_config *cfg;
@@ -8419,14 +8762,12 @@ static int reload_config(void)
        struct sip_user *user;
        struct ast_hostent ahp;
        char *cat;
-    char *utype;
+       char *utype;
        struct hostent *hp;
        int format;
        int oldport = ntohs(bindaddr.sin_port);
        char iabuf[INET_ADDRSTRLEN];
-
-       global_dtmfmode = SIP_DTMF_RFC2833;
-       global_promiscredir = 0;
+       struct ast_flags dummy;
        
        if (gethostname(ourhost, sizeof(ourhost))) {
                ast_log(LOG_WARNING, "Unable to get hostname, SIP disabled\n");
@@ -8440,30 +8781,54 @@ static int reload_config(void)
                return 0;
        }
        
-       global_nat = SIP_NAT_RFC3581;
-       
-       sip_prefs_free();
        
+       /* Reset IP addresses  */
        memset(&bindaddr, 0, sizeof(bindaddr));
        memset(&localaddr, 0, sizeof(localaddr));
        memset(&externip, 0, sizeof(externip));
+       memset(&prefs, 0 , sizeof(struct ast_codec_pref));
 
-       /* Initialize some reasonable defaults */
-       strncpy(default_context, "default", sizeof(default_context) - 1);
+       /* Initialize some reasonable defaults at SIP reload */
+       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(global_realm, "asterisk", sizeof(global_realm) - 1);
+       strncpy(default_notifymime, DEFAULT_NOTIFYMIME, sizeof(default_notifymime) - 1);
        global_realm[sizeof(global_realm)-1] = '\0';
-       global_canreinvite = REINVITE_INVITE;
+       strncpy(global_musicclass, "default", sizeof(global_musicclass) - 1);
+       strncpy(default_callerid, DEFAULT_CALLERID, sizeof(default_callerid) - 1);
+       memset(&outboundproxyip, 0, sizeof(outboundproxyip));
+       outboundproxyip.sin_port = htons(DEFAULT_SIP_PORT);
+       outboundproxyip.sin_family = AF_INET;   /* Type of address: IPv4 */
        videosupport = 0;
+       compactheaders = 0;
        relaxdtmf = 0;
        ourport = DEFAULT_SIP_PORT;
        global_rtptimeout = 0;
        global_rtpholdtimeout = 0;
-       pedanticsipchecking=0;
+       pedanticsipchecking = 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;
+       regcontext[0] = '\0';
+       tos = 0;
+       expiry = DEFAULT_EXPIRY;
+
+       /* 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);
@@ -8474,20 +8839,14 @@ static int reload_config(void)
                        strncpy(default_useragent, v->value, sizeof(default_useragent)-1);
                        ast_log(LOG_DEBUG, "Setting User Agent Name to %s\n",
                                default_useragent);
+               } else if (!strcasecmp(v->name, "usereqphone")) {
+                       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);
-