Remove unnecessary checks before calls to ast_strlen_zero. Also, change
[asterisk/asterisk.git] / channels / chan_iax2.c
index 8d727b2..354d107 100755 (executable)
@@ -1,14 +1,25 @@
 /*
- * Asterisk -- A telephony toolkit for Linux.
+ * Asterisk -- An open source telephony toolkit.
  *
- * Implementation of Inter-Asterisk eXchange Version 2
- *
- * Copyright (C) 2003 - 2005, Digium, Inc.
+ * Copyright (C) 1999 - 2005, Digium, Inc.
  *
  * Mark Spencer <markster@digium.com>
  *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
  * This program is free software, distributed under the terms of
- * the GNU General Public License
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Implementation of Inter-Asterisk eXchange Version 2
+ *
  */
 
 #include "asterisk.h"
@@ -42,6 +53,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/localtime.h"
 #include "asterisk/aes.h"
 #include "asterisk/dnsmgr.h"
+#include "asterisk/devicestate.h"
+#include "asterisk/netsock.h"
+
 #include <sys/mman.h>
 #include <arpa/inet.h>
 #include <dirent.h>
@@ -73,7 +87,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "iax2.h"
 #include "iax2-parser.h"
 #include "iax2-provision.h"
-#include "asterisk.h"
 
 /* Define NEWJB to use the new channel independent jitterbuffer,
  * otherwise, use the old jitterbuffer */
@@ -94,10 +107,11 @@ static int nochecksums = 0;
 /*
  * Uncomment to try experimental IAX bridge optimization,
  * designed to reduce latency when IAX calls cannot
- * be trasnferred
+ * be trasnferred -- obsolete
  */
 
-#define BRIDGE_OPTIMIZATION 
+/* #define BRIDGE_OPTIMIZATION  */
+
 
 #define PTR_TO_CALLNO(a) ((unsigned short)(unsigned long)(a))
 #define CALLNO_TO_PTR(a) ((void *)(unsigned long)(a))
@@ -125,7 +139,7 @@ static const char channeltype[] = "IAX2";
 static char context[80] = "default";
 
 static char language[MAX_LANGUAGE] = "";
-static char regcontext[AST_MAX_EXTENSION] = "";
+static char regcontext[AST_MAX_CONTEXT] = "";
 
 static int max_retries = 4;
 static int ping_time = 20;
@@ -135,10 +149,10 @@ static int maxnontrunkcall = 1;
 static int maxjitterbuffer=1000;
 #ifdef NEWJB
 static int resyncthreshold=1000;
+static int maxjitterinterps=10;
 #endif
 static int jittershrinkrate=2;
 static int trunkfreq = 20;
-static int send_trunktimestamps = 1;
 static int authdebug = 1;
 static int autokill = 0;
 static int iaxcompat = 0;
@@ -149,11 +163,12 @@ static int iaxdefaulttimeout = 5;         /* Default to wait no more than 5 seconds for
 
 static int tos = 0;
 
-static int expirey = IAX_DEFAULT_REG_EXPIRE;
+static int min_reg_expire;
+static int max_reg_expire;
 
 static int timingfd = -1;                              /* Timing file descriptor */
 
-static struct ast_netsock_list netsock;
+static struct ast_netsock_list *netsock;
 static int defaultsockfd = -1;
 
 static int usecnt;
@@ -164,22 +179,22 @@ int (*iax2_regfunk)(char *username, int onoff) = NULL;
 /* Ethernet, etc */
 #define IAX_CAPABILITY_FULLBANDWIDTH   0xFFFF
 /* T1, maybe ISDN */
-#define IAX_CAPABILITY_MEDBANDWIDTH    (IAX_CAPABILITY_FULLBANDWIDTH & \
-                                                                       ~AST_FORMAT_SLINEAR & \
-                                                                       ~AST_FORMAT_ULAW & \
-                                                                       ~AST_FORMAT_ALAW) 
+#define IAX_CAPABILITY_MEDBANDWIDTH    (IAX_CAPABILITY_FULLBANDWIDTH &         \
+                                                       ~AST_FORMAT_SLINEAR &   \
+                                                       ~AST_FORMAT_ULAW &      \
+                                                       ~AST_FORMAT_ALAW) 
 /* A modem */
-#define IAX_CAPABILITY_LOWBANDWIDTH            (IAX_CAPABILITY_MEDBANDWIDTH & \
-                                                                       ~AST_FORMAT_G726 & \
-                                                                       ~AST_FORMAT_ADPCM)
+#define IAX_CAPABILITY_LOWBANDWIDTH            (IAX_CAPABILITY_MEDBANDWIDTH &  \
+                                                       ~AST_FORMAT_G726 &      \
+                                                       ~AST_FORMAT_ADPCM)
 
-#define IAX_CAPABILITY_LOWFREE         (IAX_CAPABILITY_LOWBANDWIDTH & \
-                                                                        ~AST_FORMAT_G723_1)
+#define IAX_CAPABILITY_LOWFREE         (IAX_CAPABILITY_LOWBANDWIDTH &          \
+                                                        ~AST_FORMAT_G723_1)
 
 
 #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... */
 
 static struct io_context *io;
 static struct sched_context *sched;
@@ -205,7 +220,7 @@ static int amaflags = 0;
 static int delayreject = 0;
 static int iax2_encryption = 0;
 
-static struct ast_flags globalflags = {0};
+static struct ast_flags globalflags = { 0 };
 
 static pthread_t netthreadid = AST_PTHREADT_NULL;
 
@@ -214,31 +229,33 @@ static pthread_t netthreadid = AST_PTHREADT_NULL;
 #define IAX_STATE_TBD                  (1 << 2)
 
 struct iax2_context {
-       char context[AST_MAX_EXTENSION];
+       char context[AST_MAX_CONTEXT];
        struct iax2_context *next;
 };
 
-#define IAX_HASCALLERID                (1 << 0)        /* CallerID has been specified */
-#define IAX_DELME              (1 << 1)        /* Needs to be deleted */
-#define IAX_TEMPONLY           (1 << 2)        /* Temporary (realtime) */
-#define IAX_TRUNK              (1 << 3)        /* Treat as a trunk */
-#define IAX_NOTRANSFER         (1 << 4)        /* Don't native bridge */
-#define IAX_USEJITTERBUF       (1 << 5)        /* Use jitter buffer */
-#define IAX_DYNAMIC            (1 << 6)        /* dynamic peer */
-#define IAX_SENDANI            (1 << 7)        /* Send ANI along with CallerID */
-#define IAX_MESSAGEDETAIL      (1 << 8)        /* Show exact numbers */
-#define IAX_ALREADYGONE                (1 << 9)        /* Already disconnected */
-#define IAX_PROVISION          (1 << 10)       /* This is a provisioning request */
-#define IAX_QUELCH             (1 << 11)       /* Whether or not we quelch audio */
-#define IAX_ENCRYPTED          (1 << 12)       /* Whether we should assume encrypted tx/rx */
-#define IAX_KEYPOPULATED       (1 << 13)       /* Whether we have a key populated */
-#define IAX_CODEC_USER_FIRST   (1 << 14)       /* are we willing to let the other guy choose the codec? */
-#define IAX_CODEC_NOPREFS      (1 << 15)       /* Force old behaviour by turning off prefs */
-#define IAX_CODEC_NOCAP        (1 << 16)       /* only consider requested format and ignore capabilities*/
-#define IAX_RTCACHEFRIENDS     (1 << 17)       /* let realtime stay till your reload */
-#define IAX_RTNOUPDATE                 (1 << 18)       /* Don't send a realtime update */
-#define IAX_RTAUTOCLEAR        (1 << 19)       /* erase me on expire */ 
-#define IAX_FORCEJITTERBUF     (1 << 20)       /* Force jitterbuffer, even when bridged to a channel that can take jitter */ 
+#define IAX_HASCALLERID                (1 << 0)        /*!< CallerID has been specified */
+#define IAX_DELME              (1 << 1)        /*!< Needs to be deleted */
+#define IAX_TEMPONLY           (1 << 2)        /*!< Temporary (realtime) */
+#define IAX_TRUNK              (1 << 3)        /*!< Treat as a trunk */
+#define IAX_NOTRANSFER         (1 << 4)        /*!< Don't native bridge */
+#define IAX_USEJITTERBUF       (1 << 5)        /*!< Use jitter buffer */
+#define IAX_DYNAMIC            (1 << 6)        /*!< dynamic peer */
+#define IAX_SENDANI            (1 << 7)        /*!< Send ANI along with CallerID */
+#define IAX_MESSAGEDETAIL      (1 << 8)        /*!< Show exact numbers */
+#define IAX_ALREADYGONE                (1 << 9)        /*!< Already disconnected */
+#define IAX_PROVISION          (1 << 10)       /*!< This is a provisioning request */
+#define IAX_QUELCH             (1 << 11)       /*!< Whether or not we quelch audio */
+#define IAX_ENCRYPTED          (1 << 12)       /*!< Whether we should assume encrypted tx/rx */
+#define IAX_KEYPOPULATED       (1 << 13)       /*!< Whether we have a key populated */
+#define IAX_CODEC_USER_FIRST   (1 << 14)       /*!< are we willing to let the other guy choose the codec? */
+#define IAX_CODEC_NOPREFS      (1 << 15)       /*!< Force old behaviour by turning off prefs */
+#define IAX_CODEC_NOCAP        (1 << 16)       /*!< only consider requested format and ignore capabilities*/
+#define IAX_RTCACHEFRIENDS     (1 << 17)       /*!< let realtime stay till your reload */
+#define IAX_RTUPDATE           (1 << 18)       /*!< Send a realtime update */
+#define IAX_RTAUTOCLEAR        (1 << 19)       /*!< erase me on expire */ 
+#define IAX_FORCEJITTERBUF     (1 << 20)       /*!< Force jitterbuffer, even when bridged to a channel that can take jitter */ 
+#define IAX_RTIGNOREREGEXPIRE  (1 << 21)       /*!< When using realtime, ignore registration expiration */
+#define IAX_TRUNKTIMESTAMPS    (1 << 22)       /*!< Send trunk timestamps */
 
 static int global_rtautoclear = 120;
 
@@ -253,7 +270,7 @@ struct iax2_user {
        int authmethods;
        int encmethods;
        char accountcode[AST_MAX_ACCOUNT_CODE];
-       char inkeys[80];                                /* Key(s) this user can use to authenticate to us */
+       char inkeys[80];                                /*!< Key(s) this user can use to authenticate to us */
        char language[MAX_LANGUAGE];
        int amaflags;
        unsigned int flags;
@@ -272,39 +289,44 @@ struct iax2_peer {
        char username[80];              
        char secret[80];
        char dbsecret[80];
-       char outkey[80];                                /* What key we use to talk to this peer */
-       char context[AST_MAX_EXTENSION];                /* For transfers only */
-       char regexten[AST_MAX_EXTENSION];               /* Extension to register (if regcontext is used) */
-       char peercontext[AST_MAX_EXTENSION];            /* Context to pass to peer */
-       char mailbox[AST_MAX_EXTENSION];                /* Mailbox */
+       char outkey[80];                                /*!< What key we use to talk to this peer */
+       char context[AST_MAX_CONTEXT];                  /*!< For transfers only */
+       char regexten[AST_MAX_EXTENSION];               /*!< Extension to register (if regcontext is used) */
+       char peercontext[AST_MAX_EXTENSION];            /*!< Context to pass to peer */
+       char mailbox[AST_MAX_EXTENSION];                /*!< Mailbox */
        struct ast_codec_pref prefs;
-       struct ast_dnsmgr_entry *dnsmgr;                /* DNS refresh manager */
+       struct ast_dnsmgr_entry *dnsmgr;                /*!< DNS refresh manager */
        struct sockaddr_in addr;
        int formats;
-       int sockfd;                                     /* Socket to use for transmission */
+       int sockfd;                                     /*!< Socket to use for transmission */
        struct in_addr mask;
        unsigned int flags;
 
        /* Dynamic Registration fields */
-       struct sockaddr_in defaddr;                     /* Default address if there is one */
-       int authmethods;                                /* Authentication methods (IAX_AUTH_*) */
-       int encmethods;                                 /* Encryption methods (IAX_ENCRYPT_*) */
-       char inkeys[80];                                /* Key(s) this peer can use to authenticate to us */
+       struct sockaddr_in defaddr;                     /*!< Default address if there is one */
+       int authmethods;                                /*!< Authentication methods (IAX_AUTH_*) */
+       int encmethods;                                 /*!< Encryption methods (IAX_ENCRYPT_*) */
+       char inkeys[80];                                /*!< Key(s) this peer can use to authenticate to us */
 
        /* Suggested caller id if registering */
-       char cid_num[AST_MAX_EXTENSION];                /* Default context (for transfer really) */
-       char cid_name[AST_MAX_EXTENSION];               /* Default context (for transfer really) */
+       char cid_num[AST_MAX_EXTENSION];                /*!< Default context (for transfer really) */
+       char cid_name[AST_MAX_EXTENSION];               /*!< Default context (for transfer really) */
        
-       int expire;                                     /* Schedule entry for expirey */
-       int expirey;                                    /* How soon to expire */
-       int capability;                                 /* Capability */
-       char zonetag[80];                               /* Time Zone */
+       int expire;                                     /*!< Schedule entry for expiry */
+       int expiry;                                     /*!< How soon to expire */
+       int capability;                                 /*!< Capability */
+       char zonetag[80];                               /*!< Time Zone */
 
        /* Qualification */
-       int callno;                                     /* Call number of POKE request */
-       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 */
+       int callno;                                     /*!< Call number of POKE request */
+       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 */
+
+       int pokefreqok;                                 /*!< How often to check if the host is up */
+       int pokefreqnotok;                              /*!< How often to check when the host has been determined to be down */
+       int historicms;                                 /*!< How long recent average responses took */
+       int smoothing;                                  /*!< Sample over how many units to determine historic ms */
        
        struct ast_ha *ha;
        struct iax2_peer *next;
@@ -316,11 +338,11 @@ static struct iax2_trunk_peer {
        ast_mutex_t lock;
        int sockfd;
        struct sockaddr_in addr;
-       struct timeval txtrunktime;             /* Transmit trunktime */
-       struct timeval rxtrunktime;             /* Receive trunktime */
-       struct timeval lasttxtime;              /* Last transmitted trunktime */
-       struct timeval trunkact;                /* Last trunk activity */
-       unsigned int lastsent;                  /* Last sent time */
+       struct timeval txtrunktime;             /*!< Transmit trunktime */
+       struct timeval rxtrunktime;             /*!< Receive trunktime */
+       struct timeval lasttxtime;              /*!< Last transmitted trunktime */
+       struct timeval trunkact;                /*!< Last trunk activity */
+       unsigned int lastsent;                  /*!< Last sent time */
        /* Trunk data and length */
        unsigned char *trunkdata;
        unsigned int trunkdatalen;
@@ -341,47 +363,51 @@ struct iax_firmware {
        unsigned char *buf;
 };
 
-#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
+enum iax_reg_state {
+       REG_STATE_UNREGISTERED = 0,
+       REG_STATE_REGSENT,
+       REG_STATE_AUTHSENT,
+       REG_STATE_REGISTERED,
+       REG_STATE_REJECTED,
+       REG_STATE_TIMEOUT,
+       REG_STATE_NOAUTH
+};
 
-#define TRANSFER_NONE          0
-#define TRANSFER_BEGIN         1
-#define TRANSFER_READY         2
-#define TRANSFER_RELEASED      3
-#define TRANSFER_PASSTHROUGH   4
+enum iax_transfer_state {
+       TRANSFER_NONE = 0,
+       TRANSFER_BEGIN,
+       TRANSFER_READY,
+       TRANSFER_RELEASED,
+       TRANSFER_PASSTHROUGH
+};
 
 struct iax2_registry {
-       struct sockaddr_in addr;                /* Who we connect to for registration purposes */
+       struct sockaddr_in addr;                /*!< Who we connect to for registration purposes */
        char username[80];
-       char secret[80];                        /* Password or key name in []'s */
+       char secret[80];                        /*!< Password or key name in []'s */
        char random[80];
-       int expire;                             /* Sched ID of expiration */
-       int refresh;                            /* How often to refresh */
-       int regstate;
-       int messages;                           /* Message count */
-       int callno;                             /* Associated call number if applicable */
-       struct sockaddr_in us;                  /* Who the server thinks we are */
+       int expire;                             /*!< Sched ID of expiration */
+       int refresh;                            /*!< How often to refresh */
+       enum iax_reg_state regstate;
+       int messages;                           /*!< Message count */
+       int callno;                             /*!< Associated call number if applicable */
+       struct sockaddr_in us;                  /*!< Who the server thinks we are */
        struct iax2_registry *next;
 };
 
 static struct iax2_registry *registrations;
 
 /* Don't retry more frequently than every 10 ms, or less frequently than every 5 seconds */
-#define MIN_RETRY_TIME 100
-#define MAX_RETRY_TIME  10000
+#define MIN_RETRY_TIME         100
+#define MAX_RETRY_TIME         10000
 
-#define MAX_JITTER_BUFFER 50
-#define MIN_JITTER_BUFFER 10
+#define MAX_JITTER_BUFFER      50
+#define MIN_JITTER_BUFFER      10
 
-#define DEFAULT_TRUNKDATA      640 * 10                /* 40ms, uncompressed linear * 10 channels */
-#define MAX_TRUNKDATA          640 * 200               /* 40ms, uncompressed linear * 200 channels */
+#define DEFAULT_TRUNKDATA      640 * 10        /*!< 40ms, uncompressed linear * 10 channels */
+#define MAX_TRUNKDATA          640 * 200       /*!< 40ms, uncompressed linear * 200 channels */
 
-#define MAX_TIMESTAMP_SKEW     160                     /* maximum difference between actual and predicted ts for sending */
+#define MAX_TIMESTAMP_SKEW     160             /*!< maximum difference between actual and predicted ts for sending */
 
 /* If consecutive voice frame timestamps jump by more than this many milliseconds, then jitter buffer will resync */
 #define TS_GAP_FOR_JB_RESYNC   5000
@@ -402,147 +428,147 @@ struct iax_rr {
 };
 
 struct chan_iax2_pvt {
-       /* Socket to send/receive on for this call */
+       /*! Socket to send/receive on for this call */
        int sockfd;
-       /* Last received voice format */
+       /*! Last received voice format */
        int voiceformat;
-       /* Last received voice format */
+       /*! Last received voice format */
        int videoformat;
-       /* Last sent voice format */
+       /*! Last sent voice format */
        int svoiceformat;
-       /* Last sent video format */
+       /*! Last sent video format */
        int svideoformat;
-       /* What we are capable of sending */
+       /*! What we are capable of sending */
        int capability;
-       /* Last received timestamp */
+       /*! Last received timestamp */
        unsigned int last;
-       /* Last sent timestamp - never send the same timestamp twice in a single call */
+       /*! Last sent timestamp - never send the same timestamp twice in a single call */
        unsigned int lastsent;
-       /* Next outgoing timestamp if everything is good */
+       /*! Next outgoing timestamp if everything is good */
        unsigned int nextpred;
-       /* True if the last voice we transmitted was not silence/CNG */
+       /*! True if the last voice we transmitted was not silence/CNG */
        int notsilenttx;
-       /* Ping time */
+       /*! Ping time */
        unsigned int pingtime;
-       /* Max time for initial response */
+       /*! Max time for initial response */
        int maxtime;
-       /* Peer Address */
+       /*! Peer Address */
        struct sockaddr_in addr;
        struct ast_codec_pref prefs;
-       /* Our call number */
+       /*! Our call number */
        unsigned short callno;
-       /* Peer callno */
+       /*! Peer callno */
        unsigned short peercallno;
-       /* Peer selected format */
+       /*! Peer selected format */
        int peerformat;
-       /* Peer capability */
+       /*! Peer capability */
        int peercapability;
-       /* timeval that we base our transmission on */
+       /*! timeval that we base our transmission on */
        struct timeval offset;
-       /* timeval that we base our delivery on */
+       /*! timeval that we base our delivery on */
        struct timeval rxcore;
 #ifdef NEWJB
-       /* The jitterbuffer */
+       /*! The jitterbuffer */
         jitterbuf *jb;
-       /* active jb read scheduler id */
+       /*! active jb read scheduler id */
         int jbid;                       
 #else
-       /* Historical delivery time */
+       /*! Historical delivery time */
        int history[MEMORY_SIZE];
-       /* Current base jitterbuffer */
+       /*! Current base jitterbuffer */
        int jitterbuffer;
-       /* Current jitter measure */
+       /*! Current jitter measure */
        int jitter;
-       /* Historic jitter value */
+       /*! Historic jitter value */
        int historicjitter;
 #endif
-       /* LAG */
+       /*! LAG */
        int lag;
-       /* Error, as discovered by the manager */
+       /*! Error, as discovered by the manager */
        int error;
-       /* Owner if we have one */
+       /*! Owner if we have one */
        struct ast_channel *owner;
-       /* What's our state? */
+       /*! What's our state? */
        int state;
-       /* Expirey (optional) */
-       int expirey;
-       /* Next outgoing sequence number */
+       /*! Expiry (optional) */
+       int expiry;
+       /*! Next outgoing sequence number */
        unsigned char oseqno;
-       /* Next sequence number they have not yet acknowledged */
+       /*! Next sequence number they have not yet acknowledged */
        unsigned char rseqno;
-       /* Next incoming sequence number */
+       /*! Next incoming sequence number */
        unsigned char iseqno;
-       /* Last incoming sequence number we have acknowledged */
+       /*! Last incoming sequence number we have acknowledged */
        unsigned char aseqno;
-       /* Peer name */
+       /*! Peer name */
        char peer[80];
-       /* Default Context */
+       /*! Default Context */
        char context[80];
-       /* Caller ID if available */
+       /*! Caller ID if available */
        char cid_num[80];
        char cid_name[80];
-       /* Hidden Caller ID (i.e. ANI) if appropriate */
+       /*! Hidden Caller ID (i.e. ANI) if appropriate */
        char ani[80];
-       /* DNID */
+       /*! DNID */
        char dnid[80];
-       /* Requested Extension */
+       /*! Requested Extension */
        char exten[AST_MAX_EXTENSION];
-       /* Expected Username */
+       /*! Expected Username */
        char username[80];
-       /* Expected Secret */
+       /*! Expected Secret */
        char secret[80];
-       /* permitted authentication methods */
+       /*! permitted authentication methods */
        int authmethods;
-       /* permitted encryption methods */
+       /*! permitted encryption methods */
        int encmethods;
-       /* MD5 challenge */
+       /*! MD5 challenge */
        char challenge[10];
-       /* Public keys permitted keys for incoming authentication */
+       /*! Public keys permitted keys for incoming authentication */
        char inkeys[80];
-       /* Private key for outgoing authentication */
+       /*! Private key for outgoing authentication */
        char outkey[80];
-       /* Encryption AES-128 Key */
+       /*! Encryption AES-128 Key */
        aes_encrypt_ctx ecx;
-       /* Decryption AES-128 Key */
+       /*! Decryption AES-128 Key */
        aes_decrypt_ctx dcx;
-       /* 32 bytes of semi-random data */
-       char semirand[32];
-       /* Preferred language */
+       /*! 32 bytes of semi-random data */
+       unsigned char semirand[32];
+       /*! Preferred language */
        char language[MAX_LANGUAGE];
-       /* Hostname/peername for naming purposes */
+       /*! Hostname/peername for naming purposes */
        char host[80];
-       /* Associated registry */
+       /*! Associated registry */
        struct iax2_registry *reg;
-       /* Associated peer for poking */
+       /*! Associated peer for poking */
        struct iax2_peer *peerpoke;
-       /* IAX_ flags */
+       /*! IAX_ flags */
        unsigned int flags;
 
-       /* Transferring status */
-       int transferring;
-       /* Transfer identifier */
+       /*! Transferring status */
+       enum iax_transfer_state transferring;
+       /*! Transfer identifier */
        int transferid;
-       /* Who we are IAX transfering to */
+       /*! Who we are IAX transfering to */
        struct sockaddr_in transfer;
-       /* What's the new call number for the transfer */
+       /*! What's the new call number for the transfer */
        unsigned short transfercallno;
-       /* Transfer decrypt AES-128 Key */
+       /*! Transfer decrypt AES-128 Key */
        aes_encrypt_ctx tdcx;
 
-       /* Status of knowledge of peer ADSI capability */
+       /*! Status of knowledge of peer ADSI capability */
        int peeradsicpe;
        
-       /* Who we are bridged to */
+       /*! Who we are bridged to */
        unsigned short bridgecallno;
        unsigned int bridgesfmt;
        struct ast_trans_pvt *bridgetrans;
        
-       int pingid;                     /* Transmit PING request */
-       int lagid;                      /* Retransmit lag request */
-       int autoid;                     /* Auto hangup for Dialplan requestor */
-       int authid;                     /* Authentication rejection ID */
-       int authfail;           /* Reason to report failure */
-       int initid;                     /* Initial peer auto-congest ID (based on qualified peers) */
+       int pingid;                     /*!< Transmit PING request */
+       int lagid;                      /*!< Retransmit lag request */
+       int autoid;                     /*!< Auto hangup for Dialplan requestor */
+       int authid;                     /*!< Authentication rejection ID */
+       int authfail;                   /*!< Reason to report failure */
+       int initid;                     /*!< Initial peer auto-congest ID (based on qualified peers) */
        int calling_ton;
        int calling_tns;
        int calling_pres;
@@ -551,13 +577,13 @@ struct chan_iax2_pvt {
        int amaflags;
        struct iax2_dpcache *dpentries;
        struct ast_variable *vars;
-       /* last received remote rr */
+       /*! last received remote rr */
        struct iax_rr remote_rr;
-       /* Current base time: (just for stats) */
+       /*! Current base time: (just for stats) */
        int min;
-       /* Dropped frame count: (just for stats) */
+       /*! Dropped frame count: (just for stats) */
        int frames_dropped;
-       /* received frame count: (just for stats) */
+       /*! received frame count: (just for stats) */
        int frames_received;
 };
 
@@ -583,39 +609,39 @@ static struct ast_firmware_list {
        ast_mutex_t lock;
 } waresl;
 
-/* Extension exists */
+/*! Extension exists */
 #define CACHE_FLAG_EXISTS              (1 << 0)
-/* Extension is nonexistent */
-#define CACHE_FLAG_NONEXISTENT (1 << 1)
-/* Extension can exist */
+/*! Extension is nonexistent */
+#define CACHE_FLAG_NONEXISTENT         (1 << 1)
+/*! Extension can exist */
 #define CACHE_FLAG_CANEXIST            (1 << 2)
-/* Waiting to hear back response */
+/*! Waiting to hear back response */
 #define CACHE_FLAG_PENDING             (1 << 3)
-/* Timed out */
+/*! Timed out */
 #define CACHE_FLAG_TIMEOUT             (1 << 4)
-/* Request transmitted */
-#define CACHE_FLAG_TRANSMITTED (1 << 5)
-/* Timeout */
+/*! Request transmitted */
+#define CACHE_FLAG_TRANSMITTED         (1 << 5)
+/*! Timeout */
 #define CACHE_FLAG_UNKNOWN             (1 << 6)
-/* Matchmore */
-#define CACHE_FLAG_MATCHMORE   (1 << 7)
+/*! Matchmore */
+#define CACHE_FLAG_MATCHMORE           (1 << 7)
 
 static struct iax2_dpcache {
-       char peercontext[AST_MAX_EXTENSION];
+       char peercontext[AST_MAX_CONTEXT];
        char exten[AST_MAX_EXTENSION];
        struct timeval orig;
-       struct timeval expirey;
+       struct timeval expiry;
        int flags;
        unsigned short callno;
        int waiters[256];
        struct iax2_dpcache *next;
-       struct iax2_dpcache *peer;      /* For linking in peers */
+       struct iax2_dpcache *peer;      /*!< For linking in peers */
 } *dpcache;
 
 AST_MUTEX_DEFINE_STATIC(dpcache_lock);
 
 static void reg_source_db(struct iax2_peer *p);
-static struct iax2_peer *realtime_peer(const char *peername);
+static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in *sin);
 
 static void destroy_peer(struct iax2_peer *peer);
 static int ast_cli_netstats(int fd, int limit_fmt);
@@ -660,7 +686,6 @@ static void jb_debug_output(const char *fmt, ...)
 {
        va_list args;
        char buf[1024];
-       if(!iaxdebug) return;
 
        va_start(args, fmt);
        vsnprintf(buf, 1024, fmt, args);
@@ -677,11 +702,11 @@ static ast_mutex_t iaxsl[IAX_MAX_CALLS];
 static struct timeval lastused[IAX_MAX_CALLS];
 
 
-static int send_command(struct chan_iax2_pvt *, char, int, unsigned int, const char *, int, int);
-static int send_command_locked(unsigned short callno, char, int, unsigned int, const char *, int, int);
-static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, const char *, int, int);
-static int send_command_final(struct chan_iax2_pvt *, char, int, unsigned int, const char *, int, int);
-static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, const char *, int);
+static int send_command(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
+static int send_command_locked(unsigned short callno, char, int, unsigned int, const unsigned char *, int, int);
+static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
+static int send_command_final(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
+static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int);
 static struct iax2_user *build_user(const char *name, struct ast_variable *v, int temponly);
 static void destroy_user(struct iax2_user *user);
 static int expire_registry(void *data);
@@ -689,7 +714,7 @@ static int iax2_write(struct ast_channel *c, struct ast_frame *f);
 static int iax2_do_register(struct iax2_registry *reg);
 static void prune_peers(void);
 static int iax2_poke_peer(struct iax2_peer *peer, int heldcall);
-static int iax2_provision(struct sockaddr_in *end, char *dest, const char *template, int force);
+static int iax2_provision(struct sockaddr_in *end, int sockfd, char *dest, const char *template, int force);
 
 static struct ast_channel *iax2_request(const char *type, int format, void *data, int *cause);
 static int iax2_devicestate(void *data);
@@ -704,7 +729,7 @@ static struct ast_frame *iax2_read(struct ast_channel *c);
 static int iax2_write(struct ast_channel *c, struct ast_frame *f);
 static int iax2_indicate(struct ast_channel *c, int condition);
 static int iax2_setoption(struct ast_channel *c, int option, void *data, int datalen);
-static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
+static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
 static int iax2_transfer(struct ast_channel *c, const char *dest);
 static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan);
 
@@ -817,7 +842,7 @@ static struct iax2_peer *find_peer(const char *name, int realtime)
        }
        ast_mutex_unlock(&peerl.lock);
        if(!peer && realtime)
-               peer = realtime_peer(name);
+               peer = realtime_peer(name, NULL);
        return peer;
 }
 
