Remove unnecessary checks before calls to ast_strlen_zero. Also, change
[asterisk/asterisk.git] / channels / chan_iax2.c
index 1649d66..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"
@@ -152,7 +163,8 @@ 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 */
 
@@ -221,29 +233,29 @@ struct iax2_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_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)
-#define IAX_TRUNKTIMESTAMPS    (1 << 22)       /* Send trunk timestamps */
+#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;
 
@@ -258,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;
@@ -277,44 +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_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 */
+       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 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 */
+       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;
@@ -326,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;
@@ -351,31 +363,35 @@ 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;
 };
 
@@ -388,10 +404,10 @@ static struct iax2_registry *registrations;
 #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
@@ -412,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 */
+       /*! 32 bytes of semi-random data */
        unsigned char semirand[32];
-       /* Preferred language */
+       /*! 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;
@@ -561,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;
 };
 
@@ -593,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 */
+/*! Extension is nonexistent */
 #define CACHE_FLAG_NONEXISTENT         (1 << 1)
-/* Extension can exist */
+/*! 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 */
+/*! Request transmitted */
 #define CACHE_FLAG_TRANSMITTED         (1 << 5)
-/* Timeout */
+/*! Timeout */
 #define CACHE_FLAG_UNKNOWN             (1 << 6)
-/* Matchmore */
+/*! Matchmore */
 #define CACHE_FLAG_MATCHMORE           (1 << 7)
 
 static struct iax2_dpcache {
        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);
@@ -713,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 enum ast_bridge_result 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);
 
@@ -826,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;
 }
 
@@ -848,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;
 }
 
@@ -1057,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;
@@ -1263,7 +1287,7 @@ 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) {
@@ -1285,7 +1309,7 @@ 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((char *)dev) && bs) {
+       if (!ast_strlen_zero((char *)dev) && bs) {
                start *= bs;
                ast_mutex_lock(&waresl.lock);
                cur = waresl.wares;
@@ -1970,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);
@@ -2109,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;
@@ -2132,49 +2157,49 @@ static int get_from_jb(void *p) {
     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 = 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;
-       }
+               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]);
@@ -2497,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;
@@ -2505,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;
 
@@ -2794,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, "/");
@@ -2897,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);
@@ -2908,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)
@@ -3067,7 +3112,7 @@ static void unlock_both(unsigned short callno0, unsigned short callno1)
        ast_mutex_unlock(&iaxsl[callno0]);
 }
 
-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)
+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;
@@ -3147,7 +3192,16 @@ static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_cha
                }
                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 = AST_BRIDGE_FAILED;
                                break;
@@ -4074,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;
@@ -4083,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 iabuf[INET_ADDRSTRLEN];
        int registeredonly=0;
+       char *term = manager ? "\r\n" : "\n";
 
        switch (argc) {
        case 6:
@@ -4125,7 +4180,7 @@ 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];
@@ -4168,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);
@@ -4190,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);
@@ -4227,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 */
 
@@ -5045,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 */
 
@@ -5062,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));
@@ -5086,7 +5147,7 @@ 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];
@@ -5133,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 {
@@ -5154,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);
@@ -5205,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;
@@ -5224,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);
@@ -5239,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;
@@ -5341,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));
@@ -5352,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");
@@ -5366,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);
@@ -5457,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);
@@ -5497,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;
@@ -5505,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);
@@ -5516,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;
@@ -5525,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_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->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)
@@ -6592,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 &&
@@ -6600,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))
@@ -7239,7 +7340,7 @@ 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, fd, ies.serviceident, ies.provver);
@@ -7580,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, '|');
@@ -7992,7 +8093,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
                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;
@@ -8115,7 +8216,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
                        } 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", peer->pokefreqnotok);
+                               } 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")) */
@@ -8451,6 +8552,9 @@ static int set_config(char *config_file, int reload)
        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 */
@@ -8496,6 +8600,10 @@ 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");
@@ -8606,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) {
@@ -8768,7 +8881,7 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
        while(dp) {
                next = dp->next;
                /* Expire old caches */
-               if (ast_tvcmp(tv, dp->expirey) > 0) {
+               if (ast_tvcmp(tv, dp->expiry) > 0) {
                                /* It's expired, let it disappear */
                                if (prev)
                                        prev->next = dp->next;
@@ -8805,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++)
@@ -8886,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);
@@ -9034,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++;
@@ -9082,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"
@@ -9095,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"
 };