@@ -839,6 +864,14 @@ static int iax2_getpeername(struct sockaddr_in sin, char *host, int len, int loc
        }
        if (lockpeer)
                ast_mutex_unlock(&peerl.lock);
+       if (!peer) {
+               peer = realtime_peer(NULL, &sin);
+               if (peer) {
+                       ast_copy_string(host, peer->name, len);
+                       if (ast_test_flag(peer, IAX_TEMPONLY))
+                               destroy_peer(peer);
+               }
+       }
        return res;
 }
 
@@ -869,6 +902,7 @@ static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, int lockpeer, cons
                        tmp->jbid = -1;
                        jbconf.max_jitterbuf = maxjitterbuffer;
                        jbconf.resync_threshold = resyncthreshold;
+                       jbconf.max_contig_interp = maxjitterinterps;
                        jb_setconf(tmp->jb,&jbconf);
                }
 #endif
@@ -891,7 +925,7 @@ static struct iax_frame *iaxfrdup2(struct iax_frame *fr)
        return new;
 }
 
-#define NEW_PREVENT 0
+#define NEW_PREVENT    0
 #define NEW_ALLOW      1
 #define NEW_FORCE      2
 
@@ -925,7 +959,7 @@ static void update_max_trunk(void)
                        max = x + 1;
        }
        maxtrunkcall = max;
-       if (option_debug)
+       if (option_debug && iaxdebug)
                ast_log(LOG_DEBUG, "New max trunk callno is %d\n", max);
 }
 
@@ -939,7 +973,7 @@ static void update_max_nontrunk(void)
                        max = x + 1;
        }
        maxnontrunkcall = max;
-       if (option_debug)
+       if (option_debug && iaxdebug)
                ast_log(LOG_DEBUG, "New max nontrunk callno is %d\n", max);
 }
 
@@ -1038,7 +1072,7 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc
                iaxs[x] = new_iax(sin, lockpeer, host);
                update_max_nontrunk();
                if (iaxs[x]) {
-                       if (option_debug)
+                       if (option_debug && iaxdebug)
                                ast_log(LOG_DEBUG, "Creating new call structure %d\n", x);
                        iaxs[x]->sockfd = sockfd;
                        iaxs[x]->addr.sin_port = sin->sin_port;
@@ -1047,7 +1081,7 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc
                        iaxs[x]->peercallno = callno;
                        iaxs[x]->callno = x;
                        iaxs[x]->pingtime = DEFAULT_RETRY_TIME;
-                       iaxs[x]->expirey = expirey;
+                       iaxs[x]->expiry = min_reg_expire;
                        iaxs[x]->pingid = ast_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x);
                        iaxs[x]->lagid = ast_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x);
                        iaxs[x]->amaflags = amaflags;
@@ -1190,7 +1224,7 @@ static int try_firmware(char *s)
                close(fd);
                return -1;
        }
-       if (fwh2.devname[sizeof(fwh2.devname) - 1] || ast_strlen_zero(fwh2.devname)) {
+       if (fwh2.devname[sizeof(fwh2.devname) - 1] || ast_strlen_zero((char *)fwh2.devname)) {
                ast_log(LOG_WARNING, "No or invalid device type specified for '%s'\n", s);
                close(fd);
                return -1;
@@ -1212,7 +1246,7 @@ static int try_firmware(char *s)
        }
        cur = waresl.wares;
        while(cur) {
-               if (!strcmp(cur->fwh->devname, fwh->devname)) {
+               if (!strcmp((char *)cur->fwh->devname, (char *)fwh->devname)) {
                        /* Found a candidate */
                        if (cur->dead || (ntohs(cur->fwh->version) < ntohs(fwh->version)))
                                /* The version we have on loaded is older, load this one instead */
@@ -1253,11 +1287,11 @@ static int iax_check_version(char *dev)
 {
        int res = 0;
        struct iax_firmware *cur;
-       if (dev && !ast_strlen_zero(dev)) {
+       if (!ast_strlen_zero(dev)) {
                ast_mutex_lock(&waresl.lock);
                cur = waresl.wares;
                while(cur) {
-                       if (!strcmp(dev, cur->fwh->devname)) {
+                       if (!strcmp(dev, (char *)cur->fwh->devname)) {
                                res = ntohs(cur->fwh->version);
                                break;
                        }
@@ -1275,12 +1309,12 @@ static int iax_firmware_append(struct iax_ie_data *ied, const unsigned char *dev
        unsigned int start = (desc >> 8) & 0xffffff;
        unsigned int bytes;
        struct iax_firmware *cur;
-       if (dev && !ast_strlen_zero(dev) && bs) {
+       if (!ast_strlen_zero((char *)dev) && bs) {
                start *= bs;
                ast_mutex_lock(&waresl.lock);
                cur = waresl.wares;
                while(cur) {
-                       if (!strcmp(dev, cur->fwh->devname)) {
+                       if (!strcmp((char *)dev, (char *)cur->fwh->devname)) {
                                iax_ie_append_int(ied, IAX_IE_FWBLOCKDESC, desc);
                                if (start < ntohl(cur->fwh->datalen)) {
                                        bytes = ntohl(cur->fwh->datalen) - start;
@@ -1439,7 +1473,7 @@ static int send_packet(struct iax_frame *f)
        int res;
        char iabuf[INET_ADDRSTRLEN];
        /* Called with iaxsl held */
-       if (option_debug > 2)
+       if (option_debug > 2 && iaxdebug)
                ast_log(LOG_DEBUG, "Sending %d on %d/%d to %s:%d\n", f->ts, f->callno, iaxs[f->callno]->peercallno, ast_inet_ntoa(iabuf, sizeof(iabuf), iaxs[f->callno]->addr.sin_addr), ntohs(iaxs[f->callno]->addr.sin_port));
        /* Don't send if there was an error, but return error instead */
        if (!f->callno) {
@@ -1462,7 +1496,7 @@ static int send_packet(struct iax_frame *f)
                                        sizeof(iaxs[f->callno]->addr));
        }
        if (res < 0) {
-               if (option_debug)
+               if (option_debug && iaxdebug)
                        ast_log(LOG_DEBUG, "Received error: %s\n", strerror(errno));
                handle_error();
        } else
@@ -1841,7 +1875,7 @@ static int iax2_test_jitter(int fd, int argc, char *argv[])
 /*--- iax2_show_peer: Show one peer in detail ---*/
 static int iax2_show_peer(int fd, int argc, char *argv[])
 {
-       char status[30] = "";
+       char status[30];
        char cbuf[256];
        char iabuf[INET_ADDRSTRLEN];
        struct iax2_peer *peer;
@@ -1888,12 +1922,13 @@ static int iax2_show_peer(int fd, int argc, char *argv[])
                ast_cli(fd, "  Status       : ");
                if (peer->lastms < 0)
                        ast_copy_string(status, "UNREACHABLE", sizeof(status));
-               else if (peer->lastms > peer->maxms)
-                       snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms);
-               else if (peer->lastms)
-                       snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms);
+               else if (peer->historicms > peer->maxms)
+                       snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->historicms);
+               else if (peer->historicms)
+                       snprintf(status, sizeof(status), "OK (%d ms)", peer->historicms);
                else
                        ast_copy_string(status, "UNKNOWN", sizeof(status));
+               ast_cli(fd, " Qualify        : every %d when OK, every %d when UNREACHABLE (sample smoothing %s)\n", peer->pokefreqok, peer->pokefreqnotok, (peer->smoothing == 1) ? "On" : "Off");
                ast_cli(fd, "%s\n",status);
                ast_cli(fd,"\n");
                if (ast_test_flag(peer, IAX_TEMPONLY))
@@ -1942,7 +1977,7 @@ static int iax2_show_stats(int fd, int argc, char *argv[])
        }
        ast_cli(fd, "    IAX Statistics\n");
        ast_cli(fd, "---------------------\n");
-       ast_cli(fd, "Outstanding frames: %d (%d ingress, %d outgress)\n", iax_get_frames(), iax_get_iframes(), iax_get_oframes());
+       ast_cli(fd, "Outstanding frames: %d (%d ingress, %d egress)\n", iax_get_frames(), iax_get_iframes(), iax_get_oframes());
        ast_cli(fd, "Packets in transmit queue: %d dead, %d final, %d total\n", dead, final, cnt);
        return RESULT_SUCCESS;
 }
@@ -1950,7 +1985,7 @@ static int iax2_show_stats(int fd, int argc, char *argv[])
 static int iax2_show_cache(int fd, int argc, char *argv[])
 {
        struct iax2_dpcache *dp;
-       char tmp[1024] = "", *pc;
+       char tmp[1024], *pc;
        int s;
        int x,y;
        struct timeval tv;
@@ -1959,7 +1994,7 @@ static int iax2_show_cache(int fd, int argc, char *argv[])
        dp = dpcache;
        ast_cli(fd, "%-20.20s %-12.12s %-9.9s %-8.8s %s\n", "Peer/Context", "Exten", "Exp.", "Wait.", "Flags");
        while(dp) {
-               s = dp->expirey.tv_sec - tv.tv_sec;
+               s = dp->expiry.tv_sec - tv.tv_sec;
                tmp[0] = '\0';
                if (dp->flags & CACHE_FLAG_EXISTS)
                        strncat(tmp, "EXISTS|", sizeof(tmp) - strlen(tmp) - 1);
@@ -2060,7 +2095,7 @@ static void unwrap_timestamp(struct iax_frame *fr)
                           gotten the update from the main packet.  We'll just pretend that we did, and
                           update the timestamp appropriately. */
                        fr->ts = ( (iaxs[fr->callno]->last & 0xFFFF0000) + 0x10000) | (fr->ts & 0xFFFF);
-                       if (option_debug)
+                       if (option_debug && iaxdebug)
                                ast_log(LOG_DEBUG, "schedule_delivery: pushed forward timestamp\n");
                }
                if (x > 50000) {
@@ -2069,7 +2104,7 @@ static void unwrap_timestamp(struct iax_frame *fr)
                           top-16-bit timestamp that has turned up out of order.
                           Adjust the timestamp appropriately. */
                        fr->ts = ( (iaxs[fr->callno]->last & 0xFFFF0000) - 0x10000) | (fr->ts & 0xFFFF);
-                       if (option_debug)
+                       if (option_debug && iaxdebug)
                                ast_log(LOG_DEBUG, "schedule_delivery: pushed back timestamp\n");
                }
        }
@@ -2080,12 +2115,8 @@ static int get_from_jb(void *p);
 
 static void update_jbsched(struct chan_iax2_pvt *pvt) {
     int when;
-    struct timeval tv;
 
-    gettimeofday(&tv,NULL);
-
-    when = (tv.tv_sec - pvt->rxcore.tv_sec) * 1000 +
-         (tv.tv_usec - pvt->rxcore.tv_usec) / 1000;
+    when = ast_tvdiff_ms(ast_tvnow(), pvt->rxcore);
 
     /*    fprintf(stderr, "now = %d, next=%d\n", when, jb_next(pvt->jb)); */
 
@@ -2102,7 +2133,8 @@ static void update_jbsched(struct chan_iax2_pvt *pvt) {
     pvt->jbid = ast_sched_add(sched, when, get_from_jb, (void *)pvt);
 }
 
-static int get_from_jb(void *p) {
+static int get_from_jb(void *p) 
+{
        /* make sure pvt is valid! */   
     struct chan_iax2_pvt *pvt = p;
     struct iax_frame *fr;
@@ -2122,60 +2154,52 @@ static int get_from_jb(void *p) {
     /* to catch up with runq's now */
     tv.tv_usec += 1000;
 
-    now = (tv.tv_sec - pvt->rxcore.tv_sec) * 1000 +
-         (tv.tv_usec - pvt->rxcore.tv_usec) / 1000;
+    now = ast_tvdiff_ms(tv, pvt->rxcore);
 
     if(now >= (next = jb_next(pvt->jb))) {
-       ret = jb_get(pvt->jb,&frame,now,ast_codec_interp_len(pvt->voiceformat));
-       switch(ret) {
-           case JB_OK:
-               /*if(frame.type == JB_TYPE_VOICE && next + 20 != jb_next(pvt->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(pvt->jb), next); */
-               fr = frame.data;
-               __do_deliver(fr);
-           break;
-           case JB_INTERP:
-           {
-               struct ast_frame af;
-
-               /*if(next + 20 != jb_next(pvt->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(pvt->jb), next); */
-
-               /* create an interpolation frame */
-               /*fprintf(stderr, "Making Interpolation frame\n"); */
-               af.frametype = AST_FRAME_VOICE;
-               af.subclass = pvt->voiceformat;
-               af.datalen  = 0;
-               af.samples  = frame.ms * 8;
-               af.mallocd  = 0;
-               af.src  = "IAX2 JB interpolation";
-               af.data  = NULL;
-               af.delivery.tv_sec = pvt->rxcore.tv_sec;
-               af.delivery.tv_usec = pvt->rxcore.tv_usec;
-               af.delivery.tv_sec += next / 1000;
-               af.delivery.tv_usec += (next % 1000) * 1000;
-               af.offset=AST_FRIENDLY_OFFSET;
-               if (af.delivery.tv_usec >= 1000000) {
-                       af.delivery.tv_usec -= 1000000;
-                       af.delivery.tv_sec += 1;
-               }
-
-               /* queue the frame:  For consistency, we would call __do_deliver here, but __do_deliver wants an iax_frame,
-                * which we'd need to malloc, and then it would free it.  That seems like a drag */
-               if (iaxs[pvt->callno] && !ast_test_flag(iaxs[pvt->callno], IAX_ALREADYGONE))
-                       iax2_queue_frame(pvt->callno, &af);
-           }
-           break;
-           case JB_DROP:
-               /*if(next != jb_next(pvt->jb)) fprintf(stderr, "NEXT %ld is not next %ld!\n", jb_next(pvt->jb), next); */
-               iax2_frame_free(frame.data);
-           break;
-           case JB_NOFRAME:
-           case JB_EMPTY:
-               /* do nothing */
-           break;
-           default:
-               /* shouldn't happen */
-           break;
-       }
+               ret = jb_get(pvt->jb,&frame,now,ast_codec_interp_len(pvt->voiceformat));
+               switch(ret) {
+               case JB_OK:
+                       /*if(frame.type == JB_TYPE_VOICE && next + 20 != jb_next(pvt->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(pvt->jb), next); */
+                       fr = frame.data;
+                       __do_deliver(fr);
+                   break;
+               case JB_INTERP:
+                   {
+                       struct ast_frame af;
+       
+                       /*if(next + 20 != jb_next(pvt->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(pvt->jb), next); */
+       
+                       /* create an interpolation frame */
+                       /*fprintf(stderr, "Making Interpolation frame\n"); */
+                       af.frametype = AST_FRAME_VOICE;
+                       af.subclass = pvt->voiceformat;
+                       af.datalen  = 0;
+                       af.samples  = frame.ms * 8;
+                       af.mallocd  = 0;
+                       af.src  = "IAX2 JB interpolation";
+                       af.data  = NULL;
+                       af.delivery = ast_tvadd(pvt->rxcore, ast_samp2tv(next, 1000));
+                       af.offset=AST_FRIENDLY_OFFSET;
+       
+                       /* queue the frame:  For consistency, we would call __do_deliver here, but __do_deliver wants an iax_frame,
+                        * which we'd need to malloc, and then it would free it.  That seems like a drag */
+                       if (iaxs[pvt->callno] && !ast_test_flag(iaxs[pvt->callno], IAX_ALREADYGONE))
+                               iax2_queue_frame(pvt->callno, &af);
+                   }
+                   break;
+               case JB_DROP:
+                       /*if(next != jb_next(pvt->jb)) fprintf(stderr, "NEXT %ld is not next %ld!\n", jb_next(pvt->jb), next); */
+                       iax2_frame_free(frame.data);
+                   break;
+               case JB_NOFRAME:
+               case JB_EMPTY:
+                       /* do nothing */
+                   break;
+               default:
+                       /* shouldn't happen */
+                   break;
+               }
     }
     update_jbsched(pvt);
     ast_mutex_unlock(&iaxsl[pvt->callno]);
@@ -2185,7 +2209,7 @@ static int get_from_jb(void *p) {
 
 /* while we transition from the old JB to the new one, we can either make two schedule_delivery functions, or 
  * make preprocessor swiss-cheese out of this one.  I'm not sure which is less revolting.. */
-static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int updatehistory, int fromtrunk)
+static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtrunk)
 {
 #ifdef NEWJB
        int type, len;
@@ -2205,9 +2229,9 @@ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int update
 #endif
 
 #if 0
-       if (option_debug)
-               ast_log(LOG_DEBUG, "schedule_delivery: ts=%d, last=%d, really=%d, update=%d\n",
-                               fr->ts, iaxs[fr->callno]->last, reallydeliver, updatehistory);
+       if (option_debug && iaxdebug)
+               ast_log(LOG_DEBUG, "schedule_delivery: ts=%d, last=%d, update=%d\n",
+                               fr->ts, iaxs[fr->callno]->last, updatehistory);
 #endif
 
        /* Attempt to recover wrapped timestamps */
@@ -2225,12 +2249,11 @@ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int update
                */
                x = fr->ts - iaxs[fr->callno]->last;
                if (x > TS_GAP_FOR_JB_RESYNC || x < -TS_GAP_FOR_JB_RESYNC) {
-                       if (option_debug)
+                       if (option_debug && iaxdebug)
                                ast_log(LOG_DEBUG, "schedule_delivery: call=%d: TS jumped.  resyncing rxcore (ts=%d, last=%d)\n",
                                                        fr->callno, fr->ts, iaxs[fr->callno]->last);
                        /* zap rxcore - calc_rxstamp will make a new one based on this frame */
-                       iaxs[fr->callno]->rxcore.tv_sec = 0;
-                       iaxs[fr->callno]->rxcore.tv_usec = 0;
+                       iaxs[fr->callno]->rxcore = ast_tv(0, 0);
                        /* wipe "last" if stamps have jumped backwards */
                        if (x<0)
                                iaxs[fr->callno]->last = 0;
@@ -2257,23 +2280,13 @@ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int update
 
 
        /* delivery time is sender's sent timestamp converted back into absolute time according to our clock */
-       if ( (!fromtrunk) && (iaxs[fr->callno]->rxcore.tv_sec || iaxs[fr->callno]->rxcore.tv_usec) ) {
-               fr->af.delivery.tv_sec = iaxs[fr->callno]->rxcore.tv_sec;
-               fr->af.delivery.tv_usec = iaxs[fr->callno]->rxcore.tv_usec;
-               fr->af.delivery.tv_sec += fr->ts / 1000;
-               fr->af.delivery.tv_usec += (fr->ts % 1000) * 1000;
-               if (fr->af.delivery.tv_usec >= 1000000) {
-                       fr->af.delivery.tv_usec -= 1000000;
-                       fr->af.delivery.tv_sec += 1;
-               }
-       }
+       if ( !fromtrunk && !ast_tvzero(iaxs[fr->callno]->rxcore))
+               fr->af.delivery = ast_tvadd(iaxs[fr->callno]->rxcore, ast_samp2tv(fr->ts, 1000));
        else {
 #if 0
-               if (reallydeliver)
-                       ast_log(LOG_DEBUG, "schedule_delivery: set delivery to 0 as we don't have an rxcore yet, or frame is from trunk.\n");
+               ast_log(LOG_DEBUG, "schedule_delivery: set delivery to 0 as we don't have an rxcore yet, or frame is from trunk.\n");
 #endif
-               fr->af.delivery.tv_sec = 0;
-               fr->af.delivery.tv_usec = 0;
+               fr->af.delivery = ast_tv(0,0);
        }
 
 #ifndef NEWJB
@@ -2310,15 +2323,12 @@ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int update
 #endif
 
 #ifdef NEWJB
-       if(!reallydeliver)
-               return 0;
-
        type = JB_TYPE_CONTROL;
        len = 0;
 
        if(fr->af.frametype == AST_FRAME_VOICE) {
                type = JB_TYPE_VOICE;
-                len = ast_codec_get_samples(&fr->af) / 8;
+               len = ast_codec_get_samples(&fr->af) / 8;
        } else if(fr->af.frametype == AST_FRAME_CNG) {
                type = JB_TYPE_SILENCE;
        }
@@ -2346,9 +2356,9 @@ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int update
 
                iaxs[fr->callno]->jbid = -1;
 
-                /* deliver this frame now */
-                __do_deliver(fr);
-                return 0;
+               /* deliver this frame now */
+               __do_deliver(fr);
+               return 0;
 
        }
 
@@ -2398,10 +2408,6 @@ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int update
        /* update "min", just for RRs and stats */
        iaxs[fr->callno]->min = min; 
 
-       /* If the caller just wanted us to update, return now */
-       if (!reallydeliver)
-               return 0;
-
        /* Subtract the lateness from our jitter buffer to know how long to wait
           before sending our packet.  */
        delay = iaxs[fr->callno]->jitterbuffer - ms;
@@ -2415,7 +2421,7 @@ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int update
        if ( (!ast_test_flag(iaxs[fr->callno], IAX_USEJITTERBUF)) || fromtrunk )
                delay = 0;
 
-       if (option_debug) {
+       if (option_debug && iaxdebug) {
                /* Log jitter stats for possible offline analysis */
                ast_log(LOG_DEBUG, "Jitter: call=%d ts=%d orig=%d last=%d %s: min=%d max=%d jb=%d %+d lateness=%d jbdelay=%d jitter=%d historic=%d\n",
                                        fr->callno, fr->ts, orig_ts, iaxs[fr->callno]->last,
@@ -2429,18 +2435,18 @@ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int update
        if (delay < 1) {
                /* Don't deliver it more than 4 ms late */
                if ((delay > -4) || (fr->af.frametype != AST_FRAME_VOICE)) {
-                       if (option_debug)
+                       if (option_debug && iaxdebug)
                                ast_log(LOG_DEBUG, "schedule_delivery: Delivering immediately (Calculated delay is %d)\n", delay);
                        __do_deliver(fr);
                } else {
-                       if (option_debug)
+                       if (option_debug && iaxdebug)
                                ast_log(LOG_DEBUG, "schedule_delivery: Dropping voice packet since %dms delay is too old\n", delay);
                        iaxs[fr->callno]->frames_dropped++;
                        /* Free our iax frame */
                        iax2_frame_free(fr);
                }
        } else {
-               if (option_debug)
+               if (option_debug && iaxdebug)
                        ast_log(LOG_DEBUG, "schedule_delivery: Scheduling delivery in %d ms\n", delay);
                fr->retrans = ast_sched_add(sched, delay, do_deliver, fr);
        }
@@ -2485,7 +2491,7 @@ static int iax2_sendtext(struct ast_channel *c, const char *text)
 {
        
        return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_TEXT,
-               0, 0, text, strlen(text) + 1, -1);
+               0, 0, (unsigned char *)text, strlen(text) + 1, -1);
 }
 
 static int iax2_sendimage(struct ast_channel *c, struct ast_frame *img)
@@ -2495,7 +2501,7 @@ static int iax2_sendimage(struct ast_channel *c, struct ast_frame *img)
 
 static int iax2_sendhtml(struct ast_channel *c, int subclass, const char *data, int datalen)
 {
-       return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_HTML, subclass, 0, data, datalen, -1);
+       return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_HTML, subclass, 0, (unsigned char *)data, datalen, -1);
 }
 
 static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan)
@@ -2516,7 +2522,7 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, in
 static void destroy_user(struct iax2_user *user);
 static int expire_registry(void *data);
 
-static struct iax2_peer *realtime_peer(const char *peername)
+static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in *sin)
 {
        struct ast_variable *var;
        struct ast_variable *tmp;
@@ -2524,7 +2530,24 @@ static struct iax2_peer *realtime_peer(const char *peername)
        time_t regseconds, nowtime;
        int dynamic=0;
 
-       var = ast_load_realtime("iaxpeers", "name", peername, NULL);
+       if (peername)
+               var = ast_load_realtime("iaxpeers", "name", peername, NULL);
+       else {
+               char iabuf[INET_ADDRSTRLEN];
+               char porta[25];
+               ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr);
+               sprintf(porta, "%d", ntohs(sin->sin_port));
+               var = ast_load_realtime("iaxpeers", "ipaddr", iabuf, "port", porta, NULL);
+               if (var) {
+                       /* We'll need the peer name in order to build the structure! */
+                       tmp = var;
+                       while(tmp) {
+                               if (!strcasecmp(tmp->name, "name"))
+                                       peername = tmp->value;
+                               tmp = tmp->next;
+                       }
+               }
+       }
        if (!var)
                return NULL;
 
@@ -2579,7 +2602,7 @@ static struct iax2_peer *realtime_peer(const char *peername)
                ast_set_flag(peer, IAX_TEMPONLY);       
        }
 
-       if (dynamic) {
+       if (!ast_test_flag(&globalflags, IAX_RTIGNOREREGEXPIRE) && dynamic) {
                time(&nowtime);
                if ((nowtime - regseconds) > IAX_DEFAULT_REG_EXPIRE) {
                        memset(&peer->addr, 0, sizeof(peer->addr));
@@ -2658,8 +2681,8 @@ struct create_addr_info {
        char outkey[80];
        char timezone[80];
        char prefs[32];
-       char context[AST_MAX_EXTENSION];
-       char peercontext[AST_MAX_EXTENSION];
+       char context[AST_MAX_CONTEXT];
+       char peercontext[AST_MAX_CONTEXT];
 };
 
 static int create_addr(const char *peername, struct sockaddr_in *sin, struct create_addr_info *cai)
@@ -2813,7 +2836,7 @@ struct parsed_dial_string {
  */
 static void parse_dial_string(char *data, struct parsed_dial_string *pds)
 {
-       if (!data || ast_strlen_zero(data))
+       if (ast_strlen_zero(data))
                return;
 
        pds->peer = strsep(&data, "/");
@@ -2916,7 +2939,10 @@ static int iax2_call(struct ast_channel *c, char *dest, int timeout)
                iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, l);
                iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->cid.cid_pres);
        } else {
-               iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, AST_PRES_NUMBER_NOT_AVAILABLE);
+               if (n)
+                       iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->cid.cid_pres);
+               else
+                       iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, AST_PRES_NUMBER_NOT_AVAILABLE);
        }
 
        iax_ie_append_byte(&ied, IAX_IE_CALLINGTON, c->cid.cid_ton);
@@ -2927,9 +2953,9 @@ static int iax2_call(struct ast_channel *c, char *dest, int timeout)
        if (ast_test_flag(iaxs[callno], IAX_SENDANI) && c->cid.cid_ani)
                iax_ie_append_str(&ied, IAX_IE_CALLING_ANI, c->cid.cid_ani);
 
-       if (c->language && !ast_strlen_zero(c->language))
+       if (!ast_strlen_zero(c->language))
                iax_ie_append_str(&ied, IAX_IE_LANGUAGE, c->language);
-       if (c->cid.cid_dnid && !ast_strlen_zero(c->cid.cid_dnid))
+       if (!ast_strlen_zero(c->cid.cid_dnid))
                iax_ie_append_str(&ied, IAX_IE_DNID, c->cid.cid_dnid);
 
        if (pds.context)
@@ -3011,18 +3037,29 @@ static int iax2_setoption(struct ast_channel *c, int option, void *data, int dat
 {
        struct ast_option_header *h;
        int res;
-       h = malloc(datalen + sizeof(struct ast_option_header));
-       if (h) {
-               h->flag = AST_OPTION_FLAG_REQUEST;
-               h->option = htons(option);
-               memcpy(h->data, data, datalen);
-               res = send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_CONTROL,
-                       AST_CONTROL_OPTION, 0, (char *)h, datalen + sizeof(struct ast_option_header), -1);
-               free(h);
-               return res;
-       } else 
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return -1;
+
+       switch (option) {
+       case AST_OPTION_TXGAIN:
+       case AST_OPTION_RXGAIN:
+               /* these two cannot be sent, because they require a result */
+               errno = ENOSYS;
+               return -1;
+       default:
+               h = malloc(datalen + sizeof(*h));
+               if (h) {
+                       h->flag = AST_OPTION_FLAG_REQUEST;
+                       h->option = htons(option);
+                       memcpy(h->data, data, datalen);
+                       res = send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_CONTROL,
+                                                 AST_CONTROL_OPTION, 0, (unsigned char *) h,
+                                                 datalen + sizeof(*h), -1);
+                       free(h);
+                       return res;
+               } else {
+                       ast_log(LOG_WARNING, "Out of memory\n");
+                       return -1;
+               }
+       }
 }
 
 static struct ast_frame *iax2_read(struct ast_channel *c) 
@@ -3075,7 +3112,7 @@ static void unlock_both(unsigned short callno0, unsigned short callno1)
        ast_mutex_unlock(&iaxsl[callno0]);
 }
 
-static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
+static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
 {
        struct ast_channel *cs[3];
        struct ast_channel *who;
@@ -3114,7 +3151,7 @@ static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
                                iaxs[callno1]->bridgecallno = 0;
                                ast_mutex_unlock(&iaxsl[callno1]);
                        }
-                       return -2;
+                       return AST_BRIDGE_FAILED_NOWARN;
                }
                if (c0->nativeformats != c1->nativeformats) {
                        if (option_verbose > 2) {
@@ -3129,7 +3166,7 @@ static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
                        iaxs[callno0]->bridgecallno = 0;
                        iaxs[callno1]->bridgecallno = 0;
                        unlock_both(callno0, callno1);
-                       return -2;
+                       return AST_BRIDGE_FAILED_NOWARN;
                }
                /* check if transfered and if we really want native bridging */
                if (!transferstarted && !ast_test_flag(iaxs[callno0], IAX_NOTRANSFER) && !ast_test_flag(iaxs[callno1], IAX_NOTRANSFER) && 
@@ -3142,23 +3179,31 @@ static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
                if ((iaxs[callno0]->transferring == TRANSFER_RELEASED) && (iaxs[callno1]->transferring == TRANSFER_RELEASED)) {
                        /* Call has been transferred.  We're no longer involved */
                        gettimeofday(&tv, NULL);
-                       if (!waittimer.tv_sec && !waittimer.tv_usec) {
-                               waittimer.tv_sec = tv.tv_sec;
-                               waittimer.tv_usec = tv.tv_usec;
+                       if (ast_tvzero(waittimer)) {
+                               waittimer = tv;
                        } else if (tv.tv_sec - waittimer.tv_sec > IAX_LINGER_TIMEOUT) {
                                c0->_softhangup |= AST_SOFTHANGUP_DEV;
                                c1->_softhangup |= AST_SOFTHANGUP_DEV;
                                *fo = NULL;
                                *rc = c0;
-                               res = 0;
+                               res = AST_BRIDGE_COMPLETE;
                                break;
                        }
                }
                to = 1000;
                who = ast_waitfor_n(cs, 2, &to);
+               if (timeoutms > -1) {
+                       timeoutms -= (1000 - to);
+                       if (timeoutms < 0)
+                               timeoutms = 0;
+               }
                if (!who) {
+                       if (!timeoutms) {
+                               res = AST_BRIDGE_RETRY;
+                               break;
+                       }
                        if (ast_check_hangup(c0) || ast_check_hangup(c1)) {
-                               res = -1;
+                               res = AST_BRIDGE_FAILED;
                                break;
                        }
                        continue;
@@ -3167,28 +3212,27 @@ static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
                if (!f) {
                        *fo = NULL;
                        *rc = who;
-                       res = 0;
+                       res = AST_BRIDGE_COMPLETE;
                        break;
                }
                if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
                        *fo = f;
                        *rc = who;
-                       res =  0;
+                       res =  AST_BRIDGE_COMPLETE;
                        break;
                }
                if ((f->frametype == AST_FRAME_VOICE) ||
-                       (f->frametype == AST_FRAME_TEXT) ||
-                       (f->frametype == AST_FRAME_VIDEO) || 
-                       (f->frametype == AST_FRAME_IMAGE) ||
-                       (f->frametype == AST_FRAME_DTMF)) {
+                   (f->frametype == AST_FRAME_TEXT) ||
+                   (f->frametype == AST_FRAME_VIDEO) || 
+                   (f->frametype == AST_FRAME_IMAGE) ||
+                   (f->frametype == AST_FRAME_DTMF)) {
                        if ((f->frametype == AST_FRAME_DTMF) && 
-                               (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) {
+                           (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) {
                                if ((who == c0)) {
                                        if  ((flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
                                                *rc = c0;
                                                *fo = f;
-                                               /* Take out of conference mode */
-                                               res = 0;
+                                               res = AST_BRIDGE_COMPLETE;
                                                /* Remove from native mode */
                                                break;
                                        } else 
@@ -3198,15 +3242,15 @@ static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
                                        if (flags & AST_BRIDGE_DTMF_CHANNEL_1) {
                                                *rc = c1;
                                                *fo = f;
-                                               res =  0;
-                                               /* Remove from native mode */
+                                               res =  AST_BRIDGE_COMPLETE;
                                                break;
                                        } else
                                                goto tackygoto;
                                }
                        } else {
 #if 0
-                               ast_log(LOG_DEBUG, "Read from %s\n", who->name);
+                               if (iaxdebug && option_debug)
+                                       ast_log(LOG_DEBUG, "Read from %s\n", who->name);
                                if (who == last) 
                                        ast_log(LOG_DEBUG, "Servicing channel %s twice in a row?\n", last->name);
                                last = who;
@@ -3238,14 +3282,14 @@ static int iax2_answer(struct ast_channel *c)
 {
        unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
        if (option_debug)
-               ast_log(LOG_DEBUG, "Answering\n");
+               ast_log(LOG_DEBUG, "Answering IAX2 call\n");
        return send_command_locked(callno, AST_FRAME_CONTROL, AST_CONTROL_ANSWER, 0, NULL, 0, -1);
 }
 
 static int iax2_indicate(struct ast_channel *c, int condition)
 {
        unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
-       if (option_debug)
+       if (option_debug && iaxdebug)
                ast_log(LOG_DEBUG, "Indicating condition %d\n", condition);
        return send_command_locked(callno, AST_FRAME_CONTROL, condition, 0, NULL, 0, -1);
 }
@@ -3254,7 +3298,7 @@ static int iax2_transfer(struct ast_channel *c, const char *dest)
 {
        unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
        struct iax_ie_data ied;
-       char tmp[256] = "", *context;
+       char tmp[256], *context;
        ast_copy_string(tmp, dest, sizeof(tmp));
        context = strchr(tmp, '@');
        if (context) {
@@ -3305,10 +3349,7 @@ static struct ast_channel *ast_iax2_new(int callno, int state, int capability)
        i = iaxs[callno];
        if (i && tmp) {
                tmp->tech = &iax2_tech;
-               if (!ast_strlen_zero(i->username))
-                       snprintf(tmp->name, sizeof(tmp->name), "IAX2/%s@%s-%d", i->username, i->host, i->callno);
-               else
-                       snprintf(tmp->name, sizeof(tmp->name), "IAX2/%s-%d", i->host, i->callno);
+               snprintf(tmp->name, sizeof(tmp->name), "IAX2/%s-%d", i->host, i->callno);
                tmp->type = channeltype;
                /* We can support any format by default, until we get restricted */
                tmp->nativeformats = capability;
@@ -3363,21 +3404,17 @@ static unsigned int calc_txpeerstamp(struct iax2_trunk_peer *tpeer, int sampms,
        long int ms, pred;
 
        tpeer->trunkact = *tv;
-       mssincetx = (tv->tv_sec - tpeer->lasttxtime.tv_sec) * 1000 +
-                       (1000000 + tv->tv_usec - tpeer->lasttxtime.tv_usec) / 1000 - 1000;
-       if (mssincetx > 5000 || (!tpeer->txtrunktime.tv_sec && !tpeer->txtrunktime.tv_usec)) {
+       mssincetx = ast_tvdiff_ms(*tv, tpeer->lasttxtime);
+       if (mssincetx > 5000 || ast_tvzero(tpeer->txtrunktime)) {
                /* If it's been at least 5 seconds since the last time we transmitted on this trunk, reset our timers */
-               tpeer->txtrunktime.tv_sec = tv->tv_sec;
-               tpeer->txtrunktime.tv_usec = tv->tv_usec;
+               tpeer->txtrunktime = *tv;
                tpeer->lastsent = 999999;
        }
        /* Update last transmit time now */
-       tpeer->lasttxtime.tv_sec = tv->tv_sec;
-       tpeer->lasttxtime.tv_usec = tv->tv_usec;
+       tpeer->lasttxtime = *tv;
        
        /* Calculate ms offset */
-       ms = (tv->tv_sec - tpeer->txtrunktime.tv_sec) * 1000 +
-               (1000000 + tv->tv_usec - tpeer->txtrunktime.tv_usec) / 1000 - 1000;
+       ms = ast_tvdiff_ms(*tv, tpeer->txtrunktime);
        /* Predict from last value */
        pred = tpeer->lastsent + sampms;
        if (abs(ms - pred) < MAX_TIMESTAMP_SKEW)
@@ -3393,37 +3430,24 @@ static unsigned int calc_txpeerstamp(struct iax2_trunk_peer *tpeer, int sampms,
 static unsigned int fix_peerts(struct timeval *tv, int callno, unsigned int ts)
 {
        long ms;        /* NOT unsigned */
-       if (!iaxs[callno]->rxcore.tv_sec && !iaxs[callno]->rxcore.tv_usec) {
+       if (ast_tvzero(iaxs[callno]->rxcore)) {
                /* Initialize rxcore time if appropriate */
                gettimeofday(&iaxs[callno]->rxcore, NULL);
                /* Round to nearest 20ms so traces look pretty */
                iaxs[callno]->rxcore.tv_usec -= iaxs[callno]->rxcore.tv_usec % 20000;
        }
        /* Calculate difference between trunk and channel */
-       ms = (tv->tv_sec - iaxs[callno]->rxcore.tv_sec) * 1000 + 
-               (1000000 + tv->tv_usec - iaxs[callno]->rxcore.tv_usec) / 1000 - 1000;
+       ms = ast_tvdiff_ms(*tv, iaxs[callno]->rxcore);
        /* Return as the sum of trunk time and the difference between trunk and real time */
        return ms + ts;
 }
 
-static void add_ms(struct timeval *tv, int ms) {
-       tv->tv_usec += ms * 1000;
-       if(tv->tv_usec > 1000000) {
-               tv->tv_usec -= 1000000;
-               tv->tv_sec++;
-       }
-       if(tv->tv_usec < 0) {
-               tv->tv_usec += 1000000;
-               tv->tv_sec--;
-       }
-}
-
 static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, struct ast_frame *f)
 {
-       struct timeval tv;
        int ms;
        int voice = 0;
        int genuine = 0;
+       int adjust;
        struct timeval *delivery = NULL;
 
 
@@ -3443,7 +3467,7 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
                        p->notsilenttx = 0;     
                }
        }
-       if (!p->offset.tv_sec && !p->offset.tv_usec) {
+       if (ast_tvzero(p->offset)) {
                gettimeofday(&p->offset, NULL);
                /* Round to nearest 20ms for nice looking traces */
                p->offset.tv_usec -= p->offset.tv_usec % 20000;
@@ -3452,23 +3476,40 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
        if (ts)
                return ts;
        /* If we have a time that the frame arrived, always use it to make our timestamp */
-       if (delivery && (delivery->tv_sec || delivery->tv_usec)) {
-               ms = (delivery->tv_sec - p->offset.tv_sec) * 1000 +
-                       (1000000 + delivery->tv_usec - p->offset.tv_usec) / 1000 - 1000;
-               if (option_debug > 2)
+       if (delivery && !ast_tvzero(*delivery)) {
+               ms = ast_tvdiff_ms(*delivery, p->offset);
+               if (option_debug > 2 && iaxdebug)
                        ast_log(LOG_DEBUG, "calc_timestamp: call %d/%d: Timestamp slaved to delivery time\n", p->callno, iaxs[p->callno]->peercallno);
        } else {
-               gettimeofday(&tv, NULL);
-               ms = (tv.tv_sec - p->offset.tv_sec) * 1000 +
-                       (1000000 + tv.tv_usec - p->offset.tv_usec) / 1000 - 1000;
+               ms = ast_tvdiff_ms(ast_tvnow(), p->offset);
                if (ms < 0)
                        ms = 0;
                if (voice) {
                        /* On a voice frame, use predicted values if appropriate */
                        if (p->notsilenttx && abs(ms - p->nextpred) <= MAX_TIMESTAMP_SKEW) {
-                               /* Adjust our txcore, keeping voice and 
-                                       non-voice synchronized */
-                               add_ms(&p->offset, (int)(ms - p->nextpred)/10);
+                               /* Adjust our txcore, keeping voice and non-voice synchronized */
+                               /* AN EXPLANATION:
+                                  When we send voice, we usually send "calculated" timestamps worked out
+                                  on the basis of the number of samples sent. When we send other frames,
+                                  we usually send timestamps worked out from the real clock.
+                                  The problem is that they can tend to drift out of step because the 
+                                  source channel's clock and our clock may not be exactly at the same rate.
+                                  We fix this by continuously "tweaking" p->offset.  p->offset is "time zero"
+                                  for this call.  Moving it adjusts timestamps for non-voice frames.
+                                  We make the adjustment in the style of a moving average.  Each time we
+                                  adjust p->offset by 10% of the difference between our clock-derived
+                                  timestamp and the predicted timestamp.  That's why you see "10000"
+                                  below even though IAX2 timestamps are in milliseconds.
+                                  The use of a moving average avoids offset moving too radically.
+                                  Generally, "adjust" roams back and forth around 0, with offset hardly
+                                  changing at all.  But if a consistent different starts to develop it
+                                  will be eliminated over the course of 10 frames (200-300msecs) 
+                               */
+                               adjust = (ms - p->nextpred);
+                               if (adjust < 0)
+                                       p->offset = ast_tvsub(p->offset, ast_samp2tv(abs(adjust), 10000));
+                               else if (adjust > 0)
+                                       p->offset = ast_tvadd(p->offset, ast_samp2tv(adjust, 10000));
 
                                if (!p->nextpred) {
                                        p->nextpred = ms; /*f->samples / 8;*/
@@ -3486,8 +3527,8 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
                                * silent periods are multiples of
                                * frame size too) */
 
-                               if (abs(ms - p->nextpred) > MAX_TIMESTAMP_SKEW)
-                                       ast_log(LOG_DEBUG,"predicted timestamp skew (%u) > max (%u), using real ts instead.",
+                               if (iaxdebug && abs(ms - p->nextpred) > MAX_TIMESTAMP_SKEW )
+                                       ast_log(LOG_DEBUG, "predicted timestamp skew (%u) > max (%u), using real ts instead.\n",
                                                abs(ms - p->nextpred), MAX_TIMESTAMP_SKEW);
 
                                if (f->samples >= 8) /* check to make sure we dont core dump */
@@ -3529,19 +3570,18 @@ static unsigned int calc_fakestamp(struct chan_iax2_pvt *p1, struct chan_iax2_pv
        /* Receive from p1, send to p2 */
        
        /* Setup rxcore if necessary on outgoing channel */
-       if (!p1->rxcore.tv_sec && !p1->rxcore.tv_usec)
-               gettimeofday(&p1->rxcore, NULL);
+       if (ast_tvzero(p1->rxcore))
+               p1->rxcore = ast_tvnow();
 
        /* Setup txcore if necessary on outgoing channel */
-       if (!p2->offset.tv_sec && !p2->offset.tv_usec)
-               gettimeofday(&p2->offset, NULL);
+       if (ast_tvzero(p2->offset))
+               p2->offset = ast_tvnow();
        
        /* Now, ts is the timestamp of the original packet in the orignal context.
           Adding rxcore to it gives us when we would want the packet to be delivered normally.
           Subtracting txcore of the outgoing channel gives us what we'd expect */
        
-       ms = (p1->rxcore.tv_sec - p2->offset.tv_sec) * 1000 +
-               (1000000 + p1->rxcore.tv_usec - p2->offset.tv_usec) / 1000 - 1000;
+       ms = ast_tvdiff_ms(p1->rxcore, p2->offset);
        fakets += ms;
 
        /* FIXME? SLD would rather remove this and leave it to the end system to deal with */
@@ -3556,33 +3596,25 @@ static unsigned int calc_rxstamp(struct chan_iax2_pvt *p, unsigned int offset)
 {
        /* Returns where in "receive time" we are.  That is, how many ms
           since we received (or would have received) the frame with timestamp 0 */
-       struct timeval tv;
        int ms;
 #ifdef IAXTESTS
        int jit;
 #endif /* IAXTESTS */
        /* Setup rxcore if necessary */
-       if (!p->rxcore.tv_sec && !p->rxcore.tv_usec) {
-               gettimeofday(&p->rxcore, NULL);
-               if (option_debug)
+       if (ast_tvzero(p->rxcore)) {
+               p->rxcore = ast_tvnow();
+               if (option_debug && iaxdebug)
                        ast_log(LOG_DEBUG, "calc_rxstamp: call=%d: rxcore set to %d.%6.6d - %dms\n",
                                        p->callno, (int)(p->rxcore.tv_sec), (int)(p->rxcore.tv_usec), offset);
-               p->rxcore.tv_sec -= offset / 1000;
-               p->rxcore.tv_usec -= (offset % 1000) * 1000;
-               if (p->rxcore.tv_usec < 0) {
-                       p->rxcore.tv_usec += 1000000;
-                       p->rxcore.tv_sec -= 1;
-               }
+               p->rxcore = ast_tvsub(p->rxcore, ast_samp2tv(offset, 1000));
 #if 1
-               if (option_debug)
+               if (option_debug && iaxdebug)
                        ast_log(LOG_DEBUG, "calc_rxstamp: call=%d: works out as %d.%6.6d\n",
                                        p->callno, (int)(p->rxcore.tv_sec),(int)( p->rxcore.tv_usec));
 #endif
        }
 
-       gettimeofday(&tv, NULL);
-       ms = (tv.tv_sec - p->rxcore.tv_sec) * 1000 +
-               (1000000 + tv.tv_usec - p->rxcore.tv_usec) / 1000 - 1000;
+       ms = ast_tvdiff_ms(ast_tvnow(), p->rxcore);
 #ifdef IAXTESTS
        if (test_jit) {
                if (!test_jitpct || ((100.0 * rand() / (RAND_MAX + 1.0)) < test_jitpct)) {
@@ -3622,7 +3654,7 @@ static struct iax2_trunk_peer *find_tpeer(struct sockaddr_in *sin, int fd)
                        ast_mutex_init(&tpeer->lock);
                        tpeer->lastsent = 9999;
                        memcpy(&tpeer->addr, sin, sizeof(tpeer->addr));
-                       gettimeofday(&tpeer->trunkact, NULL);
+                       tpeer->trunkact = ast_tvnow();
                        ast_mutex_lock(&tpeer->lock);
                        tpeer->next = tpeers;
                        tpeer->sockfd = fd;
@@ -3671,7 +3703,7 @@ static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr)
 
                /* Append to meta frame */
                ptr = tpeer->trunkdata + IAX2_TRUNK_PREFACE + tpeer->trunkdatalen;
-               if(send_trunktimestamps) {      
+               if (ast_test_flag(&globalflags, IAX_TRUNKTIMESTAMPS)) {
                        mtm = (struct ast_iax2_meta_trunk_mini *)ptr;
                        mtm->len = htons(f->datalen);
                        mtm->mini.callno = htons(pvt->callno);
@@ -3705,7 +3737,14 @@ static void build_enc_keys(const unsigned char *digest, aes_encrypt_ctx *ecx, ae
 
 static void memcpy_decrypt(unsigned char *dst, const unsigned char *src, int len, aes_decrypt_ctx *dcx)
 {
-/*     memcpy(dst, src, len); */
+#if 0
+       /* Debug with "fake encryption" */
+       int x;
+       if (len % 16)
+               ast_log(LOG_WARNING, "len should be multiple of 16, not %d!\n", len);
+       for (x=0;x<len;x++)
+               dst[x] = src[x] ^ 0xff;
+#else  
        unsigned char lastblock[16] = { 0 };
        int x;
        while(len > 0) {
@@ -3717,11 +3756,19 @@ static void memcpy_decrypt(unsigned char *dst, const unsigned char *src, int len
                src += 16;
                len -= 16;
        }
+#endif
 }
 
 static void memcpy_encrypt(unsigned char *dst, const unsigned char *src, int len, aes_encrypt_ctx *ecx)
 {
-/*     memcpy(dst, src, len); */
+#if 0
+       /* Debug with "fake encryption" */
+       int x;
+       if (len % 16)
+               ast_log(LOG_WARNING, "len should be multiple of 16, not %d!\n", len);
+       for (x=0;x<len;x++)
+               dst[x] = src[x] ^ 0xff;
+#else
        unsigned char curblock[16] = { 0 };
        int x;
        while(len > 0) {
@@ -3733,6 +3780,7 @@ static void memcpy_encrypt(unsigned char *dst, const unsigned char *src, int len
                src += 16;
                len -= 16;
        }
+#endif
 }
 
 static int decode_frame(aes_decrypt_ctx *dcx, struct ast_iax2_full_hdr *fh, struct ast_frame *f, int *datalen)
@@ -3744,15 +3792,17 @@ static int decode_frame(aes_decrypt_ctx *dcx, struct ast_iax2_full_hdr *fh, stru
                return -1;
        if (ntohs(fh->scallno) & IAX_FLAG_FULL) {
                struct ast_iax2_full_enc_hdr *efh = (struct ast_iax2_full_enc_hdr *)fh;
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Decoding full frame with length %d\n", *datalen);
                if (*datalen < 16 + sizeof(struct ast_iax2_full_hdr))
                        return -1;
-               padding = 16 + (efh->encdata[15] & 0xf);
+               /* Decrypt */
+               memcpy_decrypt(workspace, efh->encdata, *datalen - sizeof(struct ast_iax2_full_enc_hdr), dcx);
+
+               padding = 16 + (workspace[15] & 0xf);
+               if (option_debug && iaxdebug)
+                       ast_log(LOG_DEBUG, "Decoding full frame with length %d (padding = %d) (15=%02x)\n", *datalen, padding, workspace[15]);
                if (*datalen < padding + sizeof(struct ast_iax2_full_hdr))
                        return -1;
-               /* Decrypt */
-               memcpy_decrypt(workspace, efh->encdata, *datalen, dcx);
+
                *datalen -= padding;
                memcpy(efh->encdata, workspace + padding, *datalen - sizeof(struct ast_iax2_full_enc_hdr));
                f->frametype = fh->type;
@@ -3763,15 +3813,15 @@ static int decode_frame(aes_decrypt_ctx *dcx, struct ast_iax2_full_hdr *fh, stru
                }
        } else {
                struct ast_iax2_mini_enc_hdr *efh = (struct ast_iax2_mini_enc_hdr *)fh;
-               if (option_debug)
+               if (option_debug && iaxdebug)
                        ast_log(LOG_DEBUG, "Decoding mini with length %d\n", *datalen);
                if (*datalen < 16 + sizeof(struct ast_iax2_mini_hdr))
                        return -1;
-               padding = 16 + (efh->encdata[15] & 0x0f);
+               /* Decrypt */
+               memcpy_decrypt(workspace, efh->encdata, *datalen - sizeof(struct ast_iax2_mini_enc_hdr), dcx);
+               padding = 16 + (workspace[15] & 0x0f);
                if (*datalen < padding + sizeof(struct ast_iax2_mini_hdr))
                        return -1;
-               /* Decrypt */
-               memcpy_decrypt(workspace, efh->encdata, *datalen, dcx);
                *datalen -= padding;
                memcpy(efh->encdata, workspace + padding, *datalen - sizeof(struct ast_iax2_mini_enc_hdr));
        }
@@ -3787,30 +3837,32 @@ static int encrypt_frame(aes_encrypt_ctx *ecx, struct ast_iax2_full_hdr *fh, uns
                return -1;
        if (ntohs(fh->scallno) & IAX_FLAG_FULL) {
                struct ast_iax2_full_enc_hdr *efh = (struct ast_iax2_full_enc_hdr *)fh;
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Encoding full frame with length %d\n", *datalen);
+               if (option_debug && iaxdebug)
+                       ast_log(LOG_DEBUG, "Encoding full frame %d/%d with length %d\n", fh->type, fh->csub, *datalen);
                padding = 16 - ((*datalen - sizeof(struct ast_iax2_full_enc_hdr)) % 16);
                padding = 16 + (padding & 0xf);
                memcpy(workspace, poo, padding);
                memcpy(workspace + padding, efh->encdata, *datalen - sizeof(struct ast_iax2_full_enc_hdr));
-               *datalen += padding;
                workspace[15] &= 0xf0;
                workspace[15] |= (padding & 0xf);
-               memcpy_encrypt(efh->encdata, workspace, *datalen, ecx);
+               if (option_debug && iaxdebug)
+                       ast_log(LOG_DEBUG, "Encoding full frame %d/%d with length %d + %d padding (15=%02x)\n", fh->type, fh->csub, *datalen, padding, workspace[15]);
+               *datalen += padding;
+               memcpy_encrypt(efh->encdata, workspace, *datalen - sizeof(struct ast_iax2_full_enc_hdr), ecx);
                if (*datalen >= 32 + sizeof(struct ast_iax2_full_enc_hdr))
                        memcpy(poo, workspace + *datalen - 32, 32);
        } else {
                struct ast_iax2_mini_enc_hdr *efh = (struct ast_iax2_mini_enc_hdr *)fh;
-               if (option_debug)
+               if (option_debug && iaxdebug)
                        ast_log(LOG_DEBUG, "Encoding mini frame with length %d\n", *datalen);
                padding = 16 - ((*datalen - sizeof(struct ast_iax2_mini_enc_hdr)) % 16);
                padding = 16 + (padding & 0xf);
-               memset(workspace, 0, padding);
+               memcpy(workspace, poo, padding);
                memcpy(workspace + padding, efh->encdata, *datalen - sizeof(struct ast_iax2_mini_enc_hdr));
                workspace[15] &= 0xf0;
                workspace[15] |= (padding & 0x0f);
                *datalen += padding;
-               memcpy_encrypt(efh->encdata, workspace, *datalen, ecx);
+               memcpy_encrypt(efh->encdata, workspace, *datalen - sizeof(struct ast_iax2_mini_enc_hdr), ecx);
                if (*datalen >= 32 + sizeof(struct ast_iax2_mini_enc_hdr))
                        memcpy(poo, workspace + *datalen - 32, 32);
        }
@@ -3830,8 +3882,8 @@ static int decrypt_frame(int callno, struct ast_iax2_full_hdr *fh, struct ast_fr
                stringp = tmppw;
                while((tmppw = strsep(&stringp, ";"))) {
                        MD5Init(&md5);
-                       MD5Update(&md5, iaxs[callno]->challenge, strlen(iaxs[callno]->challenge));
-                       MD5Update(&md5, tmppw, strlen(tmppw));
+                       MD5Update(&md5, (unsigned char *)iaxs[callno]->challenge, strlen(iaxs[callno]->challenge));
+                       MD5Update(&md5, (unsigned char *)tmppw, strlen(tmppw));
                        MD5Final(digest, &md5);
                        build_enc_keys(digest, &iaxs[callno]->ecx, &iaxs[callno]->dcx);
                        res = decode_frame(&iaxs[callno]->dcx, fh, f, datalen);
@@ -3959,6 +4011,12 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
                        pvt->svideoformat = f->subclass & ~0x1;
                if (ast_test_flag(pvt, IAX_ENCRYPTED)) {
                        if (ast_test_flag(pvt, IAX_KEYPOPULATED)) {
+                               if (iaxdebug) {
+                                       if (fr->transfer)
+                                               iax_showframe(fr, NULL, 2, &pvt->transfer, fr->datalen - sizeof(struct ast_iax2_full_hdr));
+                                       else
+                                               iax_showframe(fr, NULL, 2, &pvt->addr, fr->datalen - sizeof(struct ast_iax2_full_hdr));
+                               }
                                encrypt_frame(&pvt->ecx, fh, pvt->semirand, &fr->datalen);
                        } else
                                ast_log(LOG_WARNING, "Supposed to send packet encrypted, but no key?\n");
@@ -4018,7 +4076,7 @@ static int iax2_show_users(int fd, int argc, char *argv[])
 #define FORMAT2 "%-15.15s  %-20.20s  %-15.15d  %-15.15s  %-5.5s  %-5.10s\n"
 
        struct iax2_user *user;
-       char auth[90] = "";
+       char auth[90];
        char *pstr = "";
 
        switch (argc) {
@@ -4070,7 +4128,7 @@ static int iax2_show_users(int fd, int argc, char *argv[])
 #undef FORMAT2
 }
 
-static int iax2_show_peers(int fd, int argc, char *argv[])
+static int __iax2_show_peers(int manager, int fd, int argc, char *argv[])
 {
        regex_t regexbuf;
        int havepattern = 0;
@@ -4079,13 +4137,14 @@ static int iax2_show_peers(int fd, int argc, char *argv[])
        int offline_peers = 0;
        int unmonitored_peers = 0;
 
-#define FORMAT2 "%-15.15s  %-15.15s %s  %-15.15s  %-8s  %s %-10s\n"
-#define FORMAT "%-15.15s  %-15.15s %s  %-15.15s  %-5d%s  %s %-10s\n"
+#define FORMAT2 "%-15.15s  %-15.15s %s  %-15.15s  %-8s  %s %-10s%s"
+#define FORMAT "%-15.15s  %-15.15s %s  %-15.15s  %-5d%s  %s %-10s%s"
 
        struct iax2_peer *peer;
-       char name[256] = "";
+       char name[256];
        char iabuf[INET_ADDRSTRLEN];
        int registeredonly=0;
+       char *term = manager ? "\r\n" : "\n";
 
        switch (argc) {
        case 6:
@@ -4121,11 +4180,11 @@ static int iax2_show_peers(int fd, int argc, char *argv[])
        }
 
        ast_mutex_lock(&peerl.lock);
-       ast_cli(fd, FORMAT2, "Name/Username", "Host", "   ", "Mask", "Port", "   ", "Status");
+       ast_cli(fd, FORMAT2, "Name/Username", "Host", "   ", "Mask", "Port", "   ", "Status", term);
        for (peer = peerl.peers;peer;peer = peer->next) {
                char nm[20];
-               char status[20] = "";
-               char srch[2000] = "";
+               char status[20];
+               char srch[2000];
 
                if (registeredonly && !peer->addr.sin_addr.s_addr)
                        continue;
@@ -4141,12 +4200,12 @@ static int iax2_show_peers(int fd, int argc, char *argv[])
                                ast_copy_string(status, "UNREACHABLE", sizeof(status));
                                offline_peers++;
                        }
-                       else if (peer->lastms > peer->maxms)  {
-                               snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms);
+                       else if (peer->historicms > peer->maxms)  {
+                               snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->historicms);
                                offline_peers++;
                        }
-                       else if (peer->lastms)  {
-                               snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms);
+                       else if (peer->historicms)  {
+                               snprintf(status, sizeof(status), "OK (%d ms)", peer->historicms);
                                online_peers++;
                        }
                        else  {
@@ -4164,19 +4223,19 @@ static int iax2_show_peers(int fd, int argc, char *argv[])
                                        ast_test_flag(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
                                        nm,
                                        ntohs(peer->addr.sin_port), ast_test_flag(peer, IAX_TRUNK) ? "(T)" : "   ",
-                                       peer->encmethods ? "(E)" : "   ", status);
+                                       peer->encmethods ? "(E)" : "   ", status, term);
 
                ast_cli(fd, FORMAT, name, 
                                        peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)",
                                        ast_test_flag(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
                                        nm,
                                        ntohs(peer->addr.sin_port), ast_test_flag(peer, IAX_TRUNK) ? "(T)" : "   ",
-                                       peer->encmethods ? "(E)" : "   ", status);
+                                       peer->encmethods ? "(E)" : "   ", status, term);
                total_peers++;
        }
        ast_mutex_unlock(&peerl.lock);
 
-       ast_cli(fd,"%d iax2 peers [%d online, %d offline, %d unmonitored]\n", total_peers, online_peers, offline_peers, unmonitored_peers);
+       ast_cli(fd,"%d iax2 peers [%d online, %d offline, %d unmonitored]%s", total_peers, online_peers, offline_peers, unmonitored_peers, term);
 
        if (havepattern)
                regfree(&regexbuf);
@@ -4186,6 +4245,10 @@ static int iax2_show_peers(int fd, int argc, char *argv[])
 #undef FORMAT2
 }
 
+static int iax2_show_peers(int fd, int argc, char *argv[])
+{
+       return __iax2_show_peers(0, fd, argc, argv);
+}
 static int manager_iax2_show_netstats( struct mansession *s, struct message *m )
 {
        ast_cli_netstats(s->fd, 0);
@@ -4208,7 +4271,7 @@ static int iax2_show_firmware(int fd, int argc, char *argv[])
        
        ast_cli(fd, FORMAT2, "Device", "Version", "Size");
        for (cur = waresl.wares;cur;cur = cur->next) {
-               if ((argc == 3) || (!strcasecmp(argv[3], cur->fwh->devname))) 
+               if ((argc == 3) || (!strcasecmp(argv[3], (char *)cur->fwh->devname))) 
                        ast_cli(fd, FORMAT, cur->fwh->devname, ntohs(cur->fwh->version),
                                ntohl(cur->fwh->datalen));
        }
@@ -4223,10 +4286,12 @@ static int manager_iax2_show_peers( struct mansession *s, struct message *m )
 {
        char *a[] = { "iax2", "show", "users" };
        int ret;
-       ast_mutex_lock(&s->lock);
-       ret = iax2_show_peers( s->fd, 3, a );
-       ast_cli( s->fd, "\r\n\r\n" );
-       ast_mutex_unlock(&s->lock);
+       char *id;
+       id = astman_get_header(m,"ActionID");
+       if (!ast_strlen_zero(id))
+               ast_cli(s->fd, "ActionID: %s\r\n",id);
+       ret = __iax2_show_peers(1, s->fd, 3, a );
+       ast_cli(s->fd, "\r\n\r\n" );
        return ret;
 } /* /JDG */
 
@@ -4258,7 +4323,7 @@ static int iax2_show_registry(int fd, int argc, char *argv[])
 #define FORMAT "%-20.20s  %-10.10s  %-20.20s %8d  %s\n"
        struct iax2_registry *reg;
        char host[80];
-       char perceived[80] = "";
+       char perceived[80];
        char iabuf[INET_ADDRSTRLEN];
        if (argc != 3)
                return RESULT_SHOWUSAGE;
@@ -4353,7 +4418,7 @@ static int iax2_show_channels(int fd, int argc, char *argv[])
                }
                ast_mutex_unlock(&iaxsl[x]);
        }
-       ast_cli(fd, "%d active IAX channel(s)\n", numchans);
+       ast_cli(fd, "%d active IAX channel%s\n", numchans, (numchans != 1) ? "s" : "");
        return RESULT_SUCCESS;
 #undef FORMAT
 #undef FORMAT2
@@ -4448,7 +4513,16 @@ static int iax2_show_netstats(int fd, int argc, char *argv[])
        ast_cli(fd, "                                -------- LOCAL ---------------------  -------- REMOTE --------------------\n");
        ast_cli(fd, "Channel                    RTT  Jit  Del  Lost   %%  Drop  OOO  Kpkts  Jit  Del  Lost   %%  Drop  OOO  Kpkts\n");
        numchans = ast_cli_netstats(fd, 1);
-       ast_cli(fd, "%d active IAX channel(s)\n", numchans);
+       ast_cli(fd, "%d active IAX channel%s\n", numchans, (numchans != 1) ? "s" : "");
+       return RESULT_SUCCESS;
+}
+
+static int iax2_do_debug(int fd, int argc, char *argv[])
+{
+       if (argc != 2)
+               return RESULT_SHOWUSAGE;
+       iaxdebug = 1;
+       ast_cli(fd, "IAX2 Debugging Enabled\n");
        return RESULT_SUCCESS;
 }
 
@@ -4461,15 +4535,14 @@ static int iax2_do_trunk_debug(int fd, int argc, char *argv[])
        return RESULT_SUCCESS;
 }
 
-static int iax2_do_debug(int fd, int argc, char *argv[])
+static int iax2_do_jb_debug(int fd, int argc, char *argv[])
 {
-       if (argc != 2)
+       if (argc != 3)
                return RESULT_SHOWUSAGE;
-       iaxdebug = 1;
 #ifdef NEWJB
        jb_setoutput(jb_error_output, jb_warning_output, jb_debug_output);
 #endif
-       ast_cli(fd, "IAX2 Debugging Enabled\n");
+       ast_cli(fd, "IAX2 Jitterbuffer Debugging Enabled\n");
        return RESULT_SUCCESS;
 }
 
@@ -4478,14 +4551,30 @@ static int iax2_no_debug(int fd, int argc, char *argv[])
        if (argc != 3)
                return RESULT_SHOWUSAGE;
        iaxdebug = 0;
-#ifdef NEWJB
-       jb_setoutput(jb_error_output, jb_warning_output, NULL);
-#endif
        ast_cli(fd, "IAX2 Debugging Disabled\n");
        return RESULT_SUCCESS;
 }
 
+static int iax2_no_trunk_debug(int fd, int argc, char *argv[])
+{
+       if (argc != 4)
+               return RESULT_SHOWUSAGE;
+       iaxtrunkdebug = 0;
+       ast_cli(fd, "IAX2 Trunk Debugging Disabled\n");
+       return RESULT_SUCCESS;
+}
 
+static int iax2_no_jb_debug(int fd, int argc, char *argv[])
+{
+       if (argc != 4)
+               return RESULT_SHOWUSAGE;
+#ifdef NEWJB
+       jb_setoutput(jb_error_output, jb_warning_output, NULL);
+       jb_debug_output("\n");
+#endif
+       ast_cli(fd, "IAX2 Jitterbuffer Debugging Disabled\n");
+       return RESULT_SUCCESS;
+}
 
 static int iax2_write(struct ast_channel *c, struct ast_frame *f)
 {
@@ -4516,7 +4605,7 @@ static int iax2_write(struct ast_channel *c, struct ast_frame *f)
        return res;
 }
 
-static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const char *data, int datalen, int seqno, 
+static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno, 
                int now, int transfer, int final)
 {
        struct ast_frame f;
@@ -4531,12 +4620,12 @@ static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsig
        return iax2_send(i, &f, ts, seqno, now, transfer, final);
 }
 
-static int send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const char *data, int datalen, int seqno)
+static int send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
 {
        return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0);
 }
 
-static int send_command_locked(unsigned short callno, char type, int command, unsigned int ts, const char *data, int datalen, int seqno)
+static int send_command_locked(unsigned short callno, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
 {
        int res;
        ast_mutex_lock(&iaxsl[callno]);
@@ -4552,19 +4641,19 @@ static int forward_command(struct chan_iax2_pvt *i, char type, int command, unsi
 }
 #endif
 
-static int send_command_final(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const char *data, int datalen, int seqno)
+static int send_command_final(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
 {
        /* It is assumed that the callno has already been locked */
        iax2_predestroy_nolock(i->callno);
        return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1);
 }
 
-static int send_command_immediate(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const char *data, int datalen, int seqno)
+static int send_command_immediate(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
 {
        return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0);
 }
 
-static int send_command_transfer(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const char *data, int datalen)
+static int send_command_transfer(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen)
 {
        return __send_command(i, type, command, ts, data, datalen, 0, 0, 1, 0);
 }
@@ -4823,7 +4912,7 @@ static int authenticate_request(struct chan_iax2_pvt *p)
 
 static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
 {
-       char requeststr[256] = "";
+       char requeststr[256];
        char md5secret[256] = "";
        char secret[256] = "";
        char rsasecret[256] = "";
@@ -4841,7 +4930,7 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
        if ((p->authmethods & IAX_AUTH_RSA) && !ast_strlen_zero(rsasecret) && !ast_strlen_zero(p->inkeys)) {
                struct ast_key *key;
                char *keyn;
-               char tmpkey[256] = "";
+               char tmpkey[256];
                char *stringp=NULL;
                ast_copy_string(tmpkey, p->inkeys, sizeof(tmpkey));
                stringp=tmpkey;
@@ -4864,8 +4953,8 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
                stringp = tmppw;
                while((tmppw = strsep(&stringp, ";"))) {
                        MD5Init(&md5);
-                       MD5Update(&md5, p->challenge, strlen(p->challenge));
-                       MD5Update(&md5, tmppw, strlen(tmppw));
+                       MD5Update(&md5, (unsigned char *)p->challenge, strlen(p->challenge));
+                       MD5Update(&md5, (unsigned char *)tmppw, strlen(tmppw));
                        MD5Final(digest, &md5);
                        /* If they support md5, authenticate with it.  */
                        for (x=0;x<16;x++)
@@ -4945,7 +5034,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
        /* Check secret against what we have on file */
        if (!ast_strlen_zero(rsasecret) && (p->authmethods & IAX_AUTH_RSA) && !ast_strlen_zero(iaxs[callno]->challenge)) {
                if (!ast_strlen_zero(p->inkeys)) {
-                       char tmpkeys[256] = "";
+                       char tmpkeys[256];
                        char *stringp=NULL;
                        ast_copy_string(tmpkeys, p->inkeys, sizeof(tmpkeys));
                        stringp=tmpkeys;
@@ -4992,8 +5081,8 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
                stringp = tmppw;
                while((tmppw = strsep(&stringp, ";"))) {
                        MD5Init(&md5);
-                       MD5Update(&md5, iaxs[callno]->challenge, strlen(iaxs[callno]->challenge));
-                       MD5Update(&md5, tmppw, strlen(tmppw));
+                       MD5Update(&md5, (unsigned char *)iaxs[callno]->challenge, strlen(iaxs[callno]->challenge));
+                       MD5Update(&md5, (unsigned char *)tmppw, strlen(tmppw));
                        MD5Final(digest, &md5);
                        for (x=0;x<16;x++)
                                sprintf(requeststr + (x << 1), "%2.2x", digest[x]); /* safe */
@@ -5017,9 +5106,9 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
                return -1;
        }
        ast_copy_string(iaxs[callno]->peer, peer, sizeof(iaxs[callno]->peer));
-       /* Choose lowest expirey number */
-       if (expire && (expire < iaxs[callno]->expirey)) 
-               iaxs[callno]->expirey = expire;
+       /* Choose lowest expiry number */
+       if (expire && (expire < iaxs[callno]->expiry)) 
+               iaxs[callno]->expiry = expire;
 
        ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
 
@@ -5034,9 +5123,9 @@ static int authenticate(char *challenge, char *secret, char *keyn, int authmetho
        int res = -1;
        int x;
        char iabuf[INET_ADDRSTRLEN];
-       if (keyn && !ast_strlen_zero(keyn)) {
+       if (!ast_strlen_zero(keyn)) {
                if (!(authmethods & IAX_AUTH_RSA)) {
-                       if (!secret || ast_strlen_zero(secret)) 
+                       if (ast_strlen_zero(secret)) 
                                ast_log(LOG_NOTICE, "Asked to authenticate to %s with an RSA key, but they don't allow RSA authentication\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr));
                } else if (ast_strlen_zero(challenge)) {
                        ast_log(LOG_NOTICE, "No challenge provided for RSA authentication to %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr));
@@ -5058,14 +5147,14 @@ static int authenticate(char *challenge, char *secret, char *keyn, int authmetho
                }
        } 
        /* Fall back */
-       if (res && secret && !ast_strlen_zero(secret)) {
+       if (res && !ast_strlen_zero(secret)) {
                if ((authmethods & IAX_AUTH_MD5) && !ast_strlen_zero(challenge)) {
                        struct MD5Context md5;
                        unsigned char digest[16];
-                       char digres[128] = "";
+                       char digres[128];
                        MD5Init(&md5);
-                       MD5Update(&md5, challenge, strlen(challenge));
-                       MD5Update(&md5, secret, strlen(secret));
+                       MD5Update(&md5, (unsigned char *)challenge, strlen(challenge));
+                       MD5Update(&md5, (unsigned char *)secret, strlen(secret));
                        MD5Final(digest, &md5);
                        /* If they support md5, authenticate with it.  */
                        for (x=0;x<16;x++)
@@ -5105,7 +5194,7 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin,
                p->encmethods = 0;
 
        /* Check for override RSA authentication first */
-       if ((override && !ast_strlen_zero(override)) || (okey && !ast_strlen_zero(okey))) {
+       if (!ast_strlen_zero(override) || !ast_strlen_zero(okey)) {
                /* Normal password authentication */
                res = authenticate(p->challenge, override, okey, authmethods, &ied, sin, &p->ecx, &p->dcx);
        } else {
@@ -5126,6 +5215,15 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin,
                        peer = peer->next;
                }
                ast_mutex_unlock(&peerl.lock);
+               if (!peer) {
+                       /* We checked our list and didn't find one.  It's unlikely, but possible, 
+                          that we're trying to authenticate *to* a realtime peer */
+                       if ((peer = realtime_peer(p->peer, NULL))) {
+                               res = authenticate(p->challenge, peer->secret,peer->outkey, authmethods, &ied, sin, &p->ecx, &p->dcx);
+                               if (ast_test_flag(peer, IAX_TEMPONLY))
+                                       destroy_peer(peer);
+                       }
+               }
        }
        if (ies->encmethods)
                ast_set_flag(p, IAX_ENCRYPTED | IAX_KEYPOPULATED);
@@ -5147,7 +5245,7 @@ static int iax2_do_register_s(void *data)
 static int try_transfer(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
 {
        int newcall = 0;
-       char newip[256] = "";
+       char newip[256];
        struct iax_ie_data ied;
        struct sockaddr_in new;
        
@@ -5177,7 +5275,7 @@ static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
 {
        char exten[256] = "";
        int status = CACHE_FLAG_UNKNOWN;
-       int expirey = iaxdefaultdpcache;
+       int expiry = iaxdefaultdpcache;
        int x;
        int matchmore = 0;
        struct iax2_dpcache *dp, *prev;
@@ -5196,7 +5294,7 @@ static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
                /* Don't really do anything with this */
        }
        if (ies->refresh)
-               expirey = ies->refresh;
+               expiry = ies->refresh;
        if (ies->dpstatus & IAX_DPSTATUS_MATCHMORE)
                matchmore = CACHE_FLAG_MATCHMORE;
        ast_mutex_lock(&dpcache_lock);
@@ -5211,7 +5309,7 @@ static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
                                pvt->dpentries = dp->peer;
                        dp->peer = NULL;
                        dp->callno = 0;
-                       dp->expirey.tv_sec = dp->orig.tv_sec + expirey;
+                       dp->expiry.tv_sec = dp->orig.tv_sec + expiry;
                        if (dp->flags & CACHE_FLAG_PENDING) {
                                dp->flags &= ~CACHE_FLAG_PENDING;
                                dp->flags |= status;
@@ -5293,7 +5391,7 @@ static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int c
        struct iax2_registry *reg;
        /* Start pessimistic */
        char peer[256] = "";
-       char msgstatus[40] = "";
+       char msgstatus[40];
        int refresh = 0;
        char ourip[256] = "<Unspecified>";
        struct sockaddr_in oldus;
@@ -5313,7 +5411,7 @@ static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int c
        }
        reg = iaxs[callno]->reg;
        if (!reg) {
-               ast_log(LOG_WARNING, "Registry acknowledge on unknown registery '%s'\n", peer);
+               ast_log(LOG_WARNING, "Registry acknowledge on unknown registry '%s'\n", peer);
                return -1;
        }
        memcpy(&oldus, &reg->us, sizeof(oldus));
@@ -5324,13 +5422,13 @@ static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int c
        }
        memcpy(&reg->us, &us, sizeof(reg->us));
        reg->messages = ies->msgcount;
-       if (refresh && (reg->refresh > refresh)) {
-               /* Refresh faster if necessary */
-               reg->refresh = refresh;
-               if (reg->expire > -1)
-                       ast_sched_del(sched, reg->expire);
-               reg->expire = ast_sched_add(sched, (5 * reg->refresh / 6) * 1000, iax2_do_register_s, reg);
-       }
+       /* always refresh the registration at the interval requested by the server
+          we are registering to
+       */
+       reg->refresh = refresh;
+       if (reg->expire > -1)
+               ast_sched_del(sched, reg->expire);
+       reg->expire = ast_sched_add(sched, (5 * reg->refresh / 6) * 1000, iax2_do_register_s, reg);
        if ((inaddrcmp(&oldus, &reg->us) || (reg->messages != oldmsgs)) && (option_verbose > 2)) {
                if (reg->messages > 65534)
                        snprintf(msgstatus, sizeof(msgstatus), " with message(s) waiting\n");
@@ -5338,7 +5436,7 @@ static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int c
                        snprintf(msgstatus, sizeof(msgstatus), " with %d messages waiting\n", reg->messages);
                else if (reg->messages > 0)
                        snprintf(msgstatus, sizeof(msgstatus), " with 1 message waiting\n");
-               else if (reg->messages > -1)
+               else
                        snprintf(msgstatus, sizeof(msgstatus), " with no messages waiting\n");
                snprintf(ourip, sizeof(ourip), "%s:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), reg->us.sin_addr), ntohs(reg->us.sin_port));
                ast_verbose(VERBOSE_PREFIX_3 "Registered IAX2 to '%s', who sees us as %s%s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ourip, msgstatus);
@@ -5406,7 +5504,7 @@ static int iax2_register(char *value, int lineno)
 
 static void register_peer_exten(struct iax2_peer *peer, int onoff)
 {
-       unsigned char multi[256]="";
+       char multi[256];
        char *stringp, *ext;
        if (!ast_strlen_zero(regcontext)) {
                ast_copy_string(multi, ast_strlen_zero(peer->regexten) ? peer->name : peer->regexten, sizeof(multi));
@@ -5429,8 +5527,8 @@ static int expire_registry(void *data)
        memset(&p->addr, 0, sizeof(p->addr));
        /* Reset expire notice */
        p->expire = -1;
-       /* Reset expirey value */
-       p->expirey = expirey;
+       /* Reset expiry value */
+       p->expiry = min_reg_expire;
        if (!ast_test_flag(p, IAX_TEMPONLY))
                ast_db_del("IAX/Registry", p->name);
        register_peer_exten(p, 0);
@@ -5469,7 +5567,7 @@ static void reg_source_db(struct iax2_peer *p)
                                                ast_verbose(VERBOSE_PREFIX_3 "Seeding '%s' at %s:%d for %d\n", p->name, 
                                                ast_inet_ntoa(iabuf, sizeof(iabuf), in), atoi(c), atoi(d));
                                        iax2_poke_peer(p, 0);
-                                       p->expirey = atoi(d);
+                                       p->expiry = atoi(d);
                                        memset(&p->addr, 0, sizeof(p->addr));
                                        p->addr.sin_family = AF_INET;
                                        p->addr.sin_addr = in;
@@ -5477,7 +5575,7 @@ static void reg_source_db(struct iax2_peer *p)
                                        if (p->expire > -1)
                                                ast_sched_del(sched, p->expire);
                                        ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
-                                       p->expire = ast_sched_add(sched, (p->expirey + 10) * 1000, expire_registry, (void *)p);
+                                       p->expire = ast_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, (void *)p);
                                        if (iax2_regfunk)
                                                iax2_regfunk(p->name, 1);
                                        register_peer_exten(p, 1);
@@ -5488,7 +5586,7 @@ static void reg_source_db(struct iax2_peer *p)
        }
 }
 
-static int update_registry(char *name, struct sockaddr_in *sin, int callno, char *devtype, int fd)
+static int update_registry(char *name, struct sockaddr_in *sin, int callno, char *devtype, int fd, unsigned short refresh)
 {
        /* Called from IAX thread only, with proper iaxsl lock */
        struct iax_ie_data ied;
@@ -5497,79 +5595,92 @@ static int update_registry(char *name, struct sockaddr_in *sin, int callno, char
        char data[80];
        char iabuf[INET_ADDRSTRLEN];
        int version;
+
        memset(&ied, 0, sizeof(ied));
-       p = find_peer(name, 1);
-       if (p) {
-               if (!ast_test_flag((&globalflags), IAX_RTNOUPDATE) && (ast_test_flag(p, IAX_TEMPONLY|IAX_RTCACHEFRIENDS)))
-                       realtime_update_peer(name, sin);
-               if (inaddrcmp(&p->addr, sin)) {
-                       if (iax2_regfunk)
-                               iax2_regfunk(p->name, 1);
-                       snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port), p->expirey);
-                       if (!ast_test_flag(p, IAX_TEMPONLY) && sin->sin_addr.s_addr) {
-                               ast_db_put("IAX/Registry", p->name, data);
-                               if  (option_verbose > 2)
+
+       if (!(p = find_peer(name, 1))) {
+               ast_log(LOG_WARNING, "No such peer '%s'\n", name);
+               return -1;
+       }
+
+       if (ast_test_flag((&globalflags), IAX_RTUPDATE) && (ast_test_flag(p, IAX_TEMPONLY|IAX_RTCACHEFRIENDS)))
+               realtime_update_peer(name, sin);
+       if (inaddrcmp(&p->addr, sin)) {
+               if (iax2_regfunk)
+                       iax2_regfunk(p->name, 1);
+               snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port), p->expiry);
+               if (!ast_test_flag(p, IAX_TEMPONLY) && sin->sin_addr.s_addr) {
+                       ast_db_put("IAX/Registry", p->name, data);
+                       if  (option_verbose > 2)
                                ast_verbose(VERBOSE_PREFIX_3 "Registered IAX2 '%s' (%s) at %s:%d\n", p->name, 
-                                       iaxs[callno]->state & IAX_STATE_AUTHENTICATED ? "AUTHENTICATED" : "UNAUTHENTICATED", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
-                               manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Registered\r\n", p->name);
-                               ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
-                               register_peer_exten(p, 1);
-                       } else if (!ast_test_flag(p, IAX_TEMPONLY)) {
-                               if  (option_verbose > 2)
+                                           iaxs[callno]->state & IAX_STATE_AUTHENTICATED ? "AUTHENTICATED" : "UNAUTHENTICATED", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
+                       manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Registered\r\n", p->name);
+                       ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
+                       register_peer_exten(p, 1);
+               } else if (!ast_test_flag(p, IAX_TEMPONLY)) {
+                       if  (option_verbose > 2)
                                ast_verbose(VERBOSE_PREFIX_3 "Unregistered IAX2 '%s' (%s)\n", p->name, 
-                                       iaxs[callno]->state & IAX_STATE_AUTHENTICATED ? "AUTHENTICATED" : "UNAUTHENTICATED");
-                               manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Unregistered\r\n", p->name);
-                               ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
-                               register_peer_exten(p, 0);
-                               ast_db_del("IAX/Registry", p->name);
-                       }
-                       /* Update the host */
-                       memcpy(&p->addr, sin, sizeof(p->addr));
-                       /* Verify that the host is really there */
-                       iax2_poke_peer(p, callno);
-               }               
-               /* Store socket fd */
-               p->sockfd = fd;
-               /* Setup the expirey */
-               if (p->expire > -1)
-                       ast_sched_del(sched, p->expire);
-               if (p->expirey && sin->sin_addr.s_addr)
-                       p->expire = ast_sched_add(sched, (p->expirey + 10) * 1000, expire_registry, (void *)p);
-               iax_ie_append_str(&ied, IAX_IE_USERNAME, p->name);
-               iax_ie_append_int(&ied, IAX_IE_DATETIME, iax2_datetime(p->zonetag));
-               if (sin->sin_addr.s_addr) {
-                       iax_ie_append_short(&ied, IAX_IE_REFRESH, p->expirey);
-                       iax_ie_append_addr(&ied, IAX_IE_APPARENT_ADDR, &p->addr);
-                       if (!ast_strlen_zero(p->mailbox)) {
-                               if (ast_test_flag(p, IAX_MESSAGEDETAIL)) {
-                                       int new, old;
-                                       ast_app_messagecount(p->mailbox, &new, &old);
-                                       if (new > 255)
-                                               new = 255;
-                                       if (old > 255)
-                                               old = 255;
-                                       msgcount = (old << 8) | new;
-                               } else {
-                                       msgcount = ast_app_has_voicemail(p->mailbox, NULL);
-                                       if (msgcount)
-                                               msgcount = 65535;
-                               }
-                               iax_ie_append_short(&ied, IAX_IE_MSGCOUNT, msgcount);
-                       }
-                       if (ast_test_flag(p, IAX_HASCALLERID)) {
-                               iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, p->cid_num);
-                               iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, p->cid_name);
+                                           iaxs[callno]->state & IAX_STATE_AUTHENTICATED ? "AUTHENTICATED" : "UNAUTHENTICATED");
+                       manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Unregistered\r\n", p->name);
+                       ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
+                       register_peer_exten(p, 0);
+                       ast_db_del("IAX/Registry", p->name);
+               }
+               /* Update the host */
+               memcpy(&p->addr, sin, sizeof(p->addr));
+               /* Verify that the host is really there */
+               iax2_poke_peer(p, callno);
+       }               
+       /* Store socket fd */
+       p->sockfd = fd;
+       /* Setup the expiry */
+       if (p->expire > -1)
+               ast_sched_del(sched, p->expire);
+       if (refresh > max_reg_expire) {
+               ast_log(LOG_NOTICE, "Restricting registration for peer '%s' to %d seconds (requested %d)\n",
+                       p->name, max_reg_expire, refresh);
+               p->expiry = max_reg_expire;
+       } else if (refresh < min_reg_expire) {
+               ast_log(LOG_NOTICE, "Restricting registration for peer '%s' to %d seconds (requested %d)\n",
+                       p->name, min_reg_expire, refresh);
+               p->expiry = min_reg_expire;
+       } else {
+               p->expiry = refresh;
+       }
+       if (p->expiry && sin->sin_addr.s_addr)
+               p->expire = ast_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, (void *)p);
+       iax_ie_append_str(&ied, IAX_IE_USERNAME, p->name);
+       iax_ie_append_int(&ied, IAX_IE_DATETIME, iax2_datetime(p->zonetag));
+       if (sin->sin_addr.s_addr) {
+               iax_ie_append_short(&ied, IAX_IE_REFRESH, p->expiry);
+               iax_ie_append_addr(&ied, IAX_IE_APPARENT_ADDR, &p->addr);
+               if (!ast_strlen_zero(p->mailbox)) {
+                       if (ast_test_flag(p, IAX_MESSAGEDETAIL)) {
+                               int new, old;
+                               ast_app_messagecount(p->mailbox, &new, &old);
+                               if (new > 255)
+                                       new = 255;
+                               if (old > 255)
+                                       old = 255;
+                               msgcount = (old << 8) | new;
+                       } else {
+                               msgcount = ast_app_has_voicemail(p->mailbox, NULL);
+                               if (msgcount)
+                                       msgcount = 65535;
                        }
+                       iax_ie_append_short(&ied, IAX_IE_MSGCOUNT, msgcount);
+               }
+               if (ast_test_flag(p, IAX_HASCALLERID)) {
+                       iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, p->cid_num);
+                       iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, p->cid_name);
                }
-               version = iax_check_version(devtype);
-               if (version) 
-                       iax_ie_append_short(&ied, IAX_IE_FIRMWAREVER, version);
-               if (ast_test_flag(p, IAX_TEMPONLY))
-                       destroy_peer(p);
-               return send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, ied.buf, ied.pos, -1);
        }
-       ast_log(LOG_WARNING, "No such peer '%s'\n", name);
-       return -1;
+       version = iax_check_version(devtype);
+       if (version) 
+               iax_ie_append_short(&ied, IAX_IE_FIRMWAREVER, version);
+       if (ast_test_flag(p, IAX_TEMPONLY))
+               destroy_peer(p);
+       return send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, ied.buf, ied.pos, -1);
 }
 
 static int registry_authrequest(char *name, int callno)
@@ -5783,7 +5894,7 @@ static int send_trunk(struct iax2_trunk_peer *tpeer, struct timeval *now)
                /* We're actually sending a frame, so fill the meta trunk header and meta header */
                meta->zeros = 0;
                meta->metacmd = IAX_META_TRUNK;
-               if(send_trunktimestamps)
+               if (ast_test_flag(&globalflags, IAX_TRUNKTIMESTAMPS))
                        meta->cmddata = IAX_META_TRUNK_MINI;
                else
                        meta->cmddata = IAX_META_TRUNK_SUPERMINI;
@@ -5868,7 +5979,7 @@ static int timing_read(int *id, int fd, short events, void *cbdata)
                } else {
                        res = send_trunk(tpeer, &now);
                        if (iaxtrunkdebug)
-                               ast_verbose(" - Trunk peer (%s:%d) has %d call chunk(s) in transit, %d bytes backloged and has hit a high water mark of %d bytes\n", ast_inet_ntoa(iabuf, sizeof(iabuf), tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port), res, tpeer->trunkdatalen, tpeer->trunkdataalloc);
+                               ast_verbose(" - Trunk peer (%s:%d) has %d call chunk%s in transit, %d bytes backloged and has hit a high water mark of %d bytes\n", ast_inet_ntoa(iabuf, sizeof(iabuf), tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port), res, (res != 1) ? "s" : "", tpeer->trunkdatalen, tpeer->trunkdataalloc);
                }               
                totalcalls += res;      
                res = 0;
@@ -5984,7 +6095,7 @@ static void *iax_park_thread(void *stuff)
                ast_frfree(f);
        res = ast_park_call(chan1, chan2, 0, &ext);
        ast_hangup(chan2);
-       ast_log(LOG_DEBUG, "Parked on extension '%d'\n", ext);
+       ast_log(LOG_NOTICE, "Parked on extension '%d'\n", ext);
        return NULL;
 }
 
@@ -6042,19 +6153,19 @@ static int iax_park(struct ast_channel *chan1, struct ast_channel *chan2)
 }
 
 
-static int iax2_provision(struct sockaddr_in *end, char *dest, const char *template, int force);
+static int iax2_provision(struct sockaddr_in *end, int sockfd, char *dest, const char *template, int force);
 
-static int check_provisioning(struct sockaddr_in *sin, char *si, unsigned int ver)
+static int check_provisioning(struct sockaddr_in *sin, int sockfd, char *si, unsigned int ver)
 {
        unsigned int ourver;
-       unsigned char rsi[80];
+       char rsi[80];
        snprintf(rsi, sizeof(rsi), "si-%s", si);
        if (iax_provision_version(&ourver, rsi, 1))
                return 0;
        if (option_debug)
                ast_log(LOG_DEBUG, "Service identifier '%s', we think '%08x', they think '%08x'\n", si, ourver, ver);
        if (ourver != ver) 
-               iax2_provision(sin, NULL, rsi, 1);
+               iax2_provision(sin, sockfd, NULL, rsi, 1);
        return 0;
 }
 
@@ -6104,7 +6215,8 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
        int res;
        int updatehistory=1;
        int new = NEW_PREVENT;
-       char buf[4096], *ptr;
+       unsigned char buf[4096]; 
+       void *ptr;
        socklen_t len = sizeof(sin);
        int dcallno = 0;
        struct ast_iax2_full_hdr *fh = (struct ast_iax2_full_hdr *)buf;
@@ -6179,11 +6291,9 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                                ast_log(LOG_WARNING, "Unable to accept trunked packet from '%s:%d': No matching peer\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
                                return 1;
                        }
-                       if (!ts || (!tpeer->rxtrunktime.tv_sec && !tpeer->rxtrunktime.tv_usec)) {
-                               gettimeofday(&tpeer->rxtrunktime, NULL);
-                               tpeer->trunkact = tpeer->rxtrunktime;
-                       } else
-                               gettimeofday(&tpeer->trunkact, NULL);
+                       tpeer->trunkact = ast_tvnow();
+                       if (!ts || ast_tvzero(tpeer->rxtrunktime))
+                               tpeer->rxtrunktime = tpeer->trunkact;
                        rxtrunktime = tpeer->rxtrunktime;
                        ast_mutex_unlock(&tpeer->lock);
                        while(res >= sizeof(struct ast_iax2_meta_trunk_entry)) {
@@ -6248,13 +6358,17 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                                                                                forward_delivery(&fr);
                                                                        } else {
                                                                                duped_fr = iaxfrdup2(&fr);
-                                                                               schedule_delivery(duped_fr, 1, updatehistory, 1);
-                                                                               fr.ts = duped_fr->ts;
+                                                                               if (duped_fr) {
+                                                                                       schedule_delivery(duped_fr, updatehistory, 1);
+                                                                                       fr.ts = duped_fr->ts;
+                                                                               }
                                                                        }
 #else
                                                                        duped_fr = iaxfrdup2(&fr);
-                                                                       schedule_delivery(duped_fr, 1, updatehistory, 1);
-                                                                       fr.ts = duped_fr->ts;
+                                                                       if (duped_fr) {
+                                                                               schedule_delivery(duped_fr, updatehistory, 1);
+                                                                               fr.ts = duped_fr->ts;
+                                                                       }
 #endif
                                                                        if (iaxs[fr.callno]->last < fr.ts) {
                                                                                iaxs[fr.callno]->last = fr.ts;
@@ -6295,8 +6409,9 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                } else {
                        f.subclass = uncompress_subclass(fh->csub);
                }
-               if ((f.frametype == AST_FRAME_IAX) && ((f.subclass == IAX_COMMAND_NEW) || (f.subclass == IAX_COMMAND_REGREQ)
-                               || (f.subclass == IAX_COMMAND_POKE) || (f.subclass == IAX_COMMAND_FWDOWNL)))
+               if ((f.frametype == AST_FRAME_IAX) && ((f.subclass == IAX_COMMAND_NEW) || (f.subclass == IAX_COMMAND_REGREQ) ||
+                                                      (f.subclass == IAX_COMMAND_POKE) || (f.subclass == IAX_COMMAND_FWDOWNL) ||
+                                                      (f.subclass == IAX_COMMAND_REGREL)))
                        new = NEW_ALLOW;
        } else {
                /* Don't know anything about it yet */
@@ -6335,7 +6450,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                }
 #ifdef DEBUG_SUPPORT
                else if (iaxdebug)
-                       iax_showframe(NULL, fh, 1, &sin, res - sizeof(struct ast_iax2_full_hdr));
+                       iax_showframe(NULL, fh, 3, &sin, res - sizeof(struct ast_iax2_full_hdr));
 #endif
        }
 
@@ -6347,7 +6462,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                f.subclass != IAX_COMMAND_TXACC)                /* for attended transfer */
                iaxs[fr.callno]->peercallno = (unsigned short)(ntohs(mh->callno) & ~IAX_FLAG_FULL);
        if (ntohs(mh->callno) & IAX_FLAG_FULL) {
-               if (option_debug)
+               if (option_debug  && iaxdebug)
                        ast_log(LOG_DEBUG, "Received packet %d, (%d, %d)\n", fh->oseqno, f.frametype, f.subclass);
                /* Check if it's out of order (and not an ACK or INVAL) */
                fr.oseqno = fh->oseqno;
@@ -6444,7 +6559,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                                   that it says to */
                                for (x=iaxs[fr.callno]->rseqno; x != fr.iseqno; x++) {
                                        /* Ack the packet with the given timestamp */
-                                       if (option_debug)
+                                       if (option_debug && iaxdebug)
                                                ast_log(LOG_DEBUG, "Cancelling transmission of packet %d\n", x);
                                        ast_mutex_lock(&iaxq.lock);
                                        for (cur = iaxq.head; cur ; cur = cur->next) {
@@ -6453,7 +6568,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                                                        cur->retries = -1;
                                                        /* Destroy call if this is the end */
                                                        if (cur->final) { 
-                                                               if (option_debug)
+                                                               if (iaxdebug && option_debug)
                                                                        ast_log(LOG_DEBUG, "Really destroying %d, having been acked on final message\n", fr.callno);
                                                                iax2_destroy_nolock(fr.callno);
                                                        }
@@ -6541,7 +6656,7 @@ retryowner:
                                iaxs[fr.callno]->initid = -1;
                        }
                        /* Handle the IAX pseudo frame itself */
-                       if (option_debug)
+                       if (option_debug && iaxdebug)
                                ast_log(LOG_DEBUG, "IAX subclass %d received\n", f.subclass);
 
                         /* Update last ts unless the frame's timestamp originated with us. */
@@ -6550,7 +6665,7 @@ retryowner:
                             f.subclass != IAX_COMMAND_PONG &&
                             f.subclass != IAX_COMMAND_LAGRP) {
                                iaxs[fr.callno]->last = fr.ts;
-                               if (option_debug)
+                               if (option_debug && iaxdebug)
                                        ast_log(LOG_DEBUG, "For call=%d, set last=%d\n", fr.callno, fr.ts);
                        }
 
@@ -6560,6 +6675,15 @@ retryowner:
                                break;
                        case IAX_COMMAND_QUELCH:
                                if (iaxs[fr.callno]->state & IAX_STATE_STARTED) {
+                                       /* Generate Manager Hold event, if necessary*/
+                                       if (iaxs[fr.callno]->owner) {
+                                               manager_event(EVENT_FLAG_CALL, "Hold",
+                                                       "Channel: %s\r\n"
+                                                       "Uniqueid: %s\r\n",
+                                                       iaxs[fr.callno]->owner->name, 
+                                                       iaxs[fr.callno]->owner->uniqueid);
+                                       }
+
                                        ast_set_flag(iaxs[fr.callno], IAX_QUELCH);
                                        if (ies.musiconhold) {
                                                if (iaxs[fr.callno]->owner &&
@@ -6568,8 +6692,17 @@ retryowner:
                                        }
                                }
                                break;
-                       case IAX_COMMAND_UNQUELCH:
+                       case IAX_COMMAND_UNQUELCH:                       
                                if (iaxs[fr.callno]->state & IAX_STATE_STARTED) {
+                                       /* Generate Manager Unhold event, if necessary*/
+                                       if (iaxs[fr.callno]->owner && ast_test_flag(iaxs[fr.callno], IAX_QUELCH)) {
+                                               manager_event(EVENT_FLAG_CALL, "Unhold",
+                                                       "Channel: %s\r\n"
+                                                       "Uniqueid: %s\r\n",
+                                                       iaxs[fr.callno]->owner->name, 
+                                                       iaxs[fr.callno]->owner->uniqueid);
+                                       }
+
                                        ast_clear_flag(iaxs[fr.callno], IAX_QUELCH);
                                        if (iaxs[fr.callno]->owner &&
                                                ast_bridged_channel(iaxs[fr.callno]->owner))
@@ -6597,7 +6730,7 @@ retryowner:
                                if (iaxs[fr.callno]->state & (IAX_STATE_STARTED | IAX_STATE_TBD))
                                        break;
                                if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr)
-                                       check_provisioning(&sin, ies.serviceident, ies.provver);
+                                       check_provisioning(&sin, fd, ies.serviceident, ies.provver);
                                /* For security, always ack immediately */
                                if (delayreject)
                                        send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr.ts, NULL, 0,fr.iseqno);
@@ -6930,13 +7063,13 @@ retryowner2:
 
                                if (iaxs[fr.callno]->peerpoke) {
                                        peer = iaxs[fr.callno]->peerpoke;
-                                       if ((peer->lastms < 0)  || (peer->lastms > peer->maxms)) {
+                                       if ((peer->lastms < 0)  || (peer->historicms > peer->maxms)) {
                                                if (iaxs[fr.callno]->pingtime <= peer->maxms) {
                                                        ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE! Time: %d\n", peer->name, iaxs[fr.callno]->pingtime);
                                                        manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Reachable\r\nTime: %d\r\n", peer->name, iaxs[fr.callno]->pingtime); 
                                                        ast_device_state_changed("IAX2/%s", peer->name); /* Activate notification */
                                                }
-                                       } else if ((peer->lastms > 0) && (peer->lastms <= peer->maxms)) {
+                                       } else if ((peer->historicms > 0) && (peer->historicms <= peer->maxms)) {
                                                if (iaxs[fr.callno]->pingtime > peer->maxms) {
                                                        ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED (%d ms)!\n", peer->name, iaxs[fr.callno]->pingtime);
                                                        manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Lagged\r\nTime: %d\r\n", peer->name, iaxs[fr.callno]->pingtime); 
@@ -6944,16 +7077,24 @@ retryowner2:
                                                }
                                        }
                                        peer->lastms = iaxs[fr.callno]->pingtime;
+                                       if (peer->smoothing && (peer->lastms > -1))
+                                               peer->historicms = (iaxs[fr.callno]->pingtime + peer->historicms) / 2;
+                                       else if (peer->smoothing && peer->lastms < 0)
+                                               peer->historicms = (0 + peer->historicms) / 2;
+                                       else                                    
+                                               peer->historicms = iaxs[fr.callno]->pingtime;
+
                                        if (peer->pokeexpire > -1)
                                                ast_sched_del(sched, peer->pokeexpire);
                                        send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr.ts, NULL, 0,fr.iseqno);
                                        iax2_destroy_nolock(fr.callno);
                                        peer->callno = 0;
                                        /* Try again eventually */
-                                       if ((peer->lastms < 0)  || (peer->lastms > peer->maxms))
-                                               peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_NOTOK, iax2_poke_peer_s, peer);
+                                               ast_log(LOG_DEBUG, "Peer lastms %d, historicms %d, maxms %d\n", peer->lastms, peer->historicms, peer->maxms);
+                                       if ((peer->lastms < 0)  || (peer->historicms > peer->maxms)) 
+                                               peer->pokeexpire = ast_sched_add(sched, peer->pokefreqnotok, iax2_poke_peer_s, peer);
                                        else
-                                               peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_OK, iax2_poke_peer_s, peer);
+                                               peer->pokeexpire = ast_sched_add(sched, peer->pokefreqok, iax2_poke_peer_s, peer);
                                }
                                break;
                        case IAX_COMMAND_LAGRQ:
@@ -6978,7 +7119,7 @@ retryowner2:
                                            /* This is a reply we've been given, actually measure the difference */
                                            ts = calc_timestamp(iaxs[fr.callno], 0, &fr.af);
                                            iaxs[fr.callno]->lag = ts - fr.ts;
-                                           if (option_debug)
+                                           if (option_debug && iaxdebug)
                                                ast_log(LOG_DEBUG, "Peer %s lag measured as %dms\n",
                                                                ast_inet_ntoa(iabuf, sizeof(iabuf), iaxs[fr.callno]->addr.sin_addr), iaxs[fr.callno]->lag);
                                        }
@@ -7199,10 +7340,10 @@ retryowner2:
                                if ((ast_strlen_zero(iaxs[fr.callno]->secret) && ast_strlen_zero(iaxs[fr.callno]->inkeys)) || (iaxs[fr.callno]->state & IAX_STATE_AUTHENTICATED)) {
                                        if (f.subclass == IAX_COMMAND_REGREL)
                                                memset(&sin, 0, sizeof(sin));
-                                       if (update_registry(iaxs[fr.callno]->peer, &sin, fr.callno, ies.devicetype, fd))
+                                       if (update_registry(iaxs[fr.callno]->peer, &sin, fr.callno, ies.devicetype, fd, ies.refresh))
                                                ast_log(LOG_WARNING, "Registry error\n");
                                        if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr)
-                                               check_provisioning(&sin, ies.serviceident, ies.provver);
+                                               check_provisioning(&sin, fd, ies.serviceident, ies.provver);
                                        break;
                                }
                                registry_authrequest(iaxs[fr.callno]->peer, fr.callno);
@@ -7301,7 +7442,7 @@ retryowner2:
                        case IAX_COMMAND_FWDOWNL:
                                /* Firmware download */
                                memset(&ied0, 0, sizeof(ied0));
-                               res = iax_firmware_append(&ied0, ies.devicetype, ies.fwdesc);
+                               res = iax_firmware_append(&ied0, (unsigned char *)ies.devicetype, ies.fwdesc);
                                if (res < 0)
                                        send_command_final(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
                                else if (res > 0)
@@ -7403,7 +7544,7 @@ retryowner2:
                /*iaxs[fr.callno]->last = fr.ts; (do it afterwards cos schedule/forward_delivery needs the last ts too)*/
                fr.outoforder = 0;
        } else {
-               if (option_debug)
+               if (option_debug && iaxdebug)
                        ast_log(LOG_DEBUG, "Received out of order packet... (type=%d, subclass %d, ts = %d, last = %d)\n", f.frametype, f.subclass, fr.ts, iaxs[fr.callno]->last);
                fr.outoforder = -1;
        }
@@ -7412,19 +7553,23 @@ retryowner2:
                forward_delivery(&fr);
        } else {
                duped_fr = iaxfrdup2(&fr);
-               schedule_delivery(duped_fr, 1, updatehistory, 0);
-               fr.ts = duped_fr->ts;
+               if (duped_fr) {
+                       schedule_delivery(duped_fr, updatehistory, 0);
+                       fr.ts = duped_fr->ts;
+               }
        }
 #else
        duped_fr = iaxfrdup2(&fr);
-       schedule_delivery(duped_fr, 1, updatehistory, 0);
-       fr.ts = duped_fr->ts;
+       if (duped_fr) {
+               schedule_delivery(duped_fr, updatehistory, 0);
+               fr.ts = duped_fr->ts;
+       }
 #endif
 
        if (iaxs[fr.callno]->last < fr.ts) {
                iaxs[fr.callno]->last = fr.ts;
 #if 1
-               if (option_debug)
+               if (option_debug && iaxdebug)
                        ast_log(LOG_DEBUG, "For call=%d, set last=%d\n", fr.callno, fr.ts);
 #endif
        }
@@ -7437,7 +7582,7 @@ retryowner2:
 static int iax2_do_register(struct iax2_registry *reg)
 {
        struct iax_ie_data ied;
-       if (option_debug)
+       if (option_debug && iaxdebug)
                ast_log(LOG_DEBUG, "Sending registration request for '%s'\n", reg->username);
        if (!reg->callno) {
                if (option_debug)
@@ -7471,7 +7616,7 @@ static char *iax2_prov_complete_template_3rd(char *line, char *word, int pos, in
        return iax_prov_complete_template(line, word, pos, state);
 }
 
-static int iax2_provision(struct sockaddr_in *end, char *dest, const char *template, int force)
+static int iax2_provision(struct sockaddr_in *end, int sockfd, char *dest, const char *template, int force)
 {
        /* Returns 1 if provisioned, -1 if not able to find destination, or 0 if no provisioning
           is found for template */
@@ -7492,9 +7637,10 @@ static int iax2_provision(struct sockaddr_in *end, char *dest, const char *templ
                return 0;
        }
 
-       if (end)
+       if (end) {
                memcpy(&sin, end, sizeof(sin));
-       else if (create_addr(dest, &sin, &cai))
+               cai.sockfd = sockfd;
+       } else if (create_addr(dest, &sin, &cai))
                return -1;
 
        /* Build the rest of the message */
@@ -7535,7 +7681,7 @@ static int iax2_prov_app(struct ast_channel *chan, void *data)
        int force =0;
        unsigned short callno = PTR_TO_CALLNO(chan->tech_pvt);
        char iabuf[INET_ADDRSTRLEN];
-       if (!data || ast_strlen_zero(data))
+       if (ast_strlen_zero(data))
                data = "default";
        sdata = ast_strdupa(data);
        opts = strchr(sdata, '|');
@@ -7550,7 +7696,7 @@ static int iax2_prov_app(struct ast_channel *chan, void *data)
                ast_log(LOG_NOTICE, "Can't provision something with no IP?\n");
                return -1;
        }
-       res = iax2_provision(&iaxs[callno]->addr, NULL, sdata, force);
+       res = iax2_provision(&iaxs[callno]->addr, iaxs[callno]->sockfd, NULL, sdata, force);
        if (option_verbose > 2)
                ast_verbose(VERBOSE_PREFIX_3 "Provisioned IAXY at '%s' with '%s'= %d\n", 
                ast_inet_ntoa(iabuf, sizeof(iabuf), iaxs[callno]->addr.sin_addr),
@@ -7571,7 +7717,7 @@ static int iax2_prov_cmd(int fd, int argc, char *argv[])
                else
                        return RESULT_SHOWUSAGE;
        }
-       res = iax2_provision(NULL, argv[2], argv[3], force);
+       res = iax2_provision(NULL, -1, argv[2], argv[3], force);
        if (res < 0)
                ast_cli(fd, "Unable to find peer/address '%s'\n", argv[2]);
        else if (res < 1)
@@ -7595,7 +7741,7 @@ static int iax2_poke_noanswer(void *data)
        peer->callno = 0;
        peer->lastms = -1;
        /* Try again quickly */
-       peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_NOTOK, iax2_poke_peer_s, peer);
+       peer->pokeexpire = ast_sched_add(sched, peer->pokefreqnotok, iax2_poke_peer_s, peer);
        return 0;
 }
 
@@ -7605,6 +7751,7 @@ static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
                /* IF we have no IP, or this isn't to be monitored, return
                  imeediately after clearing things out */
                peer->lastms = 0;
+               peer->historicms = 0;
                peer->pokeexpire = -1;
                peer->callno = 0;
                return 0;
@@ -7628,7 +7775,13 @@ static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
        iaxs[peer->callno]->pingtime = peer->maxms / 4 + 1;
        iaxs[peer->callno]->peerpoke = peer;
        send_command(iaxs[peer->callno], AST_FRAME_IAX, IAX_COMMAND_POKE, 0, NULL, 0, -1);
-       peer->pokeexpire = ast_sched_add(sched, DEFAULT_MAXMS * 2, iax2_poke_noanswer, peer);
+       
+       /* If the host is already unreachable then use the unreachable interval instead */
+       if (peer->lastms < 0) {
+               peer->pokeexpire = ast_sched_add(sched, peer->pokefreqnotok, iax2_poke_noanswer, peer);
+       } else
+               peer->pokeexpire = ast_sched_add(sched, DEFAULT_MAXMS * 2, iax2_poke_noanswer, peer);
+
        return 0;
 }
 
@@ -7649,7 +7802,6 @@ static struct ast_channel *iax2_request(const char *type, int format, void *data
        int fmt, native;
        struct sockaddr_in sin;
        struct ast_channel *c;
-       int capability = iax2_capability;
        struct parsed_dial_string pds;
        struct create_addr_info cai;
        char *tmpstr;
@@ -7659,9 +7811,16 @@ static struct ast_channel *iax2_request(const char *type, int format, void *data
        parse_dial_string(tmpstr, &pds);
 
        memset(&cai, 0, sizeof(cai));
+       cai.capability = iax2_capability;
 
        ast_copy_flags(&cai, &globalflags, IAX_NOTRANSFER | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
 
+       if (!pds.peer) {
+               ast_log(LOG_WARNING, "No peer given\n");
+               return NULL;
+       }
+              
+       
        /* Populate our address from the given */
        if (create_addr(pds.peer, &sin, &cai)) {
                *cause = AST_CAUSE_UNREGISTERED;
@@ -7688,7 +7847,7 @@ static struct ast_channel *iax2_request(const char *type, int format, void *data
        if (cai.found)
                ast_copy_string(iaxs[callno]->host, pds.peer, sizeof(iaxs[callno]->host));
 
-       c = ast_iax2_new(callno, AST_STATE_DOWN, capability);
+       c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability);
 
        ast_mutex_unlock(&iaxsl[callno]);
 
@@ -7799,6 +7958,92 @@ static int get_auth_methods(char *value)
 }
 
 
+/*--- check_src_ip: Check if address can be used as packet source.
+ returns:
+ 0  address available
+ 1  address unavailable
+-1  error
+*/
+static int check_srcaddr(struct sockaddr *sa, socklen_t salen)
+{
+       int sd;
+       int res;
+       
+       sd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sd < 0) {
+               ast_log(LOG_ERROR, "Socket: %s\n", strerror(errno));
+               return -1;
+       }
+
+       res = bind(sd, sa, salen);
+       if (res < 0) {
+               ast_log(LOG_DEBUG, "Can't bind: %s\n", strerror(errno));
+               close(sd);
+               return 1;
+       }
+
+       close(sd);
+       return 0;
+}
+
+/*--- peer_set_srcaddr: Parse the "sourceaddress" value,
+  lookup in netsock list and set peer's sockfd. Defaults to defaultsockfd if
+  not found. */
+static int peer_set_srcaddr(struct iax2_peer *peer, const char *srcaddr)
+{
+       struct sockaddr_in sin;
+       int nonlocal = 1;
+       int port = IAX_DEFAULT_PORTNO;
+       int sockfd = defaultsockfd;
+       char *tmp;
+       char *addr;
+       char *portstr;
+
+       tmp = ast_strdupa(srcaddr);
+       if (!tmp) {
+               ast_log(LOG_WARNING, "Out of memory!\n");
+               return -1;
+       }
+
+       addr = strsep(&tmp, ":");
+       portstr = tmp;
+
+       if (portstr) {
+               port = atoi(portstr);
+               if (port < 1)
+                       port = IAX_DEFAULT_PORTNO;
+       }
+       
+       if (!ast_get_ip(&sin, addr)) {
+               struct ast_netsock *sock;
+               int res;
+
+               sin.sin_port = 0;
+               res = check_srcaddr((struct sockaddr *) &sin, sizeof(sin));
+               if (res == 0) {
+                       /* ip address valid. */
+                       sin.sin_port = htons(port);
+                       sock = ast_netsock_find(netsock, &sin);
+                       if (sock) {
+                               sockfd = ast_netsock_sockfd(sock);
+                               nonlocal = 0;
+                       }
+               }
+       }
+               
+       peer->sockfd = sockfd;
+
+       if (nonlocal) {
+               ast_log(LOG_WARNING, "Non-local or unbound address specified (%s) in sourceaddress for '%s', reverting to default\n",
+                       srcaddr, peer->name);
+               return -1;
+       } else {
+               ast_log(LOG_DEBUG, "Using sourceaddress %s for '%s'\n", srcaddr, peer->name);
+               return 0;
+       }
+}
+
+               
 /*--- build_peer: Create peer structure based on configuration */
 static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, int temponly)
 {
@@ -7842,16 +8087,19 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
                }
        }
        if (peer) {
-               ast_copy_flags(peer, (&globalflags), IAX_MESSAGEDETAIL | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);        
+               ast_copy_flags(peer, &globalflags, IAX_MESSAGEDETAIL | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
                peer->encmethods = iax2_encryption;
                peer->secret[0] = '\0';
                if (!found) {
                        ast_copy_string(peer->name, name, sizeof(peer->name));
                        peer->addr.sin_port = htons(IAX_DEFAULT_PORTNO);
-                       peer->expirey = expirey;
+                       peer->expiry = min_reg_expire;
                }
                peer->prefs = prefs;
                peer->capability = iax2_capability;
+               peer->smoothing = 0;
+               peer->pokefreqok = DEFAULT_FREQ_OK;
+               peer->pokefreqnotok = DEFAULT_FREQ_NOTOK;
                while(v) {
                        if (!strcasecmp(v->name, "secret")) {
                                if (!ast_strlen_zero(peer->secret)) {
@@ -7861,13 +8109,11 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
                                        ast_copy_string(peer->secret, v->value, sizeof(peer->secret));
                        } else if (!strcasecmp(v->name, "mailbox")) {
                                ast_copy_string(peer->mailbox, v->value, sizeof(peer->mailbox));
-                       } else if (!strcasecmp(v->name, "dbsecret")) 
+                       } else if (!strcasecmp(v->name, "dbsecret")) {
                                ast_copy_string(peer->dbsecret, v->value, sizeof(peer->dbsecret));
-                       else if (!strcasecmp(v->name, "mailboxdetail"))
+                       } else if (!strcasecmp(v->name, "mailboxdetail")) {
                                ast_set2_flag(peer, ast_true(v->value), IAX_MESSAGEDETAIL);     
-                       else if (!strcasecmp(v->name, "trunktimestamps"))
-                               send_trunktimestamps = ast_true(v->value);
-                       else if (!strcasecmp(v->name, "trunk")) {
+                       } else if (!strcasecmp(v->name, "trunk")) {
                                ast_set2_flag(peer, ast_true(v->value), IAX_TRUNK);     
                                if (ast_test_flag(peer, IAX_TRUNK) && (timingfd < 0)) {
                                        ast_log(LOG_WARNING, "Unable to support trunking on peer '%s' without zaptel timing\n", peer->name);
@@ -7915,6 +8161,8 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
                                        free(peer);
                                        return NULL;
                                }
+                       } else if (!strcasecmp(v->name, "sourceaddress")) {
+                               peer_set_srcaddr(peer, v->value);
                        } else if (!strcasecmp(v->name, "permit") ||
                                           !strcasecmp(v->name, "deny")) {
                                peer->ha = ast_append_ha(v->name, v->value, peer->ha);
@@ -7959,6 +8207,16 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
                                        ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of iax.conf\n", peer->name, v->lineno);
                                        peer->maxms = 0;
                                }
+                       } else if (!strcasecmp(v->name, "qualifysmoothing")) {
+                               peer->smoothing = ast_true(v->value);
+                       } else if (!strcasecmp(v->name, "qualifyfreqok")) {
+                               if (sscanf(v->value, "%d", &peer->pokefreqok) != 1) {
+                                       ast_log(LOG_WARNING, "Qualification testing frequency of peer '%s' when OK should a number of milliseconds at line %d of iax.conf\n", peer->name, v->lineno);
+                               }
+                       } else if (!strcasecmp(v->name, "qualifyfreqnotok")) {
+                               if (sscanf(v->value, "%d", &peer->pokefreqnotok) != 1) {
+                                       ast_log(LOG_WARNING, "Qualification testing frequency of peer '%s' when NOT OK should be a number of milliseconds at line %d of iax.conf\n", peer->name, v->lineno);
+                               } else ast_log(LOG_WARNING, "Set peer->pokefreqnotok to %d\n", peer->pokefreqnotok);
                        } else if (!strcasecmp(v->name, "timezone")) {
                                ast_copy_string(peer->zonetag, v->value, sizeof(peer->zonetag));
                        }/* else if (strcasecmp(v->name,"type")) */
@@ -7984,7 +8242,6 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, in
        struct ast_ha *oldha = NULL;
        struct iax2_context *oldcon = NULL;
        int format;
-       int found;
        char *varname = NULL, *varval = NULL;
        struct ast_variable *tmpvar = NULL;
        
@@ -8001,8 +8258,8 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, in
                }
        } else
                user = NULL;
+       
        if (user) {
-               found++;
                oldha = user->ha;
                oldcon = user->contexts;
                user->ha = NULL;
@@ -8028,11 +8285,7 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, in
                user->encmethods = iax2_encryption;
                ast_copy_string(user->name, name, sizeof(user->name));
                ast_copy_string(user->language, language, sizeof(user->language));
-               ast_copy_flags(user, (&globalflags), IAX_USEJITTERBUF); 
-               ast_copy_flags(user, (&globalflags), IAX_FORCEJITTERBUF);       
-               ast_copy_flags(user, (&globalflags), IAX_CODEC_USER_FIRST);
-               ast_copy_flags(user, (&globalflags), IAX_CODEC_NOPREFS);        
-               ast_copy_flags(user, (&globalflags), IAX_CODEC_NOCAP);  
+               ast_copy_flags(user, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_CODEC_USER_FIRST | IAX_CODEC_NOPREFS | IAX_CODEC_NOCAP); 
                while(v) {
                        if (!strcasecmp(v->name, "context")) {
                                con = build_context(v->value);
@@ -8270,6 +8523,7 @@ static int set_config(char *config_file, int reload)
        struct ast_variable *v;
        char *cat;
        char *utype;
+       char *tosval;
        int format;
        int portno = IAX_DEFAULT_PORTNO;
        int  x;
@@ -8286,14 +8540,29 @@ static int set_config(char *config_file, int reload)
                ast_log(LOG_ERROR, "Unable to load config %s\n", config_file);
                return -1;
        }
+
+       /* Reset global codec prefs */  
        memset(&prefs, 0 , sizeof(struct ast_codec_pref));
-       v = ast_variable_browse(cfg, "general");
+       
        /* Reset Global Flags */
        memset(&globalflags, 0, sizeof(globalflags));
+       ast_set_flag(&globalflags, IAX_RTUPDATE);
+
 #ifdef SO_NO_CHECK
        nochecksums = 0;
 #endif
 
+       min_reg_expire = IAX_DEFAULT_REG_EXPIRE;
+       max_reg_expire = IAX_DEFAULT_REG_EXPIRE;
+
+       v = ast_variable_browse(cfg, "general");
+
+       /* Seed initial tos value */
+       tosval = ast_variable_retrieve(cfg, "general", "tos");
+       if (tosval) {
+               if (ast_str2tos(tosval, &tos))
+                       ast_log(LOG_WARNING, "Invalid tos value, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none'\n");
+       }
        while(v) {
                if (!strcasecmp(v->name, "bindport")){ 
                        if (reload)
@@ -8318,6 +8587,8 @@ static int set_config(char *config_file, int reload)
 #ifdef NEWJB
                else if (!strcasecmp(v->name, "resyncthreshold")) 
                        resyncthreshold = atoi(v->value);
+               else if (!strcasecmp(v->name, "maxjitterinterps")) 
+                       maxjitterinterps = atoi(v->value);
 #endif
                else if (!strcasecmp(v->name, "jittershrinkrate")) 
                        jittershrinkrate = atoi(v->value);
@@ -8329,11 +8600,15 @@ static int set_config(char *config_file, int reload)
                        lagrq_time = atoi(v->value);
                else if (!strcasecmp(v->name, "dropcount")) 
                        iax2_dropcount = atoi(v->value);
+               else if (!strcasecmp(v->name, "maxregexpire")) 
+                       max_reg_expire = atoi(v->value);
+               else if (!strcasecmp(v->name, "minregexpire")) 
+                       min_reg_expire = atoi(v->value);
                else if (!strcasecmp(v->name, "bindaddr")) {
                        if (reload) {
                                ast_log(LOG_NOTICE, "Ignoring bindaddr on reload\n");
                        } else {
-                               if (!(ns = ast_netsock_bind(&netsock, io, v->value, portno, tos, socket_read, NULL))) {
+                               if (!(ns = ast_netsock_bind(netsock, io, v->value, portno, tos, socket_read, NULL))) {
                                        ast_log(LOG_WARNING, "Unable apply binding to '%s' at line %d\n", v->value, v->lineno);
                                } else {
                                        if (option_verbose > 1) {
@@ -8371,8 +8646,12 @@ static int set_config(char *config_file, int reload)
                        ast_set2_flag((&globalflags), ast_true(v->value), IAX_MESSAGEDETAIL);   
                else if (!strcasecmp(v->name, "rtcachefriends"))
                        ast_set2_flag((&globalflags), ast_true(v->value), IAX_RTCACHEFRIENDS);  
-               else if (!strcasecmp(v->name, "rtnoupdate"))
-                       ast_set2_flag((&globalflags), ast_true(v->value), IAX_RTNOUPDATE);      
+               else if (!strcasecmp(v->name, "rtignoreregexpire"))
+                       ast_set2_flag((&globalflags), ast_true(v->value), IAX_RTIGNOREREGEXPIRE);       
+               else if (!strcasecmp(v->name, "rtupdate"))
+                       ast_set2_flag((&globalflags), ast_true(v->value), IAX_RTUPDATE);
+               else if (!strcasecmp(v->name, "trunktimestamps"))
+                       ast_set2_flag(&globalflags, ast_true(v->value), IAX_TRUNKTIMESTAMPS);
                else if (!strcasecmp(v->name, "rtautoclear")) {
                        int i = atoi(v->value);
                        if(i > 0)
@@ -8418,19 +8697,7 @@ static int set_config(char *config_file, int reload)
                        if (!ast_context_find(regcontext))
                                ast_context_create(NULL, regcontext, channeltype);
                } else if (!strcasecmp(v->name, "tos")) {
-                       if (sscanf(v->value, "%d", &format) == 1)
-                               tos = format & 0xff;
-                       else if (!strcasecmp(v->value, "lowdelay"))
-                               tos = IPTOS_LOWDELAY;
-                       else if (!strcasecmp(v->value, "throughput"))
-                               tos = IPTOS_THROUGHPUT;
-                       else if (!strcasecmp(v->value, "reliability"))
-                               tos = IPTOS_RELIABILITY;
-                       else if (!strcasecmp(v->value, "mincost"))
-                               tos = IPTOS_MINCOST;
-                       else if (!strcasecmp(v->value, "none"))
-                               tos = 0;
-                       else
+                       if (ast_str2tos(v->value, &tos))
                                ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none'\n", v->lineno);
                } else if (!strcasecmp(v->name, "accountcode")) {
                        ast_copy_string(accountcode, v->value, sizeof(accountcode));
@@ -8447,6 +8714,11 @@ static int set_config(char *config_file, int reload)
                /*      ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
                v = v->next;
        }
+       if (min_reg_expire > max_reg_expire) {
+               ast_log(LOG_WARNING, "Minimum registration interval of %d is more than maximum of %d, resetting minimum to %d\n",
+                       min_reg_expire, max_reg_expire, max_reg_expire);
+               min_reg_expire = max_reg_expire;
+       }
        iax2_capability = capability;
        cat = ast_category_browse(cfg, NULL);
        while(cat) {
@@ -8609,8 +8881,7 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
        while(dp) {
                next = dp->next;
                /* Expire old caches */
-               if ((tv.tv_sec > dp->expirey.tv_sec) ||
-                               ((tv.tv_sec == dp->expirey.tv_sec) && (tv.tv_usec > dp->expirey.tv_usec)))  {
+               if (ast_tvcmp(tv, dp->expiry) > 0) {
                                /* It's expired, let it disappear */
                                if (prev)
                                        prev->next = dp->next;
@@ -8647,10 +8918,10 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
                memset(dp, 0, sizeof(struct iax2_dpcache));
                ast_copy_string(dp->peercontext, data, sizeof(dp->peercontext));
                ast_copy_string(dp->exten, exten, sizeof(dp->exten));
-               gettimeofday(&dp->expirey, NULL);
-               dp->orig = dp->expirey;
+               gettimeofday(&dp->expiry, NULL);
+               dp->orig = dp->expiry;
                /* Expires in 30 mins by default */
-               dp->expirey.tv_sec += iaxdefaultdpcache;
+               dp->expiry.tv_sec += iaxdefaultdpcache;
                dp->next = dpcache;
                dp->flags = CACHE_FLAG_PENDING;
                for (x=0;x<sizeof(dp->waiters) / sizeof(dp->waiters[0]); x++)
@@ -8728,7 +8999,7 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
                                dp->flags |= CACHE_FLAG_TIMEOUT;
                                /* Expire after only 60 seconds now.  This is designed to help reduce backlog in heavily loaded
                                   systems without leaving it unavailable once the server comes back online */
-                               dp->expirey.tv_sec = dp->orig.tv_sec + 60;
+                               dp->expiry.tv_sec = dp->orig.tv_sec + 60;
                                for (x=0;x<sizeof(dp->waiters) / sizeof(dp->waiters[0]); x++)
                                        if (dp->waiters[x] > -1)
                                                write(dp->waiters[x], "asdf", 4);
@@ -8876,6 +9147,13 @@ static char *function_iaxpeer(struct ast_channel *chan, char *cmd, char *data, c
                return ret;
        }
 
+       /* if our channel, return the IP address of the endpoint of current channel */
+       if (!strcmp(peername,"CURRENTCHANNEL")) {
+               unsigned short callno = PTR_TO_CALLNO(chan->tech_pvt);
+               ast_copy_string(buf, iaxs[callno]->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), iaxs[callno]->addr.sin_addr) : "", len);
+               return buf;
+       }
+
        if ((colname = strchr(peername, ':'))) {
                *colname = '\0';
                colname++;
@@ -8924,9 +9202,9 @@ static char *function_iaxpeer(struct ast_channel *chan, char *cmd, char *data, c
 struct ast_custom_function iaxpeer_function = {
     .name = "IAXPEER",
     .synopsis = "Gets IAX peer information",
-    .syntax = "IAXPEER(<peername>[:item])",
+    .syntax = "IAXPEER(<peername|CURRENTCHANNEL>[:item])",
     .read = function_iaxpeer,
-       .desc = "Valid items are:\n"
+       .desc = "If peername specified, valid items are:\n"
        "- ip (default)          The IP address.\n"
        "- mailbox               The configured mailbox.\n"
        "- context               The configured context.\n"
@@ -8937,6 +9215,8 @@ struct ast_custom_function iaxpeer_function = {
        "- codecs                The configured codecs.\n"
        "- codec[x]              Preferred codec index number 'x' (beginning with zero).\n"
        "\n"
+       "If CURRENTCHANNEL specified, returns IP address of current channel\n"
+       "\n"
 };
 
 
@@ -8947,7 +9227,7 @@ static int iax2_devicestate(void *data)
        struct iax2_peer *p;
        int found = 0;
        char *ext, *host;
-       char tmp[256] = "";
+       char tmp[256];
        int res = AST_DEVICE_INVALID;
 
        ast_copy_string(tmp, dest, sizeof(tmp));
@@ -8971,15 +9251,13 @@ static int iax2_devicestate(void *data)
                if (option_debug > 2) 
                        ast_log(LOG_DEBUG, "Found peer. Now checking device state for peer %s\n", host);
 
-
                if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) &&
-                       (!p->maxms || ((p->lastms > -1)  && (p->lastms <= p->maxms)))) {
-                       /* Peer is registred, or have default IP address
+                   (!p->maxms || ((p->lastms > -1) && (p->historicms <= p->maxms)))) {
+                       /* Peer is registered, or have default IP address
                           and a valid registration */
-                       if (p->lastms == 0 || p->lastms <= p->lastms)
-                               res = AST_DEVICE_NOT_INUSE;
-                       else
-                               res = AST_DEVICE_UNKNOWN;       /* Not reachable */
+                       if (p->historicms == 0 || p->historicms <= p->maxms)
+                               /* let the core figure out whether it is in use or not */
+                               res = AST_DEVICE_UNKNOWN;       
                }
        } else {
                if (option_debug > 2) 
@@ -9067,6 +9345,18 @@ static char debug_trunk_usage[] =
 "Usage: iax2 trunk debug\n"
 "       Requests current status of IAX trunking\n";
 
+static char no_debug_trunk_usage[] =
+"Usage: iax2 no trunk debug\n"
+"       Requests current status of IAX trunking\n";
+
+static char debug_jb_usage[] =
+"Usage: iax2 jb debug\n"
+"       Enables jitterbuffer debugging information\n";
+
+static char no_debug_jb_usage[] =
+"Usage: iax2 no jb debug\n"
+"       Disables jitterbuffer debugging information\n";
+
 static char iax2_test_losspct_usage[] =
 "Usage: iax2 test losspct <percentage>\n"
 "       For testing, throws away <percentage> percent of incoming packets\n";
@@ -9113,9 +9403,15 @@ static struct ast_cli_entry iax2_cli[] = {
        { { "iax2", "debug", NULL }, iax2_do_debug,
          "Enable IAX debugging", debug_usage },
        { { "iax2", "trunk", "debug", NULL }, iax2_do_trunk_debug,
-         "Request snapshot of IAX trunk states", debug_trunk_usage },
+         "Enable IAX trunk debugging", debug_trunk_usage },
+       { { "iax2", "jb", "debug", NULL }, iax2_do_jb_debug,
+         "Enable IAX jitterbuffer debugging", debug_jb_usage },
        { { "iax2", "no", "debug", NULL }, iax2_no_debug,
          "Disable IAX debugging", no_debug_usage },
+       { { "iax2", "no", "trunk", "debug", NULL }, iax2_no_trunk_debug,
+         "Disable IAX trunk debugging", no_debug_trunk_usage },
+       { { "iax2", "no", "jb", "debug", NULL }, iax2_no_jb_debug,
+         "Disable IAX jitterbuffer debugging", no_debug_jb_usage },
        { { "iax2", "test", "losspct", NULL }, iax2_test_losspct,
          "Set IAX2 incoming frame loss percentage", iax2_test_losspct_usage },
        { { "iax2", "provision", NULL }, iax2_prov_cmd,
@@ -9138,7 +9434,7 @@ static int __unload_module(void)
                pthread_cancel(netthreadid);
                pthread_join(netthreadid, NULL);
        }
-       ast_netsock_release(&netsock);
+       ast_netsock_release(netsock);
        for (x=0;x<IAX_MAX_CALLS;x++)
                if (iaxs[x])
                        iax2_destroy(x);
@@ -9184,9 +9480,6 @@ int load_module(void)
        jb_setoutput(jb_error_output, jb_warning_output, NULL);
 #endif
        
-       /* Seed random number generator */
-       srand(time(NULL));
-       
        sin.sin_family = AF_INET;
        sin.sin_port = htons(IAX_DEFAULT_PORTNO);
        sin.sin_addr.s_addr = INADDR_ANY;
@@ -9201,6 +9494,8 @@ int load_module(void)
                ast_log(LOG_WARNING, "Unable to open IAX timing interface: %s\n", strerror(errno));
 #endif         
 
+       memset(iaxs, 0, sizeof(iaxs));
+
        for (x=0;x<IAX_MAX_CALLS;x++)
                ast_mutex_init(&iaxsl[x]);
        
@@ -9212,13 +9507,18 @@ int load_module(void)
                return -1;
        }
 
+       netsock = ast_netsock_list_alloc();
+       if (!netsock) {
+               ast_log(LOG_ERROR, "Could not allocate netsock list.\n");
+               return -1;
+       }
+       ast_netsock_init(netsock);
+
        ast_mutex_init(&iaxq.lock);
        ast_mutex_init(&userl.lock);
        ast_mutex_init(&peerl.lock);
        ast_mutex_init(&waresl.lock);
        
-       ast_netsock_init(&netsock);
-
        ast_cli_register_multiple(iax2_cli, sizeof(iax2_cli) / sizeof(iax2_cli[0]));
 
        ast_register_application(papp, iax2_prov_app, psyn, pdescrip);
@@ -9238,7 +9538,7 @@ int load_module(void)
                ast_log(LOG_ERROR, "Unable to register IAX switch\n");
        
        if (defaultsockfd < 0) {
-               if (!(ns = ast_netsock_bindaddr(&netsock, io, &sin, tos, socket_read, NULL))) {
+               if (!(ns = ast_netsock_bindaddr(netsock, io, &sin, tos, socket_read, NULL))) {
                        ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
                        return -1;
                } else {
@@ -9254,7 +9554,7 @@ int load_module(void)
                        ast_verbose(VERBOSE_PREFIX_2 "IAX Ready and Listening\n");
        } else {
                ast_log(LOG_ERROR, "Unable to start network thread\n");
-               ast_netsock_release(&netsock);
+               ast_netsock_release(netsock);
        }
 
        for (reg = registrations; reg; reg = reg->next)
@@ -9278,11 +9578,7 @@ char *description()
 
 int usecount()
 {
-       int res;
-       ast_mutex_lock(&usecnt_lock);
-       res = usecnt;
-       ast_mutex_unlock(&usecnt_lock);
-       return res;
+       return usecnt;
 }
 
 char *key()