Merged revisions 338995 via svnmerge from
[asterisk/asterisk.git] / addons / chan_ooh323.c
index 70c0f02..621459a 100644 (file)
  *
  *****************************************************************************/
 
+/* Reworked version I, Nov-2009, by Alexandr Anikin, may@telecom-service.ru */
 
-#include "chan_ooh323.h"
 
 /*** MODULEINFO
        <defaultenabled>no</defaultenabled>
+       <support_level>extended</support_level>
  ***/
 
+#include "chan_ooh323.h"
+#include <math.h>
+
+#define FORMAT_STRING_SIZE     512
+
 /* Defaults */
 #define DEFAULT_CONTEXT "default"
 #define DEFAULT_H323ID "Asterisk PBX"
 #define H323_ALREADYGONE        (1<<5)
 #define H323_NEEDDESTROY        (1<<6)
 #define H323_DISABLEGK          (1<<7)
+#define H323_NEEDSTART         (1<<8)
+
+#define MAXT30 240
+#define T38TOAUDIOTIMEOUT 30
+#define T38_DISABLED 0
+#define T38_ENABLED 1
+#define T38_FAXGW 1
+
+#define FAXDETECT_CNG  1
+#define FAXDETECT_T38  2
 
 /* Channel description */
 static const char type[] = "OOH323";
 static const char tdesc[] = "Objective Systems H323 Channel Driver";
 static const char config[] = "ooh323.conf";
 
+struct ast_module *myself;
+
+static struct ast_jb_conf default_jbconf =
+{
+       .flags = 0,
+       .max_size = -1,
+       .resync_threshold = -1,
+       .impl = ""
+};
+static struct ast_jb_conf global_jbconf;
 
 /* Channel Definition */
-static struct ast_channel *ooh323_request(const char *type, int format, 
-                                        void *data, int *cause);
+static struct ast_channel *ooh323_request(const char *type, struct ast_format_cap *cap,
+                       const struct ast_channel *requestor,  void *data, int *cause);
 static int ooh323_digit_begin(struct ast_channel *ast, char digit);
 static int ooh323_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int ooh323_call(struct ast_channel *ast, char *dest, int timeout);
@@ -54,23 +80,28 @@ static int ooh323_answer(struct ast_channel *ast);
 static struct ast_frame *ooh323_read(struct ast_channel *ast);
 static int ooh323_write(struct ast_channel *ast, struct ast_frame *f);
 static int ooh323_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
+static int ooh323_queryoption(struct ast_channel *ast, int option, void *data, int *datalen);
 static int ooh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+static int function_ooh323_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
+static int function_ooh323_write(struct ast_channel *chan, const char *cmd, char *data, const char *value);
+
+static enum ast_rtp_glue_result ooh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **rtp);
+static enum ast_rtp_glue_result ooh323_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp_instance **rtp);
+static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, 
+          struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, const struct ast_format_cap *codecs, int nat_active);
 
-static enum ast_rtp_get_result ooh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
-static enum ast_rtp_get_result ooh323_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
-static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, 
-                             struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active);
+static struct ast_udptl *ooh323_get_udptl_peer(struct ast_channel *chan);
+static int ooh323_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl);
 
 static void print_codec_to_cli(int fd, struct ast_codec_pref *pref);
 
-#if 0
-static void ast_ooh323c_exit();
-#endif
+struct ooh323_peer *find_friend(const char *name, int port);
 
-static const struct ast_channel_tech ooh323_tech = {
+
+static struct ast_channel_tech ooh323_tech = {
        .type = type,
        .description = tdesc,
-       .capabilities = -1,
+       .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
        .requester = ooh323_request,
        .send_digit_begin = ooh323_digit_begin,
        .send_digit_end = ooh323_digit_end,
@@ -83,22 +114,53 @@ static const struct ast_channel_tech ooh323_tech = {
        .indicate = ooh323_indicate,
        .fixup = ooh323_fixup,
        .send_html = 0,
-       .bridge = ast_rtp_bridge,
+       .queryoption = ooh323_queryoption,
+       .bridge = ast_rtp_instance_bridge,              /* XXX chan unlocked ? */
+       .early_bridge = ast_rtp_instance_early_bridge,
+       .func_channel_read = function_ooh323_read,
+       .func_channel_write = function_ooh323_write,
 };
 
-static struct ast_rtp_protocol ooh323_rtp = {
+static struct ast_rtp_glue ooh323_rtp = {
        .type = type,
        .get_rtp_info = ooh323_get_rtp_peer,
        .get_vrtp_info = ooh323_get_vrtp_peer,
-       .set_rtp_peer = ooh323_set_rtp_peer
+       .update_peer = ooh323_set_rtp_peer,
+};
+
+static struct ast_udptl_protocol ooh323_udptl = {
+       type: "H323",
+       get_udptl_info: ooh323_get_udptl_peer,
+       set_udptl_peer: ooh323_set_udptl_peer,
 };
 
+
+
+struct ooh323_user;
+
 /* H.323 channel private structure */
 static struct ooh323_pvt {
        ast_mutex_t lock;               /* Channel private lock */
-       struct ast_rtp *rtp;
-       struct ast_rtp *vrtp; /* Placeholder for now */
+       struct ast_rtp_instance *rtp;
+       struct ast_rtp_instance *vrtp; /* Placeholder for now */
+
+       int t38support;                 /* T.38 mode - disable, transparent, faxgw */
+       int faxdetect;
+       int faxdetected;
+       int rtptimeout;
+       struct ast_udptl *udptl;
+       int faxmode;
+       int t38_tx_enable;
+       int t38_init;
+       struct ast_sockaddr udptlredirip;
+       time_t lastTxT38;
+       int chmodepend;
+
        struct ast_channel *owner;      /* Master Channel */
+       union {
+               char  *user;    /* cooperating user/peer */
+               char  *peer;
+       } neighbor;
        time_t lastrtptx;
        time_t lastrtprx;
        unsigned int flags;
@@ -118,17 +180,25 @@ static struct ooh323_pvt {
        char callee_url[AST_MAX_EXTENSION];
  
        int port;
-       int readformat;   /* negotiated read format */
-       int writeformat;  /* negotiated write format */
-       int capability;
+       struct ast_format readformat;   /* negotiated read format */
+       struct ast_format writeformat;  /* negotiated write format */
+       struct ast_format_cap *cap;
        struct ast_codec_pref prefs;
        int dtmfmode;
+       int dtmfcodec;
        char exten[AST_MAX_EXTENSION];  /* Requested extension */
        char context[AST_MAX_EXTENSION];        /* Context where to start */
        char accountcode[256];  /* Account code */
        int nat;
        int amaflags;
+       int progsent;                   /* progress is sent */
+       int alertsent;                  /* alerting is sent */
+       int g729onlyA;                  /* G.729 only A */
        struct ast_dsp *vad;
+       struct OOH323Regex *rtpmask;    /* rtp ip regexp */
+       char rtpmaskstr[120];
+       int rtdrcount, rtdrinterval;    /* roundtripdelayreq */
+       int faststart, h245tunneling;   /* faststart & h245 tunneling */
        struct ooh323_pvt *next;        /* Next entity */
 } *iflist = NULL;
 
@@ -138,18 +208,26 @@ AST_MUTEX_DEFINE_STATIC(iflock);
 /* Profile of H.323 user registered with PBX*/
 struct ooh323_user{
        ast_mutex_t lock;
-       char        name[256];
-       char        context[AST_MAX_EXTENSION];
-       int         incominglimit;
-       unsigned    inUse;
-       char        accountcode[20];
-       int         amaflags;
-       int         capability;
+       char            name[256];
+       char            context[AST_MAX_EXTENSION];
+       int             incominglimit;
+       unsigned        inUse;
+       char            accountcode[20];
+       int             amaflags;
+       struct ast_format_cap *cap;
        struct ast_codec_pref prefs;
-       int         dtmfmode;
-       int         rtptimeout;
-       int         mUseIP;        /* Use IP address or H323-ID to search user */
-       char        mIP[20];
+       int             dtmfmode;
+       int             dtmfcodec;
+       int             faxdetect;
+       int             t38support;
+       int             rtptimeout;
+       int             mUseIP;        /* Use IP address or H323-ID to search user */
+       char            mIP[4*8+7+2];  /* Max for IPv6 - 2 brackets, 8 4hex, 7 - : */
+       struct OOH323Regex *rtpmask;
+       char            rtpmaskstr[120];
+       int             rtdrcount, rtdrinterval;
+       int             faststart, h245tunneling;
+       int             g729onlyA;
        struct ooh323_user *next;
 };
 
@@ -159,19 +237,27 @@ struct ooh323_peer{
        char        name[256];
        unsigned    outgoinglimit;
        unsigned    outUse;
-       int         capability;
+       struct ast_format_cap *cap;
        struct ast_codec_pref prefs;
        char        accountcode[20];
        int         amaflags;
        int         dtmfmode;
+       int         dtmfcodec;
+       int         faxdetect;
+       int         t38support;
        int         mFriend;    /* indicates defined as friend */
-       char        ip[20];
+       char        ip[4*8+7+2]; /* Max for IPv6 - 2 brackets, 8 4hex, 7 - : */
        int         port;
        char        *h323id;    /* H323-ID alias, which asterisk will register with gk to reach this peer*/
        char        *email;     /* Email alias, which asterisk will register with gk to reach this peer*/
        char        *url;       /* url alias, which asterisk will register with gk to reach this peer*/
        char        *e164;      /* e164 alias, which asterisk will register with gk to reach this peer*/
        int         rtptimeout;
+       struct OOH323Regex          *rtpmask;
+       char        rtpmaskstr[120];
+       int         rtdrcount,rtdrinterval;
+       int         faststart, h245tunneling;
+       int         g729onlyA;
        struct ooh323_peer *next;
 };
 
@@ -197,35 +283,56 @@ AST_MUTEX_DEFINE_STATIC(usecnt_lock);
 
 AST_MUTEX_DEFINE_STATIC(ooh323c_cmd_lock);
 
+static long callnumber = 0;
+AST_MUTEX_DEFINE_STATIC(ooh323c_cn_lock);
+
 /* stack callbacks */
 int onAlerting(ooCallData *call);
+int onProgress(ooCallData *call);
 int onNewCallCreated(ooCallData *call);
+int onOutgoingCall(ooCallData *call);
 int onCallEstablished(ooCallData *call);
 int onCallCleared(ooCallData *call);
+void onModeChanged(ooCallData *call, int t38mode);
 
 static char gLogFile[256] = DEFAULT_LOGFILE;
 static int  gPort = 1720;
-static char gIP[20];
-static char gCallerID[AST_MAX_EXTENSION] = DEFAULT_H323ID;
+static char gIP[2+8*4+7];      /* Max for IPv6 addr */
+struct ast_sockaddr bindaddr;
+int v6mode = 0;
+static char gCallerID[AST_MAX_EXTENSION] = "";
 static struct ooAliases *gAliasList;
-static int  gCapability = AST_FORMAT_ULAW;
+static struct ast_format_cap *gCap;
 static struct ast_codec_pref gPrefs;
 static int  gDTMFMode = H323_DTMF_RFC2833;
+static int  gDTMFCodec = 101;
+static int  gFAXdetect = FAXDETECT_CNG;
+static int  gT38Support = T38_FAXGW;
 static char gGatekeeper[100];
 static enum RasGatekeeperMode gRasGkMode = RasNoGatekeeper;
 
 static int  gIsGateway = 0;
 static int  gFastStart = 1;
 static int  gTunneling = 1;
+static int  gBeMaster = 0;
 static int  gMediaWaitForConnect = 0;
 static int  gTOS = 0;
 static int  gRTPTimeout = 60;
+static int  g729onlyA = 0;
 static char gAccountcode[80] = DEFAULT_H323ACCNT;
 static int  gAMAFLAGS;
 static char gContext[AST_MAX_EXTENSION] = DEFAULT_CONTEXT;
-static int  gIncomingLimit = 4;
-static int  gOutgoingLimit = 4;
+static int  gIncomingLimit = 1024;
+static int  gOutgoingLimit = 1024;
 OOBOOL gH323Debug = FALSE;
+static int gTRCLVL = OOTRCLVLERR;
+static int gRTDRCount = 0, gRTDRInterval = 0;
+
+static int t35countrycode = 0;
+static int t35extensions = 0;
+static int manufacturer = 0;
+static char vendor[AST_MAX_EXTENSION] =  "";
+static char version[AST_MAX_EXTENSION] = "";
 
 static struct ooh323_config
 {
@@ -234,7 +341,7 @@ static struct ooh323_config
 } ooconfig;
 
 /** Asterisk RTP stuff*/
-static struct sched_context *sched;
+static struct ast_sched_context *sched;
 static struct io_context *io;
 
 /* Protect the monitoring thread, so only one process can kill or start it, 
@@ -248,45 +355,74 @@ static pthread_t monitor_thread = AST_PTHREADT_NULL;
 
 
 static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
-                                             const char *host) 
+                                             const char *host, struct ast_format_cap *cap, const char *linkedid)
 {
        struct ast_channel *ch = NULL;
-       int fmt;
+       struct ast_format tmpfmt;
+       int features = 0;
+
        if (gH323Debug)
                ast_verbose("---   ooh323_new - %s\n", host);
 
-
+       ast_format_clear(&tmpfmt);
        /* Don't hold a h323 pvt lock while we allocate a channel */
        ast_mutex_unlock(&i->lock);
-       ch = ast_channel_alloc(1, state, i->callerid_num, i->callerid_name, i->accountcode, i->exten, i->context, i->amaflags, "OOH323/%s-%08x", host, (unsigned int)(unsigned long) i);
+       ch = ast_channel_alloc(1, state, i->callerid_num, i->callerid_name, 
+                               i->accountcode, i->exten, i->context, linkedid, i->amaflags,
+                               "OOH323/%s-%ld", host, callnumber);
+       ast_mutex_lock(&ooh323c_cn_lock);
+       callnumber++;
+       ast_mutex_unlock(&ooh323c_cn_lock);
+   
        ast_mutex_lock(&i->lock);
 
        if (ch) {
                ast_channel_lock(ch);
                ch->tech = &ooh323_tech;
 
-               ch->nativeformats = i->capability;
+               if (cap)
+                       ast_best_codec(cap, &tmpfmt);
+               if (!tmpfmt.id)
+                       ast_codec_pref_index(&i->prefs, 0, &tmpfmt);
 
-               fmt = ast_best_codec(ch->nativeformats);
+               ast_format_cap_add(ch->nativeformats, &tmpfmt);
+               ast_format_copy(&ch->rawwriteformat, &tmpfmt);
+               ast_format_copy(&ch->rawreadformat, &tmpfmt);
 
-               ch->fds[0] = ast_rtp_fd(i->rtp);
-               ch->fds[1] = ast_rtcp_fd(i->rtp);
+               ast_jb_configure(ch, &global_jbconf);
 
                if (state == AST_STATE_RING)
                        ch->rings = 1;
 
                ch->adsicpe = AST_ADSI_UNAVAILABLE;
-               ch->writeformat = fmt;
-               ch->rawwriteformat = fmt;
-               ch->readformat = fmt;
-               ch->rawreadformat = fmt;
+               ast_set_write_format(ch, &tmpfmt);
+               ast_set_read_format(ch, &tmpfmt);
                ch->tech_pvt = i;
                i->owner = ch;
+               ast_module_ref(myself);
 
                /* Allocate dsp for in-band DTMF support */
-               if (i->dtmfmode & H323_DTMF_INBAND) {
+               if ((i->dtmfmode & H323_DTMF_INBAND) || (i->faxdetect & FAXDETECT_CNG)) {
                        i->vad = ast_dsp_new();
-                       ast_dsp_set_features(i->vad, DSP_FEATURE_DIGIT_DETECT);
+               }
+
+               /* inband DTMF*/
+               if (i->dtmfmode & H323_DTMF_INBAND) {
+                       features |= DSP_FEATURE_DIGIT_DETECT;
+                       if (i->dtmfmode & H323_DTMF_INBANDRELAX) {
+                               ast_dsp_set_digitmode(i->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
+                       }
+               }
+
+               /* fax detection*/
+               if (i->faxdetect & FAXDETECT_CNG) {
+                       features |= DSP_FEATURE_FAX_DETECT;
+                       ast_dsp_set_faxmode(i->vad,
+                                       DSP_FAXMODE_DETECT_CNG | DSP_FAXMODE_DETECT_CED);
+               }
+
+               if (features) {
+                       ast_dsp_set_features(i->vad, features);
                }
 
                ast_mutex_lock(&usecnt_lock);
@@ -300,15 +436,8 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
                ast_copy_string(ch->exten, i->exten, sizeof(ch->exten));
 
                ch->priority = 1;
-               if (i->callerid_name) {
-                       ch->cid.cid_name = strdup(i->callerid_name);
-               }
-               if (i->callerid_num) {
-
-                       ch->cid.cid_num = strdup(i->callerid_num);
-               }
 
-               if (!ast_test_flag(i, H323_OUTGOING)) {
+               if(!ast_test_flag(i, H323_OUTGOING)) {
                
                        if (!ast_strlen_zero(i->caller_h323id)) {
                                pbx_builtin_setvar_helper(ch, "_CALLER_H323ID", i->caller_h323id);
@@ -335,19 +464,21 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
 
                ast_setstate(ch, state);
                if (state != AST_STATE_DOWN) {
-                       if (ast_pbx_start(ch)) {
+                       if (ast_pbx_start(ch)) {
                                ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ch->name);
-                               ast_channel_unlock(ch);
+                               ast_channel_unlock(ch);
                                ast_hangup(ch);
                                ch = NULL;
-                       }
-               }
+                       } 
+               }
+
+               manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", "Channel: %s\r\nChanneltype: %s\r\n"
+                               "CallRef: %d\r\n", ch->name, "OOH323", i->call_reference);
        } else
                ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
 
 
-       if (ch)
-               ast_channel_unlock(ch);
+       if(ch)   ast_channel_unlock(ch);
 
        if (gH323Debug)
                ast_verbose("+++   h323_new\n");
@@ -360,7 +491,7 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
 static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken) 
 {
        struct ooh323_pvt *pvt = NULL;
-       struct in_addr ipAddr;
+
        if (gH323Debug)
                ast_verbose("---   ooh323_alloc\n");
 
@@ -368,28 +499,24 @@ static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken)
                ast_log(LOG_ERROR, "Couldn't allocate private ooh323 structure\n");
                return NULL;
        }
+       if (!(pvt->cap = ast_format_cap_alloc_nolock())) {
+               ast_free(pvt);
+               ast_log(LOG_ERROR, "Couldn't allocate private ooh323 structure\n");
+               return NULL;
+       }
 
        ast_mutex_init(&pvt->lock);
        ast_mutex_lock(&pvt->lock);
 
-       if (!inet_aton(gIP, &ipAddr)) {
-               ast_log(LOG_ERROR, "Invalid OOH323 driver ip address\n");
-               ast_mutex_unlock(&pvt->lock);
-               ast_mutex_destroy(&pvt->lock);
-               free(pvt);
-               return NULL;
-       }
-
-       if (!(pvt->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, ipAddr))) {
-               ast_log(LOG_WARNING, "Unable to create RTP session: %s\n", 
-                                 strerror(errno));
-               ast_mutex_unlock(&pvt->lock);
-               ast_mutex_destroy(&pvt->lock);
-               free(pvt);
-               return NULL;
-       }
-       ast_rtp_setqos(pvt->rtp, gTOS, 0, "ooh323");
+       pvt->faxmode = 0;
+       pvt->chmodepend = 0;
+       pvt->faxdetected = 0;
+       pvt->faxdetect = gFAXdetect;
+       pvt->t38support = gT38Support;
+       pvt->rtptimeout = gRTPTimeout;
+       pvt->rtdrinterval = gRTDRInterval;
+       pvt->rtdrcount = gRTDRCount;
+       pvt->g729onlyA = g729onlyA;
 
        pvt->call_reference = callref;
        if (callToken)
@@ -400,10 +527,12 @@ static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken)
                OO_SETFLAG(pvt->flags, H323_DISABLEGK);
 
        pvt->dtmfmode = gDTMFMode;
+       pvt->dtmfcodec = gDTMFCodec;
        ast_copy_string(pvt->context, gContext, sizeof(pvt->context));
        ast_copy_string(pvt->accountcode, gAccountcode, sizeof(pvt->accountcode));
+
        pvt->amaflags = gAMAFLAGS;
-       pvt->capability = gCapability;
+       ast_format_cap_copy(pvt->cap, gCap);
        memcpy(&pvt->prefs, &gPrefs, sizeof(pvt->prefs));
 
        ast_mutex_unlock(&pvt->lock); 
@@ -423,8 +552,9 @@ static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken)
 /*
        Possible data values - peername, exten/peername, exten@ip
  */
-static struct ast_channel *ooh323_request(const char *type, int format, 
-                                                                                                        void *data, int *cause)
+static struct ast_channel *ooh323_request(const char *type, struct ast_format_cap *cap,
+               const struct ast_channel *requestor, void *data, int *cause)
+
 {
        struct ast_channel *chan = NULL;
        struct ooh323_pvt *p = NULL;
@@ -432,19 +562,15 @@ static struct ast_channel *ooh323_request(const char *type, int format,
        char *dest = NULL; 
        char *ext = NULL;
        char tmp[256];
-       char formats[512];
-       int oldformat;
+       char formats[FORMAT_STRING_SIZE];
        int port = 0;
 
        if (gH323Debug)
                ast_verbose("---   ooh323_request - data %s format %s\n", (char*)data,  
-                                                                               ast_getformatname_multiple(formats,512,format));
+                                                                               ast_getformatname_multiple(formats,FORMAT_STRING_SIZE,cap));
 
-       oldformat = format;
-       format &= AST_FORMAT_AUDIO_MASK;
-       if (!format) {
-               ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format "
-                                                                 "'%d'\n", format);
+       if (!(ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO))) {
+               ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(formats,FORMAT_STRING_SIZE,cap));
                return NULL;
        }
 
@@ -459,14 +585,16 @@ static struct ast_channel *ooh323_request(const char *type, int format,
        /* This is an outgoing call, since ooh323_request is called */
        ast_set_flag(p, H323_OUTGOING);
 
-       ast_copy_string(tmp, data, sizeof(data));
+
+       ast_copy_string(tmp, data, sizeof(tmp));
 
        dest = strchr(tmp, '/');
 
        if (dest) {  
                *dest = '\0';
                dest++;
-               ext = tmp;
+               ext = dest;
+               dest = tmp;
        } else if ((dest = strchr(tmp, '@'))) {
                *dest = '\0';
                dest++;
@@ -487,6 +615,10 @@ static struct ast_channel *ooh323_request(const char *type, int format,
        if (dest) {
                peer = find_peer(dest, port);
        } else{
+               ast_mutex_lock(&iflock);
+               ast_mutex_unlock(&p->lock);
+               ooh323_destroy(p);
+               ast_mutex_unlock(&iflock);
                ast_log(LOG_ERROR, "Destination format is not supported\n");
                return NULL;
        }
@@ -496,23 +628,54 @@ static struct ast_channel *ooh323_request(const char *type, int format,
                p->host = strdup(peer->ip);
                p->port = peer->port;
                /* Disable gk as we are going to call a known peer*/
-               OO_SETFLAG(p->flags, H323_DISABLEGK);
+               /* OO_SETFLAG(p->flags, H323_DISABLEGK); */
 
                if (ext)
                        ast_copy_string(p->exten, ext, sizeof(p->exten));
 
-               if (peer->capability & format) {
-                       p->capability = peer->capability & format;
-               } else {
-                 p->capability = peer->capability;
-               }
+               ast_format_cap_copy(p->cap, peer->cap);
                memcpy(&p->prefs, &peer->prefs, sizeof(struct ast_codec_pref));
-               p->dtmfmode = peer->dtmfmode;
+               p->g729onlyA = peer->g729onlyA;
+               p->dtmfmode |= peer->dtmfmode;
+               p->dtmfcodec  = peer->dtmfcodec;
+               p->faxdetect = peer->faxdetect;
+               p->t38support = peer->t38support;
+               p->rtptimeout = peer->rtptimeout;
+               p->faststart = peer->faststart;
+               p->h245tunneling = peer->h245tunneling;
+               if (peer->rtpmask && peer->rtpmaskstr[0]) {
+                       p->rtpmask = peer->rtpmask;
+                       ast_copy_string(p->rtpmaskstr, peer->rtpmaskstr, sizeof(p->rtpmaskstr));
+               }
+
+               if (peer->rtdrinterval) {
+                       p->rtdrinterval = peer->rtdrinterval;
+                       p->rtdrcount = peer->rtdrcount;
+               }
+
                ast_copy_string(p->accountcode, peer->accountcode, sizeof(p->accountcode));
                p->amaflags = peer->amaflags;
        } else {
+               if (gRasGkMode ==  RasNoGatekeeper) {
+                       /* no gk and no peer */
+                       ast_log(LOG_ERROR, "Call to undefined peer %s", dest);
+                       ast_mutex_lock(&iflock);
+                       ast_mutex_unlock(&p->lock);
+                       ooh323_destroy(p);
+                       ast_mutex_unlock(&iflock);
+                       return NULL;
+               }
+               p->g729onlyA = g729onlyA;
                p->dtmfmode = gDTMFMode;
-               p->capability = gCapability;
+               p->dtmfcodec = gDTMFCodec;
+               p->faxdetect = gFAXdetect;
+               p->t38support = gT38Support;
+               p->rtptimeout = gRTPTimeout;
+               ast_format_cap_copy(p->cap, gCap);
+               p->rtdrinterval = gRTDRInterval;
+               p->rtdrcount = gRTDRCount;
+               p->faststart = gFastStart;
+               p->h245tunneling = gTunneling;
 
                memcpy(&p->prefs, &gPrefs, sizeof(struct ast_codec_pref));
                p->username = strdup(dest);
@@ -527,7 +690,8 @@ static struct ast_channel *ooh323_request(const char *type, int format,
        }
 
 
-       chan = ooh323_new(p, AST_STATE_DOWN, p->username);
+       chan = ooh323_new(p, AST_STATE_DOWN, p->username, cap,
+                                requestor ? requestor->linkedid : NULL);
        
        ast_mutex_unlock(&p->lock);
 
@@ -535,6 +699,22 @@ static struct ast_channel *ooh323_request(const char *type, int format,
                ast_mutex_lock(&iflock);
                ooh323_destroy(p);
                ast_mutex_unlock(&iflock);
+       } else {
+               ast_mutex_lock(&p->lock);
+               p->callToken = (char*)ast_calloc(1, AST_MAX_EXTENSION);
+               if(!p->callToken) {
+                               ast_mutex_unlock(&p->lock);
+                               ast_mutex_lock(&iflock);
+                               ooh323_destroy(p);
+                               ast_mutex_unlock(&iflock);
+                               ast_log(LOG_ERROR, "Failed to allocate memory for callToken\n");
+                               return NULL;
+               }
+
+               ast_mutex_unlock(&p->lock);
+               ast_mutex_lock(&ooh323c_cmd_lock);
+               ooMakeCall(data, p->callToken, AST_MAX_EXTENSION, NULL);
+               ast_mutex_unlock(&ooh323c_cmd_lock);
        }
 
        restart_monitor();
@@ -573,9 +753,10 @@ struct ooh323_user *find_user(const char * name, const char* ip)
        struct ooh323_user *user;
 
        if (gH323Debug)
-               ast_verbose("---   find_user\n");
+      ast_verbose("---   find_user: %s, %s\n",name,ip);
 
        ast_mutex_lock(&userl.lock);
+
        for (user = userl.users; user; user = user->next) {
                if (ip && user->mUseIP && !strcmp(user->mIP, ip)) {
                        break;
@@ -584,6 +765,7 @@ struct ooh323_user *find_user(const char * name, const char* ip)
                        break;
                }
        }
+
        ast_mutex_unlock(&userl.lock);
 
        if (gH323Debug)
@@ -631,6 +813,7 @@ struct ooh323_peer *find_peer(const char * name, int port)
        if (gH323Debug)
                ast_verbose("---   find_peer \"%s\"\n", name);
 
+
        ast_mutex_lock(&peerl.lock);
        for (peer = peerl.peers; peer; peer = peer->next) {
                if (gH323Debug) {
@@ -674,16 +857,15 @@ static int ooh323_digit_begin(struct ast_channel *chan, char digit)
                return -1;
        }
        ast_mutex_lock(&p->lock);
-       if (p->rtp && (p->dtmfmode & H323_DTMF_RFC2833)) {
-               ast_rtp_senddigit_begin(p->rtp, digit);
+
+       if (p->rtp && ((p->dtmfmode & H323_DTMF_RFC2833) || (p->dtmfmode & H323_DTMF_CISCO))) {
+               ast_rtp_instance_dtmf_begin(p->rtp, digit);
        } else if (((p->dtmfmode & H323_DTMF_Q931) ||
                                                 (p->dtmfmode & H323_DTMF_H245ALPHANUMERIC) ||
                                                 (p->dtmfmode & H323_DTMF_H245SIGNAL))) {
                dtmf[0] = digit;
                dtmf[1] = '\0';
-               ast_mutex_lock(&ooh323c_cmd_lock);
                ooSendDTMFDigit(p->callToken, dtmf);
-               ast_mutex_unlock(&ooh323c_cmd_lock);
        }
        ast_mutex_unlock(&p->lock);
        if (gH323Debug)
@@ -704,8 +886,8 @@ static int ooh323_digit_end(struct ast_channel *chan, char digit, unsigned int d
                return -1;
        }
        ast_mutex_lock(&p->lock);
-       if (p->rtp && (p->dtmfmode & H323_DTMF_RFC2833)) 
-               ast_rtp_senddigit_end(p->rtp, digit);
+       if (p->rtp && ((p->dtmfmode & H323_DTMF_RFC2833) || (p->dtmfmode & H323_DTMF_CISCO)) ) 
+               ast_rtp_instance_dtmf_end(p->rtp, digit);
 
        ast_mutex_unlock(&p->lock);
        if (gH323Debug)
@@ -719,43 +901,44 @@ static int ooh323_call(struct ast_channel *ast, char *dest, int timeout)
 {
        struct ooh323_pvt *p = ast->tech_pvt;
        char destination[256];
-       int res = 0;
+       int res=0, i;
        const char *val = NULL;
        ooCallOptions opts = {
                .fastStart = TRUE,
                .tunneling = TRUE,
                .disableGk = TRUE,
-               .callMode = OO_CALLMODE_AUDIOCALL
+               .callMode = OO_CALLMODE_AUDIOCALL,
+               .transfercap = 0
        };
+
        if (gH323Debug)
                ast_verbose("---   ooh323_call- %s\n", dest);
 
-       if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
+
+       if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
                ast_log(LOG_WARNING, "ooh323_call called on %s, neither down nor "
-                                                                       "reserved\n", ast->name);
+                                                               "reserved\n", ast->name);
                return -1;
        }
        ast_mutex_lock(&p->lock);
        ast_set_flag(p, H323_OUTGOING);
-       if (ast->cid.cid_num) {
-               if (p->callerid_num) {
-                       free(p->callerid_num);
-               }
-               p->callerid_num = strdup(ast->cid.cid_num);
+       if (ast->connected.id.number.valid && ast->connected.id.number.str) {
+               free(p->callerid_num);
+               p->callerid_num = strdup(ast->connected.id.number.str);
        }
 
-       if (ast->cid.cid_name) {
-               if (p->callerid_name) {
-                       free(p->callerid_name);
-               }
-               p->callerid_name = strdup(ast->cid.cid_name);
-       }
-       else{
-               ast->cid.cid_name = strdup(gCallerID);
-               if (p->callerid_name) {
-                       free(p->callerid_name);
-               }
-               p->callerid_name = strdup(ast->cid.cid_name);
+       if (ast->connected.id.name.valid && ast->connected.id.name.str) {
+               free(p->callerid_name);
+               p->callerid_name = strdup(ast->connected.id.name.str);
+       } else if (ast->connected.id.number.valid && ast->connected.id.number.str) {
+               free(p->callerid_name);
+               p->callerid_name = strdup(ast->connected.id.number.str);
+       } else {
+               ast->connected.id.name.valid = 1;
+               free(ast->connected.id.name.str);
+               ast->connected.id.name.str = strdup(gCallerID);
+               free(p->callerid_name);
+               p->callerid_name = strdup(ast->connected.id.name.str);
        }
 
        /* Retrieve vars */
@@ -767,9 +950,8 @@ static int ooh323_call(struct ast_channel *ast, char *dest, int timeout)
        
        if ((val = pbx_builtin_getvar_helper(ast, "CALLER_H323DIALEDDIGITS"))) {
                ast_copy_string(p->caller_dialedDigits, val, sizeof(p->caller_dialedDigits));
-               if (!p->callerid_num) {
+               if(!p->callerid_num)
                        p->callerid_num = strdup(val);
-               }
        }
 
        if ((val = pbx_builtin_getvar_helper(ast, "CALLER_H323EMAIL"))) {
@@ -780,13 +962,6 @@ static int ooh323_call(struct ast_channel *ast, char *dest, int timeout)
                ast_copy_string(p->caller_url, val, sizeof(p->caller_url));
        }
 
-
-       if (!(p->callToken = (char*)malloc(AST_MAX_EXTENSION))) {
-               ast_mutex_unlock(&p->lock);
-               ast_log(LOG_ERROR, "Failed to allocate memory for callToken\n");
-               return -1; /* TODO: need to clean/hangup?? */
-       }               
-
        if (p->host && p->port != 0)
                snprintf(destination, sizeof(destination), "%s:%d", p->host, p->port);
        else if (p->host)
@@ -794,17 +969,24 @@ static int ooh323_call(struct ast_channel *ast, char *dest, int timeout)
        else
                ast_copy_string(destination, dest, sizeof(destination));
 
-       ast_mutex_lock(&ooh323c_cmd_lock);
-       if (OO_TESTFLAG(p->flags, H323_DISABLEGK))
-               res = ooMakeCall(destination, p->callToken, AST_MAX_EXTENSION, &opts);
-       else
-               res = ooMakeCall(destination, p->callToken, AST_MAX_EXTENSION, NULL);
-       ast_mutex_unlock(&ooh323c_cmd_lock);
+       destination[sizeof(destination)-1]='\0';
+
+       opts.transfercap = ast->transfercapability;
+       opts.fastStart = p->faststart;
+       opts.tunneling = p->h245tunneling;
+
+       for (i=0;i<480 && !isRunning(p->callToken);i++) usleep(12000);
+
+       if(OO_TESTFLAG(p->flags, H323_DISABLEGK)) {
+               res = ooRunCall(destination, p->callToken, AST_MAX_EXTENSION, &opts);
+       } else {
+               res = ooRunCall(destination, p->callToken, AST_MAX_EXTENSION, NULL);
+       }
 
        ast_mutex_unlock(&p->lock);
        if (res != OO_OK) {
                ast_log(LOG_ERROR, "Failed to make call\n");
-               return -1; /* TODO: cleanup */
+               return -1; /* ToDO: cleanup */
        }
        if (gH323Debug)
                ast_verbose("+++   ooh323_call\n");
@@ -815,6 +997,7 @@ static int ooh323_call(struct ast_channel *ast, char *dest, int timeout)
 static int ooh323_hangup(struct ast_channel *ast)
 {
        struct ooh323_pvt *p = ast->tech_pvt;
+       int q931cause = AST_CAUSE_NORMAL_CLEARING;
 
        if (gH323Debug)
                ast_verbose("---   ooh323_hangup\n");
@@ -822,23 +1005,42 @@ static int ooh323_hangup(struct ast_channel *ast)
        if (p) {
                ast_mutex_lock(&p->lock);
 
+        if (ast->hangupcause) {
+                q931cause = ast->hangupcause;
+        } else {
+                const char *cause = pbx_builtin_getvar_helper(ast, "DIALSTATUS");
+                if (cause) {
+                        if (!strcmp(cause, "CONGESTION")) {
+                                q931cause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+                        } else if (!strcmp(cause, "BUSY")) {
+                                q931cause = AST_CAUSE_USER_BUSY;
+                        } else if (!strcmp(cause, "CHANISUNVAIL")) {
+                                q931cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
+                        } else if (!strcmp(cause, "NOANSWER")) {
+                                q931cause = AST_CAUSE_NO_ANSWER;
+                        } else if (!strcmp(cause, "CANCEL")) {
+                                q931cause = AST_CAUSE_CALL_REJECTED;
+                        }
+                }
+        }
+
+
+
                if (gH323Debug)
-                       ast_verbose("    hanging %s\n", p->username);
+                       ast_verbose("    hanging %s with cause: %d\n", p->username, q931cause);
                ast->tech_pvt = NULL; 
                if (!ast_test_flag(p, H323_ALREADYGONE)) {
-                       ast_mutex_lock(&ooh323c_cmd_lock);
-                       ooHangCall(p->callToken, 
-                                ooh323_convert_hangupcause_asteriskToH323(p->owner->hangupcause));
-                       ast_mutex_unlock(&ooh323c_cmd_lock);
+                       ooHangCall(p->callToken, 
+                               ooh323_convert_hangupcause_asteriskToH323(q931cause), q931cause);
                        ast_set_flag(p, H323_ALREADYGONE);
                        /* ast_mutex_unlock(&p->lock); */
-               } else {
+               } else 
                        ast_set_flag(p, H323_NEEDDESTROY);
-               }
                /* detach channel here */
                if (p->owner) {
                        p->owner->tech_pvt = NULL;
                        p->owner = NULL;
+                       ast_module_unref(myself);
                }
 
                ast_mutex_unlock(&p->lock);
@@ -850,8 +1052,7 @@ static int ooh323_hangup(struct ast_channel *ast)
                ast_update_use_count();
          
        } else {
-               ast_log(LOG_ERROR, "No call to hangup\n" );
-               return -1;
+               ast_debug(1, "No call to hangup\n" );
        }
        
        if (gH323Debug)
@@ -863,21 +1064,37 @@ static int ooh323_hangup(struct ast_channel *ast)
 static int ooh323_answer(struct ast_channel *ast)
 {
        struct ooh323_pvt *p = ast->tech_pvt;
+       char *callToken = (char *)NULL;
 
        if (gH323Debug)
                ast_verbose("--- ooh323_answer\n");
 
-       ast_mutex_lock(&p->lock);
-       if (ast->_state != AST_STATE_UP) {
-               ast_channel_lock(ast);
-               ast_setstate(ast, AST_STATE_UP);
-               ast_debug(1, "ooh323_answer(%s)\n", ast->name);
-               ast_channel_unlock(ast);
-               ast_mutex_lock(&ooh323c_cmd_lock);
-               ooAnswerCall(p->callToken);
-               ast_mutex_unlock(&ooh323c_cmd_lock);
+       if (p) {
+
+               ast_mutex_lock(&p->lock);
+               callToken = (p->callToken ? strdup(p->callToken) : NULL);
+               if (ast->_state != AST_STATE_UP) {
+                       ast_channel_lock(ast);
+                       if (!p->alertsent) {
+                               if (gH323Debug) {
+                                       ast_debug(1, "Sending forced ringback for %s, res = %d\n", 
+                                               callToken, ooManualRingback(callToken));
+                               } else {
+                                       ooManualRingback(callToken);
+                               }
+                               p->alertsent = 1;
+                       }
+                       ast_setstate(ast, AST_STATE_UP);
+                       if (option_debug)
+                               ast_debug(1, "ooh323_answer(%s)\n", ast->name);
+                       ast_channel_unlock(ast);
+                       ooAnswerCall(p->callToken);
+               }
+               if (callToken) {
+                       free(callToken);
+               }
+               ast_mutex_unlock(&p->lock);
        }
-       ast_mutex_unlock(&p->lock);
 
        if (gH323Debug)
                ast_verbose("+++ ooh323_answer\n");
@@ -891,6 +1108,8 @@ static struct ast_frame *ooh323_read(struct ast_channel *ast)
        static struct ast_frame null_frame = { AST_FRAME_NULL, };
        struct ooh323_pvt *p = ast->tech_pvt;
 
+       if (!p) return &null_frame;
+
        ast_mutex_lock(&p->lock);
        if (p->rtp)
                fr = ooh323_rtp_read(ast, p);
@@ -905,27 +1124,63 @@ static int ooh323_write(struct ast_channel *ast, struct ast_frame *f)
 {
        struct ooh323_pvt *p = ast->tech_pvt;
        int res = 0;
+       char buf[256];
 
-       if (f->frametype == AST_FRAME_VOICE) {
-               if (!(f->subclass & ast->nativeformats)) {
-                       ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native "
-                                                                         "formats is %d (read/write = %d/%d)\n",
-                                                                       f->subclass, ast->nativeformats, ast->readformat,
-                                                                               ast->writeformat);
-                       return 0;
-               }
-               if (p) {
-                       ast_mutex_lock(&p->lock);
-                       if (p->rtp)
-                               res = ast_rtp_write(p->rtp, f);
+       if (p) {
+               ast_mutex_lock(&p->lock);
+
+               if (f->frametype == AST_FRAME_MODEM) {
+                       ast_debug(1, "Send UDPTL %d/%d len %d for %s\n",
+                               f->frametype, f->subclass.integer, f->datalen, ast->name);
+                       if (p->udptl)
+                               res = ast_udptl_write(p->udptl, f);
                        ast_mutex_unlock(&p->lock);
+                       return res;
                }
-       } else if (f->frametype == AST_FRAME_IMAGE) {
-               return 0;
-       } else {
-               ast_log(LOG_WARNING, "Can't send %d type frames with SIP write\n", 
+
+       
+               if (f->frametype == AST_FRAME_VOICE) {
+/* sending progress for first */
+                       if (!ast_test_flag(p, H323_OUTGOING) && !p->progsent &&
+                                       p->callToken) {
+                               ooManualProgress(p->callToken);
+                               p->progsent = 1;
+                       }
+
+
+                       if (!(ast_format_cap_iscompatible(ast->nativeformats, &f->subclass.format))) {
+                               if (!(ast_format_cap_is_empty(ast->nativeformats))) {
+                                       ast_log(LOG_WARNING,
+                                                       "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
+                                                       ast_getformatname(&f->subclass.format),
+                                                       ast_getformatname_multiple(buf, sizeof(buf), ast->nativeformats),
+                                                       ast_getformatname(&ast->readformat),
+                                                       ast_getformatname(&ast->writeformat));
+
+                                       ast_set_write_format(ast, &f->subclass.format);
+                               } else {
+                                       /* ast_set_write_format(ast, f->subclass);
+                                       ast->nativeformats = f->subclass; */
+                               }
+                       ast_mutex_unlock(&p->lock);
+                       return 0;
+                       }
+
+               if (p->rtp)
+                       res = ast_rtp_instance_write(p->rtp, f);
+
+               ast_mutex_unlock(&p->lock);
+
+               } else if (f->frametype == AST_FRAME_IMAGE) {
+                       ast_mutex_unlock(&p->lock);
+                       return 0;
+               } else {
+                       ast_log(LOG_WARNING, "Can't send %d type frames with OOH323 write\n", 
                                                                         f->frametype);
-               return 0;
+                       ast_mutex_unlock(&p->lock);
+                       return 0;
+               }
+
        }
 
        return res;
@@ -936,6 +1191,9 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d
 
        struct ooh323_pvt *p = (struct ooh323_pvt *) ast->tech_pvt;
        char *callToken = (char *)NULL;
+       int res = -1;
+
+       if (!p) return -1;
 
        ast_mutex_lock(&p->lock);
        callToken = (p->callToken ? strdup(p->callToken) : NULL);
@@ -950,33 +1208,147 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d
        if (gH323Debug)
                ast_verbose("----- ooh323_indicate %d on call %s\n", condition, callToken);
         
-
+       ast_mutex_lock(&p->lock);
        switch (condition) {
+       case AST_CONTROL_INCOMPLETE:
+               /* While h323 does support overlapped dialing, this channel driver does not
+                * at this time.  Treat a response of Incomplete as if it were congestion.
+                */
        case AST_CONTROL_CONGESTION:
                if (!ast_test_flag(p, H323_ALREADYGONE)) {
-                       ast_mutex_lock(&ooh323c_cmd_lock);
-                       ooHangCall(callToken, OO_REASON_LOCAL_CONGESTED);
-                       ast_mutex_unlock(&ooh323c_cmd_lock);
+                       ooHangCall(callToken, OO_REASON_LOCAL_CONGESTED, AST_CAUSE_SWITCH_CONGESTION);
                        ast_set_flag(p, H323_ALREADYGONE);
                }
                break;
        case AST_CONTROL_BUSY:
                if (!ast_test_flag(p, H323_ALREADYGONE)) {
-                       ast_mutex_lock(&ooh323c_cmd_lock);
-                       ooHangCall(callToken, OO_REASON_LOCAL_BUSY);
-                       ast_mutex_unlock(&ooh323c_cmd_lock);
+                       ooHangCall(callToken, OO_REASON_LOCAL_BUSY, AST_CAUSE_USER_BUSY);
                        ast_set_flag(p, H323_ALREADYGONE);
                }
                break;
        case AST_CONTROL_HOLD:
-               ast_moh_start(ast, data, NULL);         
+               ast_moh_start(ast, data, NULL);
                break;
        case AST_CONTROL_UNHOLD:
                ast_moh_stop(ast);
                break;
-       case AST_CONTROL_PROCEEDING:
-       case AST_CONTROL_RINGING:
        case AST_CONTROL_PROGRESS:
+               if (ast->_state != AST_STATE_UP) {
+                       if (!p->progsent) {
+                               if (gH323Debug) {
+                                       ast_debug(1, "Sending manual progress for %s, res = %d\n", callToken,
+                                       ooManualProgress(callToken));   
+                               } else {
+                                       ooManualProgress(callToken);
+                               }
+                               p->progsent = 1;
+                       }
+               }
+           break;
+      case AST_CONTROL_RINGING:
+               if (ast->_state == AST_STATE_RING || ast->_state == AST_STATE_RINGING) {
+                       if (!p->alertsent) {
+                               if (gH323Debug) {
+                                       ast_debug(1, "Sending manual ringback for %s, res = %d\n",
+                                               callToken,
+                                               ooManualRingback(callToken));
+                               } else {
+                                       ooManualRingback(callToken);
+                               }
+                               p->alertsent = 1;
+                       }
+                       p->alertsent = 1;
+               }
+        break;
+       case AST_CONTROL_SRCUPDATE:
+               if (p->rtp) {
+                       ast_rtp_instance_update_source(p->rtp);
+               }
+               break;
+       case AST_CONTROL_SRCCHANGE:
+               if (p->rtp) {
+                       ast_rtp_instance_change_source(p->rtp);
+               }
+               break;
+       case AST_CONTROL_CONNECTED_LINE:
+               if (!ast->connected.id.name.valid
+                       || ast_strlen_zero(ast->connected.id.name.str)) {
+                       break;
+               }
+               if (gH323Debug) {
+                       ast_debug(1, "Sending connected line info for %s (%s)\n",
+                               callToken, ast->connected.id.name.str);
+               }
+               ooSetANI(callToken, ast->connected.id.name.str);
+               break;
+
+      case AST_CONTROL_T38_PARAMETERS:
+               if (p->t38support != T38_ENABLED) {
+                       struct ast_control_t38_parameters parameters = { .request_response = 0 };
+                       parameters.request_response = AST_T38_REFUSED;
+                       ast_queue_control_data(ast, AST_CONTROL_T38_PARAMETERS,
+                                                &parameters, sizeof(parameters));
+                       break;
+               }
+               if (datalen != sizeof(struct ast_control_t38_parameters)) {
+                       ast_log(LOG_ERROR, "Invalid datalen for AST_CONTROL_T38. "
+                                          "Expected %d, got %d\n",
+                               (int)sizeof(enum ast_control_t38), (int)datalen);
+               } else {
+                       const struct ast_control_t38_parameters *parameters = data;
+                       struct ast_control_t38_parameters our_parameters;
+                       enum ast_control_t38 message = parameters->request_response;
+                       switch (message) {
+
+                       case AST_T38_NEGOTIATED:
+                               if (p->faxmode) {
+                                       res = 0;
+                                       break;
+                               }
+                       case AST_T38_REQUEST_NEGOTIATE:
+
+                               if (p->faxmode) {
+                                       /* T.38 already negotiated */
+                                       our_parameters.request_response = AST_T38_NEGOTIATED;
+                                       our_parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl);
+                                       our_parameters.rate = AST_T38_RATE_14400;
+                                       ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, &our_parameters, sizeof(our_parameters));
+                               } else if (!p->chmodepend) {
+                                       p->chmodepend = 1;
+                                       ooRequestChangeMode(p->callToken, 1);
+                                       res = 0;
+                               }
+                               break;
+
+                       case AST_T38_REQUEST_TERMINATE:
+
+                               if (!p->faxmode) {
+                                       /* T.38 already terminated */
+                                       our_parameters.request_response = AST_T38_TERMINATED;
+                                       ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, &our_parameters, sizeof(our_parameters));
+                               } else if (!p->chmodepend) {
+                                       p->chmodepend = 1;
+                                       ooRequestChangeMode(p->callToken, 0);
+                                       res = 0;
+                               }
+                               break;
+
+                       case AST_T38_REQUEST_PARMS:
+                               our_parameters.request_response = AST_T38_REQUEST_PARMS;
+                               our_parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl);
+                               our_parameters.rate = AST_T38_RATE_14400;
+                               ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, &our_parameters, sizeof(our_parameters));
+                               res = AST_T38_REQUEST_PARMS;
+                               break;
+
+                       default:
+                               ;
+
+                       }
+
+               }
+               break;
+      case AST_CONTROL_PROCEEDING:
        case -1:
                break;
        default:
@@ -984,17 +1356,83 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d
                                                                        condition, callToken);
        }
 
+       ast_mutex_unlock(&p->lock);
+
        if (gH323Debug)
                ast_verbose("++++  ooh323_indicate %d on %s\n", condition, callToken);
 
+       free(callToken);
+       return res;
+}
+
+static int ooh323_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
+{
+
+       struct ooh323_pvt *p = (struct ooh323_pvt *) ast->tech_pvt;
+       int res = -1;
+       enum ast_t38_state state = T38_STATE_UNAVAILABLE;
+       char* cp;
+
+       if (!p) return -1;
+
+       ast_mutex_lock(&p->lock);
+
+       if (gH323Debug)
+               ast_verbose("----- ooh323_queryoption %d on channel %s\n", option, ast->name);
+        
+       switch (option) {
+
+               case AST_OPTION_T38_STATE:
+
+                       if (*datalen != sizeof(enum ast_t38_state)) {
+                               ast_log(LOG_ERROR, "Invalid datalen for AST_OPTION_T38_STATE option."
+                               " Expected %d, got %d\n", (int)sizeof(enum ast_t38_state), *datalen);
+                               break;
+                       }
+
+                       if (p->t38support != T38_DISABLED) {
+                               if (p->faxmode) {
+                                       state = (p->chmodepend) ? T38_STATE_NEGOTIATING : T38_STATE_NEGOTIATED;
+                               } else {
+                                       state = T38_STATE_UNKNOWN;
+                               }
+                       }
+
+                       *((enum ast_t38_state *) data) = state;
+                       res = 0;
+                       break;
+
+
+               case AST_OPTION_DIGIT_DETECT:
+
+                       cp = (char *) data;
+                       *cp = p->vad ? 1 : 0;
+                       ast_debug(1, "Reporting digit detection %sabled on %s\n",
+                                                        *cp ? "en" : "dis", ast->name);
+
+                       res = 0;
+                       break;
+
+               default:        ;
+
+       }
+
+       if (gH323Debug)
+               ast_verbose("+++++ ooh323_queryoption %d on channel %s\n", option, ast->name);
+        
+       ast_mutex_unlock(&p->lock);
 
-       return -1;
+       return res;
 }
 
+
+
 static int ooh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 {
        struct ooh323_pvt *p = newchan->tech_pvt;
 
+       if (!p) return -1;
+
        if (gH323Debug)
                ast_verbose("--- ooh323c ooh323_fixup\n");
 
@@ -1020,15 +1458,14 @@ static int ooh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan
 }
 
 
-void ooh323_set_write_format(ooCallData *call, int fmt)
+void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txframes)
 {
-#if 0
        struct ooh323_pvt *p = NULL;
-       char formats[512];
-#ifdef print_debug
-       printf("---   ooh323_update_writeformat %s\n", 
-                                                                               ast_getformatname_multiple(formats,512, fmt));
-#endif
+       char formats[FORMAT_STRING_SIZE];
+
+       if (gH323Debug)
+               ast_verbose("---   ooh323_update_writeformat %s/%d\n", 
+                               ast_getformatname(fmt), txframes);
        
        p = find_call(call);
        if (!p) {
@@ -1038,35 +1475,56 @@ void ooh323_set_write_format(ooCallData *call, int fmt)
 
        ast_mutex_lock(&p->lock);
 
-       p->writeformat = fmt;
-       ast_mutex_unlock(&p->lock);
+       ast_format_copy(&(p->writeformat), fmt);
 
        if (p->owner) {
-         printf("Writeformat before update %s\n", 
-                                 ast_getformatname_multiple(formats,512, p->owner->writeformat));
-         ast_set_write_format(p->owner, fmt);
-       }
-       else
-         ast_log(LOG_ERROR, "No owner found\n");
+               while (p->owner && ast_channel_trylock(p->owner)) {
+                       ast_debug(1,"Failed to grab lock, trying again\n");
+                       DEADLOCK_AVOIDANCE(&p->lock);
+               }
+               if (!p->owner) {
+                       ast_mutex_unlock(&p->lock);
+                       ast_log(LOG_ERROR, "Channel has no owner\n");
+                       return;
+               }
+               if (gH323Debug)
+                       ast_verbose("Writeformat before update %s/%s\n", 
+                         ast_getformatname(&p->owner->writeformat),
+                         ast_getformatname_multiple(formats, sizeof(formats), p->owner->nativeformats));
+               if (txframes)
+                       ast_codec_pref_setsize(&p->prefs, fmt, txframes);
+               ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &p->prefs);
+               if (p->dtmfmode & H323_DTMF_RFC2833 && p->dtmfcodec) {
+                       ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp),
+                                p->rtp, p->dtmfcodec, "audio", "telephone-event", 0);
+               }
+               if (p->dtmfmode & H323_DTMF_CISCO && p->dtmfcodec) {
+                       ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp),
+                                p->rtp, p->dtmfcodec, "audio", "cisco-telephone-event", 0);
+               }
 
+               ast_format_cap_set(p->owner->nativeformats, fmt);
+               ast_set_write_format(p->owner, &p->owner->writeformat);
+               ast_set_read_format(p->owner, &p->owner->readformat);
+               ast_channel_unlock(p->owner);
+       } else
+               ast_log(LOG_ERROR, "No owner found\n");
 
-#ifdef print_debug
-  printf("+++   ooh323_update_writeformat\n");
-#endif
-#endif
-}
 
+       ast_mutex_unlock(&p->lock);
+
+       if (gH323Debug)
+               ast_verbose("+++   ooh323_update_writeformat\n");
+}
 
-void ooh323_set_read_format(ooCallData *call, int fmt)
+void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt)
 {
-#if 0
        struct ooh323_pvt *p = NULL;
-       char formats[512];
-#ifdef print_debug
-       printf("---   ooh323_update_readformat %s\n", 
-                                                                                       ast_getformatname_multiple(formats,512, fmt));
-#endif
 
+       if (gH323Debug)
+               ast_verbose("---   ooh323_update_readformat %s\n", 
+                               ast_getformatname(fmt));
+       
        p = find_call(call);
        if (!p) {
                ast_log(LOG_ERROR, "No matching call found for %s\n", call->callToken);
@@ -1074,49 +1532,85 @@ void ooh323_set_read_format(ooCallData *call, int fmt)
        }
 
        ast_mutex_lock(&p->lock);
-       p->readformat = fmt;
-       ast_mutex_unlock(&p->lock);
-       ast_set_read_format(p->owner, fmt);     
-       
-#ifdef print_debug
-  printf("+++   ooh323_update_readformat\n");
-#endif
-#endif
-}
-
-int onAlerting(ooCallData *call)
-{
-       struct ooh323_pvt *p = NULL;
-       struct ast_channel *c = NULL;
 
-       if (gH323Debug)
-               ast_verbose("--- onAlerting %s\n", call->callToken);
+       ast_format_copy(&(p->readformat), fmt);
 
-       if (!(p = find_call(call))) {
-               ast_log(LOG_ERROR, "No matching call found\n");
-               return -1;
-       }  
-       ast_mutex_lock(&p->lock);
-       if (!ast_test_flag(p, H323_OUTGOING)) {
-               if (!(c = ooh323_new(p, AST_STATE_RING, p->username))) {
-                       ast_mutex_unlock(&p->lock);
-                       ast_log(LOG_ERROR, "Could not create ast_channel\n");
-                       return -1;
+       if (p->owner) {
+               while (p->owner && ast_channel_trylock(p->owner)) {
+                       ast_debug(1,"Failed to grab lock, trying again\n");
+                       DEADLOCK_AVOIDANCE(&p->lock);
                }
-               ast_mutex_unlock(&p->lock);
-       } else {
                if (!p->owner) {
                        ast_mutex_unlock(&p->lock);
                        ast_log(LOG_ERROR, "Channel has no owner\n");
-                       return 0;
+                       return;
                }
-               c = p->owner;
+
+               if (gH323Debug)
+                       ast_verbose("Readformat before update %s\n", 
+                                 ast_getformatname(&p->owner->readformat));
+               ast_format_cap_set(p->owner->nativeformats, fmt);
+               ast_set_read_format(p->owner, &p->owner->readformat);
+               ast_channel_unlock(p->owner);
+       } else
+               ast_log(LOG_ERROR, "No owner found\n");
+
+       ast_mutex_unlock(&p->lock);
+
+       if (gH323Debug)
+               ast_verbose("+++   ooh323_update_readformat\n");
+}
+
+
+int onAlerting(ooCallData *call)
+{
+       struct ooh323_pvt *p = NULL;
+       struct ast_channel *c = NULL;
+
+       if (gH323Debug)
+               ast_verbose("--- onAlerting %s\n", call->callToken);
+
+       p = find_call(call);
+
+       if(!p) {
+               ast_log(LOG_ERROR, "No matching call found\n");
+               return -1;
+       }  
+       ast_mutex_lock(&p->lock);
+       if (!p->owner) {
                ast_mutex_unlock(&p->lock);
-               ast_channel_lock(c);
-               ast_setstate(c, AST_STATE_RINGING);
-               ast_channel_unlock(c);
-               ast_queue_control(c, AST_CONTROL_RINGING);
+               ast_log(LOG_ERROR, "Channel has no owner\n");
+               return 0;
+       }
+       while (p->owner && ast_channel_trylock(p->owner)) {
+               ast_debug(1, "Failed to grab lock, trying again\n");
+               DEADLOCK_AVOIDANCE(&p->lock);
+       }
+       if (!p->owner) {
+               ast_mutex_unlock(&p->lock);
+               ast_log(LOG_ERROR, "Channel has no owner\n");
+               return 0;
+       }
+       c = p->owner;
+
+       if (call->remoteDisplayName) {
+               struct ast_party_connected_line connected;
+               struct ast_set_party_connected_line update_connected;
+
+               memset(&update_connected, 0, sizeof(update_connected));
+               update_connected.id.name = 1;
+               ast_party_connected_line_init(&connected);
+               connected.id.name.valid = 1;
+               connected.id.name.str = (char *) call->remoteDisplayName;
+               connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+               ast_channel_queue_connected_line_update(c, &connected, &update_connected);
        }
+       if (c->_state != AST_STATE_UP)
+               ast_setstate(c, AST_STATE_RINGING);
+
+       ast_queue_control(c, AST_CONTROL_RINGING);
+       ast_channel_unlock(c);
+       ast_mutex_unlock(&p->lock);
 
        if (gH323Debug)
                ast_verbose("+++ onAlerting %s\n", call->callToken);
@@ -1124,6 +1618,62 @@ int onAlerting(ooCallData *call)
        return OO_OK;
 }
 
+int onProgress(ooCallData *call)
+{
+       struct ooh323_pvt *p = NULL;
+       struct ast_channel *c = NULL;
+
+       if (gH323Debug)
+               ast_verbose("--- onProgress %s\n", call->callToken);
+
+       p = find_call(call);
+
+       if(!p) {
+               ast_log(LOG_ERROR, "No matching call found\n");
+               return -1;
+       }  
+       ast_mutex_lock(&p->lock);
+       if (!p->owner) {
+               ast_mutex_unlock(&p->lock);
+               ast_log(LOG_ERROR, "Channel has no owner\n");
+               return 0;
+       }
+       while (p->owner && ast_channel_trylock(p->owner)) {
+               ast_debug(1, "Failed to grab lock, trying again\n");
+               DEADLOCK_AVOIDANCE(&p->lock);
+       }
+       if (!p->owner) {
+               ast_mutex_unlock(&p->lock);
+               ast_log(LOG_ERROR, "Channel has no owner\n");
+               return 0;
+       }
+       c = p->owner;
+
+       if (call->remoteDisplayName) {
+               struct ast_party_connected_line connected;
+               struct ast_set_party_connected_line update_connected;
+
+               memset(&update_connected, 0, sizeof(update_connected));
+               update_connected.id.name = 1;
+               ast_party_connected_line_init(&connected);
+               connected.id.name.valid = 1;
+               connected.id.name.str = (char *) call->remoteDisplayName;
+               connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+               ast_channel_queue_connected_line_update(c, &connected, &update_connected);
+       }
+       if (c->_state != AST_STATE_UP)
+               ast_setstate(c, AST_STATE_RINGING);
+
+       ast_queue_control(c, AST_CONTROL_PROGRESS);
+       ast_channel_unlock(c);
+       ast_mutex_unlock(&p->lock);
+
+       if (gH323Debug)
+               ast_verbose("+++ onProgress %s\n", call->callToken);
+
+       return OO_OK;
+}
+
 /**
   * Callback for sending digits from H.323 up to asterisk
   *
@@ -1147,15 +1697,26 @@ int ooh323_onReceivedDigit(OOH323CallData *call, const char *digit)
        ast_mutex_lock(&p->lock);
        memset(&f, 0, sizeof(f));
        f.frametype = AST_FRAME_DTMF;
-       f.subclass = digit[0];
+       f.subclass.integer = digit[0];
        f.datalen = 0;
        f.samples = 800;
        f.offset = 0;
        f.data.ptr = NULL;
        f.mallocd = 0;
        f.src = "SEND_DIGIT";
-       ast_mutex_unlock(&p->lock);
+
+       while (p->owner && ast_channel_trylock(p->owner)) {
+               ast_debug(1, "Failed to grab lock, trying again\n");
+               DEADLOCK_AVOIDANCE(&p->lock);
+       }
+       if (!p->owner) {
+               ast_mutex_unlock(&p->lock);
+               ast_log(LOG_ERROR, "Channel has no owner\n");
+               return 0;
+       }
        res = ast_queue_frame(p->owner, &f);
+       ast_channel_unlock(p->owner);
+       ast_mutex_unlock(&p->lock);
        return res;
 }
 
@@ -1163,6 +1724,7 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg)
 {
        struct ooh323_pvt *p = NULL;
        struct ooh323_user *user = NULL;
+       struct ast_channel *c = NULL;
        ooAliases *alias = NULL;
        char *at = NULL;
        char number [OO_MAX_NUMBER_LENGTH];
@@ -1194,30 +1756,35 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg)
                                        p->callerid_name = strdup(alias->value);
                                }
                                ast_copy_string(p->caller_h323id, alias->value, sizeof(p->caller_h323id));
-                       } else if (alias->type == T_H225AliasAddress_dialedDigits) {
-                               if (!p->callerid_num) {
-                                       p->callerid_num = strdup(alias->value);
                                }
+         else if(alias->type == T_H225AliasAddress_dialedDigits)
+         {
+            if(!p->callerid_num)
+               p->callerid_num = strdup(alias->value);
                                ast_copy_string(p->caller_dialedDigits, alias->value, 
                                                                                                                        sizeof(p->caller_dialedDigits));
-                       } else if (alias->type == T_H225AliasAddress_email_ID) {
+         }
+         else if(alias->type == T_H225AliasAddress_email_ID)
+         {
                                ast_copy_string(p->caller_email, alias->value, sizeof(p->caller_email));
-                       } else if (alias->type == T_H225AliasAddress_url_ID) {
+         }
+         else if(alias->type == T_H225AliasAddress_url_ID)
+         {
                                ast_copy_string(p->caller_url, alias->value, sizeof(p->caller_url));
                        }
                }
        }
 
        number[0] = '\0';
-       if (ooCallGetCalledPartyNumber(call, number, OO_MAX_NUMBER_LENGTH) == OO_OK) {
-               ast_copy_string(p->exten, number, sizeof(p->exten));
-       } else {
+       if(ooCallGetCalledPartyNumber(call, number, OO_MAX_NUMBER_LENGTH)== OO_OK) {
+               strncpy(p->exten, number, sizeof(p->exten)-1);
+       } else {
                update_our_aliases(call, p);
                if (!ast_strlen_zero(p->callee_dialedDigits)) {
-                       ast_copy_string(p->exten, p->callee_dialedDigits, sizeof(p->exten));
-               } else if (!ast_strlen_zero(p->callee_h323id)) {
+                       ast_copy_string(p->exten, p->callee_dialedDigits, sizeof(p->exten));
+               } else if(!ast_strlen_zero(p->callee_h323id)) {
                        ast_copy_string(p->exten, p->callee_h323id, sizeof(p->exten));
-               } else if (!ast_strlen_zero(p->callee_email)) {
+               } else if(!ast_strlen_zero(p->callee_email)) {
                        ast_copy_string(p->exten, p->callee_email, sizeof(p->exten));
                        if ((at = strchr(p->exten, '@'))) {
                                *at = '\0';
@@ -1227,33 +1794,85 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg)
 
        /* if no extension found, set to default 's' */
        if (ast_strlen_zero(p->exten)) {
-               ast_copy_string(p->exten, "s", sizeof(p->exten));
+               p->exten[0]='s';
+               p->exten[1]='\0';
        }
 
-       if (!p->callerid_name) {
-               p->callerid_name = strdup(call->remoteIP);
-       }
-       
-       if (p->callerid_name) {
-               if ((user = find_user(p->callerid_name, call->remoteIP))) {
-                       ast_mutex_lock(&user->lock);
-                       p->username = strdup(user->name);
-                       ast_copy_string(p->context, user->context, sizeof(p->context));
-                       ast_copy_string(p->accountcode, user->accountcode, sizeof(p->accountcode));
-                       p->amaflags = user->amaflags;
-                       p->capability = user->capability;
-                       memcpy(&p->prefs, &user->prefs, sizeof(struct ast_codec_pref));
-                       p->dtmfmode = user->dtmfmode;
-                       /* Since, call is coming from a pbx user, no need to use gk */
-                       OO_SETFLAG(p->flags, H323_DISABLEGK);
-                       OO_SETFLAG(call->flags, OO_M_DISABLEGK);
-                       ast_mutex_unlock(&user->lock);
+       user = find_user(p->callerid_name, call->remoteIP);
+       if(user && (user->incominglimit == 0 || user->inUse < user->incominglimit)) {
+               ast_mutex_lock(&user->lock);
+               p->username = strdup(user->name);
+               p->neighbor.user = user->mUseIP ? ast_strdup(user->mIP) :
+                                                 ast_strdup(user->name);
+               ast_copy_string(p->context, user->context, sizeof(p->context));
+               ast_copy_string(p->accountcode, user->accountcode, sizeof(p->accountcode));
+               p->amaflags = user->amaflags;
+               ast_format_cap_copy(p->cap, user->cap);
+               p->g729onlyA = user->g729onlyA;
+               memcpy(&p->prefs, &user->prefs, sizeof(struct ast_codec_pref));
+               p->dtmfmode |= user->dtmfmode;
+               p->dtmfcodec = user->dtmfcodec;
+               p->faxdetect = user->faxdetect;
+               p->t38support = user->t38support;
+               p->rtptimeout = user->rtptimeout;
+               p->h245tunneling = user->h245tunneling;
+               p->faststart = user->faststart;
+
+               if (p->faststart)
+                       OO_SETFLAG(call->flags, OO_M_FASTSTART);
+               else
+                       OO_CLRFLAG(call->flags, OO_M_FASTSTART);
+               /* if we disable h245tun for this user then we clear flag */
+               /* in any other case we don't must touch this */
+               /* ie if we receive setup without h245tun but enabled
+                                               we can't enable it per call */
+               if (!p->h245tunneling)
+                       OO_CLRFLAG(call->flags, OO_M_TUNNELING);
+
+               if (user->rtpmask && user->rtpmaskstr[0]) {
+                       p->rtpmask = user->rtpmask;
+                       ast_copy_string(p->rtpmaskstr, user->rtpmaskstr, 
+                                                        sizeof(p->rtpmaskstr));
+               }
+               if (user->rtdrcount > 0 && user->rtdrinterval > 0) {
+                       p->rtdrcount = user->rtdrcount;
+                       p->rtdrinterval = user->rtdrinterval;
                }
+               if (user->incominglimit) user->inUse++;
+               ast_mutex_unlock(&user->lock);
+       } else {
+        if (!OO_TESTFLAG(p->flags,H323_DISABLEGK)) {
+               p->username = strdup(call->remoteIP);
+       } else {
+         ast_mutex_unlock(&p->lock);
+         ast_log(LOG_ERROR, "Unacceptable ip %s\n", call->remoteIP);
+         if (!user) {
+          ooHangCall(call->callToken, ooh323_convert_hangupcause_asteriskToH323(AST_CAUSE_CALL_REJECTED), AST_CAUSE_CALL_REJECTED);
+          call->callEndReason = OO_REASON_REMOTE_REJECTED;
+         }
+         else {
+          ooHangCall(call->callToken, ooh323_convert_hangupcause_asteriskToH323(AST_CAUSE_NORMAL_CIRCUIT_CONGESTION), AST_CAUSE_NORMAL_CIRCUIT_CONGESTION);
+          call->callEndReason = OO_REASON_REMOTE_REJECTED;
+         }
+         ast_set_flag(p, H323_NEEDDESTROY);
+         return -1;
+        }
        }
 
-
-       ooh323c_set_capability_for_call(call, &p->prefs, p->capability, p->dtmfmode);
-       configure_local_rtp(p, call);
+       ooh323c_set_capability_for_call(call, &p->prefs, p->cap, p->dtmfmode, p->dtmfcodec,
+                                        p->t38support, p->g729onlyA);
+/* Incoming call */
+       c = ooh323_new(p, AST_STATE_RING, p->username, 0, NULL);
+       if(!c) {
+       ast_mutex_unlock(&p->lock);
+       ast_log(LOG_ERROR, "Could not create ast_channel\n");
+         return -1;
+       }
+       if (!configure_local_rtp(p, call)) {
+               ast_mutex_unlock(&p->lock);
+               ast_log(LOG_ERROR, "Couldn't create rtp structure\n");
+               return -1;
+       }
 
        ast_mutex_unlock(&p->lock);
 
@@ -1266,38 +1885,117 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg)
 
 
 
-int onNewCallCreated(ooCallData *call)
+int onOutgoingCall(ooCallData *call)
 {
        struct ooh323_pvt *p = NULL;
        int i = 0;
 
        if (gH323Debug)
-               ast_verbose("---   onNewCallCreated %s\n", call->callToken);
+               ast_verbose("---   onOutgoingCall %lx: %s\n", (long unsigned int) call, call->callToken);
 
        if (!strcmp(call->callType, "outgoing")) {
                p = find_call(call);
                if (!p) {
-                       ast_log(LOG_ERROR, "No matching call found for outgoing call\n");
+                       ast_log(LOG_ERROR, "Failed to find a matching call.\n");
                        return -1;
                }
                ast_mutex_lock(&p->lock);
-               if (p->callerid_name) {
+
+               if (!ast_strlen_zero(p->callerid_name)) {
                        ooCallSetCallerId(call, p->callerid_name);
                }
-               if (p->callerid_num) {
+               if (!ast_strlen_zero(p->callerid_num)) {
                        i = 0;
                        while (*(p->callerid_num + i) != '\0') {
-                               if (!isdigit(*(p->callerid_num + i))) {
-                                       break;
-                               }
+                               if(!isdigit(*(p->callerid_num+i))) { break; }
                                i++;
                        }
-                       if (*(p->callerid_num + i) == '\0') {
+                       if(*(p->callerid_num+i) == '\0')
                                ooCallSetCallingPartyNumber(call, p->callerid_num);
-                       } else {
-                               if (!p->callerid_name) {
+                       else {
+                               if(!p->callerid_name)
                                        ooCallSetCallerId(call, p->callerid_num);
+                       }
+               }
+               
+               if (!ast_strlen_zero(p->caller_h323id))
+                       ooCallAddAliasH323ID(call, p->caller_h323id);
+
+               if (!ast_strlen_zero(p->caller_dialedDigits)) {
+                       if (gH323Debug) {
+                               ast_verbose("Setting dialed digits %s\n", p->caller_dialedDigits);
+                       }
+                       ooCallAddAliasDialedDigits(call, p->caller_dialedDigits);
+               } else if (!ast_strlen_zero(p->callerid_num)) {
+                       if (ooIsDailedDigit(p->callerid_num)) {
+                               if (gH323Debug) {
+                                       ast_verbose("setting callid number %s\n", p->callerid_num);
                                }
+                               ooCallAddAliasDialedDigits(call, p->callerid_num);
+                       } else if (ast_strlen_zero(p->caller_h323id)) {
+                               ooCallAddAliasH323ID(call, p->callerid_num);
+                       }
+               }
+               if (p->rtpmask && p->rtpmaskstr[0]) {
+                       call->rtpMask = p->rtpmask;
+                       ast_mutex_lock(&call->rtpMask->lock);
+                       call->rtpMask->inuse++;
+                       ast_mutex_unlock(&call->rtpMask->lock);
+                       ast_copy_string(call->rtpMaskStr, p->rtpmaskstr, sizeof(call->rtpMaskStr));
+               }
+
+               if (!configure_local_rtp(p, call)) {
+                       ast_mutex_unlock(&p->lock);
+                       return OO_FAILED;
+               }
+
+               ast_mutex_unlock(&p->lock);
+       }
+
+       if (gH323Debug)
+               ast_verbose("+++   onOutgoingCall %s\n", call->callToken);
+       return OO_OK;
+}
+
+
+int onNewCallCreated(ooCallData *call)
+{
+       struct ooh323_pvt *p = NULL;
+       int i = 0;
+
+       if (gH323Debug)
+               ast_verbose("---   onNewCallCreated %lx: %s\n", (long unsigned int) call, call->callToken);
+
+       ast_mutex_lock(&call->Lock);
+       if (ooh323c_start_call_thread(call)) {
+               ast_log(LOG_ERROR,"Failed to create call thread.\n");
+               ast_mutex_unlock(&call->Lock);
+               return -1;
+       }
+
+       if (!strcmp(call->callType, "outgoing")) {
+               p = find_call(call);
+               if (!p) {
+                       ast_log(LOG_ERROR, "Failed to find a matching call.\n");
+                       ast_mutex_unlock(&call->Lock);
+                       return -1;
+               }
+               ast_mutex_lock(&p->lock);
+
+               if (!ast_strlen_zero(p->callerid_name)) {
+                       ooCallSetCallerId(call, p->callerid_name);
+               }
+               if (!ast_strlen_zero(p->callerid_num)) {
+                       i = 0;
+                       while (*(p->callerid_num + i) != '\0') {
+                               if(!isdigit(*(p->callerid_num+i))) { break; }
+                               i++;
+                       }
+                       if(*(p->callerid_num+i) == '\0')
+                               ooCallSetCallingPartyNumber(call, p->callerid_num);
+                       else {
+                               if(ast_strlen_zero(p->callerid_name))
+                                       ooCallSetCallerId(call, p->callerid_num);
                        }
                }
                
@@ -1309,7 +2007,7 @@ int onNewCallCreated(ooCallData *call)
                                ast_verbose("Setting dialed digits %s\n", p->caller_dialedDigits);
                        }
                        ooCallAddAliasDialedDigits(call, p->caller_dialedDigits);
-               } else if (p->callerid_num) {
+               } else if (!ast_strlen_zero(p->callerid_num)) {
                        if (ooIsDailedDigit(p->callerid_num)) {
                                if (gH323Debug) {
                                        ast_verbose("setting callid number %s\n", p->callerid_num);
@@ -1334,17 +2032,19 @@ int onNewCallCreated(ooCallData *call)
                        char prefsBuf[256];
                        ast_codec_pref_string(&p->prefs, prefsBuf, sizeof(prefsBuf));
                        ast_verbose(" Outgoing call %s(%s) - Codec prefs - %s\n", 
-                                                 p->username?p->username:"NULL", call->callToken, prefsBuf);
+                               p->username?p->username:"NULL", call->callToken, prefsBuf);
                }
 
-               ooh323c_set_capability_for_call(call, &p->prefs, p->capability, p->dtmfmode);
+               ooh323c_set_capability_for_call(call, &p->prefs, p->cap,
+                                     p->dtmfmode, p->dtmfcodec, p->t38support, p->g729onlyA);
 
-               configure_local_rtp(p, call);
+               /* configure_local_rtp(p, call); */
                ast_mutex_unlock(&p->lock);
        }
+
+       ast_mutex_unlock(&call->Lock);
        if (gH323Debug)
                ast_verbose("+++   onNewCallCreated %s\n", call->callToken);
-
        return OO_OK;
 }
 
@@ -1355,33 +2055,47 @@ int onCallEstablished(ooCallData *call)
        if (gH323Debug)
                ast_verbose("---   onCallEstablished %s\n", call->callToken);
 
+
        if (!(p = find_call(call))) {
                ast_log(LOG_ERROR, "Failed to find a matching call.\n");
                return -1;
        }
-       ast_mutex_lock(&p->lock);
-       if (!p->owner) {
-               ast_mutex_unlock(&p->lock);
-               ast_log(LOG_ERROR, "Channel has no owner\n");
-               return -1;
-       }
-       
-       while (ast_channel_trylock(p->owner)) {
-               ast_debug(1,"Failed to grab lock, trying again\n");
-               ast_mutex_unlock(&p->lock);
-               usleep(1);
+
+       if(ast_test_flag(p, H323_OUTGOING)) {
                ast_mutex_lock(&p->lock);
-       }        
-       if (p->owner->_state != AST_STATE_UP) {
-               ast_setstate(p->owner, AST_STATE_UP);
-       }
-       ast_channel_unlock(p->owner);
-       if (ast_test_flag(p, H323_OUTGOING)) {
-               struct ast_channel* c = p->owner;
-               ast_mutex_unlock(&p->lock);
-               ast_queue_control(c, AST_CONTROL_ANSWER);
-       } else {
+               if (!p->owner) {
+                       ast_mutex_unlock(&p->lock);
+                       ast_log(LOG_ERROR, "Channel has no owner\n");
+                       return -1;
+               }
+       
+               while (p->owner && ast_channel_trylock(p->owner)) {
+                       ast_debug(1, "Failed to grab lock, trying again\n");
+                       DEADLOCK_AVOIDANCE(&p->lock);
+               }
+               if (p->owner) {
+                       struct ast_channel* c = p->owner;
+
+                       if (call->remoteDisplayName) {
+                               struct ast_party_connected_line connected;
+                               struct ast_set_party_connected_line update_connected;
+
+                               memset(&update_connected, 0, sizeof(update_connected));
+                               update_connected.id.name = 1;
+                               ast_party_connected_line_init(&connected);
+                               connected.id.name.valid = 1;
+                               connected.id.name.str = (char *) call->remoteDisplayName;
+                               connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+                               ast_channel_queue_connected_line_update(c, &connected, &update_connected);
+                       }
+
+                       ast_queue_control(c, AST_CONTROL_ANSWER);
+                       ast_channel_unlock(p->owner);
+                       manager_event(EVENT_FLAG_SYSTEM,"ChannelUpdate","Channel: %s\r\nChanneltype: %s\r\n"
+                               "CallRef: %d\r\n", c->name, "OOH323", p->call_reference);
+               }
                ast_mutex_unlock(&p->lock);
+
        }
 
        if (gH323Debug)
@@ -1398,42 +2112,47 @@ int onCallCleared(ooCallData *call)
        if (gH323Debug)
                ast_verbose("---   onCallCleared %s \n", call->callToken);
 
-       p = find_call(call); 
-       if (!p) {
-               return 0;
-       }
+
+   if ((p = find_call(call))) {
        ast_mutex_lock(&p->lock);
   
        while (p->owner) {
                if (ast_channel_trylock(p->owner)) {
                        ooTrace(OOTRCLVLINFO, "Failed to grab lock, trying again\n");
-                       ast_debug(1,"Failed to grab lock, trying again\n");
-                       ast_mutex_unlock(&p->lock);
-                       usleep(1);
-                       ast_mutex_lock(&p->lock);
+                       ast_debug(1, "Failed to grab lock, trying again\n");
+                       DEADLOCK_AVOIDANCE(&p->lock);
                } else {
-                       ownerLock = 1;
-                       break;
+                       ownerLock = 1; break;
                }
        }
 
        if (ownerLock) {
                if (!ast_test_flag(p, H323_ALREADYGONE)) { 
 
-                       /* NOTE: Channel is not detached yet */
                        ast_set_flag(p, H323_ALREADYGONE);
-                       p->owner->hangupcause = 
-                               ooh323_convert_hangupcause_h323ToAsterisk(call->callEndReason);
+                       p->owner->hangupcause = call->q931cause;
                        p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
-                       ast_channel_unlock(p->owner);
-                       ast_queue_hangup(p->owner);
-                       ast_mutex_unlock(&p->lock);
-                       return OO_OK;
+                       ast_queue_hangup_with_cause(p->owner,call->q931cause);
                }
+       }
+
+       if(p->owner) {
+               p->owner->tech_pvt = NULL;
                ast_channel_unlock(p->owner);
+               p->owner = NULL;
+               ast_module_unref(myself);
        }
+
        ast_set_flag(p, H323_NEEDDESTROY);
+
+       ooh323c_stop_call_thread(call);
+
        ast_mutex_unlock(&p->lock);
+       ast_mutex_lock(&usecnt_lock);
+       usecnt--;
+       ast_mutex_unlock(&usecnt_lock);
+
+    }
 
        if (gH323Debug)
                ast_verbose("+++   onCallCleared\n");
@@ -1441,8 +2160,7 @@ int onCallCleared(ooCallData *call)
        return OO_OK;
 }
 
-#if 0
-static void ooh323_delete_user(struct ooh323_user *user)
+/* static void ooh323_delete_user(struct ooh323_user *user)
 {
        struct ooh323_user *prev = NULL, *cur = NULL;
 
@@ -1472,8 +2190,7 @@ static void ooh323_delete_user(struct ooh323_user *user)
        if (gH323Debug)
                ast_verbose("+++   ooh323_delete_user\n");
 
-}
-#endif
+} */
 
 void ooh323_delete_peer(struct ooh323_peer *peer)
 {
@@ -1483,36 +2200,34 @@ void ooh323_delete_peer(struct ooh323_peer *peer)
                ast_verbose("---   ooh323_delete_peer\n");
 
        if (peer) {     
+      cur = peerl.peers;
                ast_mutex_lock(&peerl.lock);
-               for (cur = peerl.peers; cur; prev = cur, cur = cur->next) {
-                       if (cur == peer) {
-                               break;
-                       }
+      while(cur) {
+         if(cur==peer) break;
+         prev = cur;
+         cur = cur->next;
                }
 
                if (cur) {
-                       if (prev) {
+         if(prev)
                                prev->next = cur->next;
-                       } else {
+         else
                                peerl.peers = cur->next;
                        }
-               }
                ast_mutex_unlock(&peerl.lock);
 
-               if (peer->h323id)
-                       free(peer->h323id);
-               if (peer->email)
-                       free(peer->email);
-               if (peer->url)
-                       free(peer->url);
-               if (peer->e164)
-                       free(peer->e164);
+      if(peer->h323id)   free(peer->h323id);
+      if(peer->email)    free(peer->email);
+      if(peer->url)      free(peer->url);
+      if(peer->e164)     free(peer->e164);
 
+               peer->cap = ast_format_cap_destroy(peer->cap);
                free(peer);
        }  
 
        if (gH323Debug)
                ast_verbose("+++   ooh323_delete_peer\n");
+
 }
 
 
@@ -1524,14 +2239,25 @@ static struct ooh323_user *build_user(const char *name, struct ast_variable *v)
        if (gH323Debug)
                ast_verbose("---   build_user\n");
 
-       user = ast_calloc(1, sizeof(*user));
+       user = ast_calloc(1,sizeof(struct ooh323_user));
        if (user) {
+               memset(user, 0, sizeof(struct ooh323_user));
+               if (!(user->cap = ast_format_cap_alloc())) {
+                       ast_free(user);
+                       return NULL;
+               }
                ast_mutex_init(&user->lock);
                ast_copy_string(user->name, name, sizeof(user->name));
-               user->capability = gCapability;
+               ast_format_cap_copy(user->cap, gCap);
                memcpy(&user->prefs, &gPrefs, sizeof(user->prefs));
                user->rtptimeout = gRTPTimeout;
                user->dtmfmode = gDTMFMode;
+               user->dtmfcodec = gDTMFCodec;
+               user->faxdetect = gFAXdetect;
+               user->t38support = gT38Support;
+               user->faststart = gFastStart;
+               user->h245tunneling = gTunneling;
+               user->g729onlyA = g729onlyA;
                /* set default context */
                ast_copy_string(user->context, gContext, sizeof(user->context));
                ast_copy_string(user->accountcode, gAccountcode, sizeof(user->accountcode));
@@ -1545,35 +2271,95 @@ static struct ooh323_user *build_user(const char *name, struct ast_variable *v)
                                if (user->incominglimit < 0)
                                        user->incominglimit = 0;
                        } else if (!strcasecmp(v->name, "accountcode")) {
-                               ast_copy_string(user->accountcode, v->value, sizeof(user->accountcode));
+                               strncpy(user->accountcode, v->value, 
+                                               sizeof(user->accountcode)-1);
+                       } else if (!strcasecmp(v->name, "roundtrip")) {
+                               sscanf(v->value, "%d,%d", &user->rtdrcount, &user->rtdrinterval);
+                       } else if (!strcasecmp(v->name, "faststart")) {
+                               user->faststart = ast_true(v->value);
+                       } else if (!strcasecmp(v->name, "h245tunneling")) {
+                               user->h245tunneling = ast_true(v->value);
+                       } else if (!strcasecmp(v->name, "g729onlyA")) {
+                               user->g729onlyA = ast_true(v->value);
                        } else if (!strcasecmp(v->name, "rtptimeout")) {
                                user->rtptimeout = atoi(v->value);
                                if (user->rtptimeout < 0)
                                        user->rtptimeout = gRTPTimeout;
+                       } else if (!strcasecmp(v->name, "rtpmask")) {
+                               if ((user->rtpmask = ast_calloc(1, sizeof(struct OOH323Regex))) &&
+                                       (regcomp(&user->rtpmask->regex, v->value, REG_EXTENDED) 
+                                                                                       == 0)) {
+                                       ast_mutex_init(&user->rtpmask->lock);
+                                       user->rtpmask->inuse = 1;
+                                       ast_copy_string(user->rtpmaskstr, v->value, 
+                                                               sizeof(user->rtpmaskstr));
+                               } else user->rtpmask = NULL;
                        } else if (!strcasecmp(v->name, "disallow")) {
-                               ast_parse_allow_disallow(&user->prefs, &user->capability, 
-                                                                                                v->value, 0);
+                               ast_parse_allow_disallow(&user->prefs, 
+                                       user->cap,  v->value, 0);
                        } else if (!strcasecmp(v->name, "allow")) {
                                const char* tcodecs = v->value;
                                if (!strcasecmp(v->value, "all")) {
                                        tcodecs = "ulaw,alaw,g729,g723,gsm";
                                }
-                               ast_parse_allow_disallow(&user->prefs, &user->capability, 
-                                                                                                tcodecs, 1);
+                               ast_parse_allow_disallow(&user->prefs,
+                                        user->cap,  tcodecs, 1);
                        } else if (!strcasecmp(v->name, "amaflags")) {
                                user->amaflags = ast_cdr_amaflags2int(v->value);
-                       } else if (!strcasecmp(v->name, "ip")) {
-                               ast_copy_string(user->mIP, v->value, sizeof(user->mIP));
-                               user->mUseIP = 1;
-                       } else if (!strcasecmp(v->name, "dtmfmode")) {
+                       } else if (!strcasecmp(v->name, "ip") || !strcasecmp(v->name, "host")) {
+                               struct ast_sockaddr p;
+                               if (!ast_parse_arg(v->value, PARSE_ADDR, &p)) {
+                                       ast_copy_string(user->mIP, ast_sockaddr_stringify_addr(&p), sizeof(user->mIP)-1);
+                               } else {        
+                                       ast_copy_string(user->mIP, v->value, sizeof(user->mIP)-1);
+                               }
+                               user->mUseIP = 1;
+                       } else if (!strcasecmp(v->name, "dtmfmode")) {
                                if (!strcasecmp(v->value, "rfc2833"))
                                        user->dtmfmode = H323_DTMF_RFC2833;
+                               if (!strcasecmp(v->value, "cisco"))
+                                       user->dtmfmode = H323_DTMF_CISCO;
                                else if (!strcasecmp(v->value, "q931keypad"))
                                        user->dtmfmode = H323_DTMF_Q931;
                                else if (!strcasecmp(v->value, "h245alphanumeric"))
                                        user->dtmfmode = H323_DTMF_H245ALPHANUMERIC;
                                else if (!strcasecmp(v->value, "h245signal"))
                                        user->dtmfmode = H323_DTMF_H245SIGNAL;
+                               else if (!strcasecmp(v->value, "inband"))
+                                       user->dtmfmode = H323_DTMF_INBAND;
+                       } else if (!strcasecmp(v->name, "relaxdtmf")) {
+                               user->dtmfmode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0;
+                       } else if (!strcasecmp(v->name, "dtmfcodec") && atoi(v->value)) {
+                               user->dtmfcodec = atoi(v->value);
+                       } else if (!strcasecmp(v->name, "faxdetect")) {
+                               if (ast_true(v->value)) {
+                                       user->faxdetect = FAXDETECT_CNG | FAXDETECT_T38;
+                               } else if (ast_false(v->value)) {
+                                       user->faxdetect = 0;
+                               } else {
+                                       char *buf = ast_strdupa(v->value);
+                                       char *word, *next = buf;
+                                       user->faxdetect = 0;
+                                       while ((word = strsep(&next, ","))) {
+                                               if (!strcasecmp(word, "cng")) {
+                                                       user->faxdetect |= FAXDETECT_CNG;
+                                               } else if (!strcasecmp(word, "t38")) {
+                                                       user->faxdetect |= FAXDETECT_T38;
+                                               } else {
+                                                       ast_log(LOG_WARNING, "Unknown faxdetect mode '%s' on line %d.\n", word, v->lineno);
+                                               }
+                                       }
+
+                               }
+                       } else if (!strcasecmp(v->name, "t38support")) {
+                               if (!strcasecmp(v->value, "disabled"))
+                                       user->t38support = T38_DISABLED;
+                               if (!strcasecmp(v->value, "no"))
+                                       user->t38support = T38_DISABLED;
+                               else if (!strcasecmp(v->value, "faxgw"))
+                                       user->t38support = T38_FAXGW;
+                               else if (!strcasecmp(v->value, "yes"))
+                                       user->t38support = T38_ENABLED;
                        }
                        v = v->next;
                }
@@ -1595,21 +2381,32 @@ static struct ooh323_peer *build_peer(const char *name, struct ast_variable *v,
        peer = ast_calloc(1, sizeof(*peer));
        if (peer) {
                memset(peer, 0, sizeof(struct ooh323_peer));
+               if (!(peer->cap = ast_format_cap_alloc())) {
+                       ast_free(peer);
+                       return NULL;
+               }
                ast_mutex_init(&peer->lock);
                ast_copy_string(peer->name, name, sizeof(peer->name));
-               peer->capability = gCapability;
-               memcpy(&peer->prefs, &gPrefs, sizeof(struct ast_codec_pref));
+               ast_format_cap_copy(peer->cap, gCap);
+               memcpy(&peer->prefs, &gPrefs, sizeof(peer->prefs));
                peer->rtptimeout = gRTPTimeout;
                ast_copy_string(peer->accountcode, gAccountcode, sizeof(peer->accountcode));
                peer->amaflags = gAMAFLAGS;
                peer->dtmfmode = gDTMFMode;
+               peer->dtmfcodec = gDTMFCodec;
+               peer->faxdetect = gFAXdetect;
+               peer->t38support = gT38Support;
+               peer->faststart = gFastStart;
+               peer->h245tunneling = gTunneling;
+               peer->g729onlyA = g729onlyA;
+               peer->port = 1720;
                if (0 == friend_type) {
                        peer->mFriend = 1;
                }
 
                while (v) {
                        if (!strcasecmp(v->name, "h323id")) {
-                               if (!(peer->h323id = ast_strdup(v->value))) {
+           if (!(peer->h323id = ast_strdup(v->value))) {
                                        ast_log(LOG_ERROR, "Could not allocate memory for h323id of "
                                                                                         "peer %s\n", name);
                                        ooh323_delete_peer(peer);
@@ -1638,39 +2435,99 @@ static struct ooh323_peer *build_peer(const char *name, struct ast_variable *v,
                                }
                        } else if (!strcasecmp(v->name, "port")) {
                                peer->port = atoi(v->value);
-                       } else if (!strcasecmp(v->name, "ip")) {
-                               ast_copy_string(peer->ip, v->value, sizeof(peer->ip));
+                       } else if (!strcasecmp(v->name, "host") || !strcasecmp(v->name, "ip")) {
+                               struct ast_sockaddr p;
+                               if (!ast_parse_arg(v->value, PARSE_ADDR, &p)) {
+                                       ast_copy_string(peer->ip, ast_sockaddr_stringify_host(&p), sizeof(peer->ip));
+                               } else {        
+                                       ast_copy_string(peer->ip, v->value, sizeof(peer->ip));
+                               }
+                       
                        } else if (!strcasecmp(v->name, "outgoinglimit")) {
-                               if ((peer->outgoinglimit = atoi(v->value)) < 0) {
+                               peer->outgoinglimit = atoi(v->value);
+                               if (peer->outgoinglimit < 0)
                                        peer->outgoinglimit = 0;
-                               }
                        } else if (!strcasecmp(v->name, "accountcode")) {
                                ast_copy_string(peer->accountcode, v->value, sizeof(peer->accountcode));
+                       } else if (!strcasecmp(v->name, "faststart")) {
+                               peer->faststart = ast_true(v->value);
+                       } else if (!strcasecmp(v->name, "h245tunneling")) {
+                               peer->h245tunneling = ast_true(v->value);
+                       } else if (!strcasecmp(v->name, "g729onlyA")) {
+                               peer->g729onlyA = ast_true(v->value);
                        } else if (!strcasecmp(v->name, "rtptimeout")) {
-                               if ((peer->rtptimeout = atoi(v->value)) < 0) {
+                               peer->rtptimeout = atoi(v->value);
+                               if(peer->rtptimeout < 0)
                                        peer->rtptimeout = gRTPTimeout;
-                               }
+                       } else if (!strcasecmp(v->name, "rtpmask")) {
+                               if ((peer->rtpmask = ast_calloc(1, sizeof(struct OOH323Regex))) &&
+                                       (regcomp(&peer->rtpmask->regex, v->value, REG_EXTENDED) 
+                                                                                       == 0)) {
+                                       ast_mutex_init(&peer->rtpmask->lock);
+                                       peer->rtpmask->inuse = 1;
+                                       ast_copy_string(peer->rtpmaskstr, v->value, 
+                                                               sizeof(peer->rtpmaskstr));
+                               } else peer->rtpmask = NULL;
                        } else if (!strcasecmp(v->name, "disallow")) {
-                               ast_parse_allow_disallow(&peer->prefs, &peer->capability, 
+                               ast_parse_allow_disallow(&peer->prefs, peer->cap, 
                                                                                                 v->value, 0); 
                        } else if (!strcasecmp(v->name, "allow")) {
                                const char* tcodecs = v->value;
                                if (!strcasecmp(v->value, "all")) {
                                        tcodecs = "ulaw,alaw,g729,g723,gsm";
                                }
-                               ast_parse_allow_disallow(&peer->prefs, &peer->capability, 
+                               ast_parse_allow_disallow(&peer->prefs, peer->cap, 
                                                                                                 tcodecs, 1);                            
                        } else if (!strcasecmp(v->name,  "amaflags")) {
                                peer->amaflags = ast_cdr_amaflags2int(v->value);
+                       } else if (!strcasecmp(v->name, "roundtrip")) {
+                               sscanf(v->value, "%d,%d", &peer->rtdrcount, &peer->rtdrinterval);
                        } else if (!strcasecmp(v->name, "dtmfmode")) {
                                if (!strcasecmp(v->value, "rfc2833"))
                                        peer->dtmfmode = H323_DTMF_RFC2833;
+                               if (!strcasecmp(v->value, "cisco"))
+                                       peer->dtmfmode = H323_DTMF_CISCO;
                                else if (!strcasecmp(v->value, "q931keypad"))
                                        peer->dtmfmode = H323_DTMF_Q931;
                                else if (!strcasecmp(v->value, "h245alphanumeric"))
                                        peer->dtmfmode = H323_DTMF_H245ALPHANUMERIC;
                                else if (!strcasecmp(v->value, "h245signal"))
                                        peer->dtmfmode = H323_DTMF_H245SIGNAL;
+                               else if (!strcasecmp(v->value, "inband"))
+                                       peer->dtmfmode = H323_DTMF_INBAND;
+                       } else if (!strcasecmp(v->name, "relaxdtmf")) {
+                               peer->dtmfmode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0;
+                       } else if (!strcasecmp(v->name, "dtmfcodec") && atoi(v->value)) {
+                               peer->dtmfcodec = atoi(v->value);
+                       } else if (!strcasecmp(v->name, "faxdetect")) {
+                               if (ast_true(v->value)) {
+                                       peer->faxdetect = FAXDETECT_CNG | FAXDETECT_T38;
+                               } else if (ast_false(v->value)) {
+                                       peer->faxdetect = 0;
+                               } else {
+                                       char *buf = ast_strdupa(v->value);
+                                       char *word, *next = buf;
+                                       peer->faxdetect = 0;
+                                       while ((word = strsep(&next, ","))) {
+                                               if (!strcasecmp(word, "cng")) {
+                                                       peer->faxdetect |= FAXDETECT_CNG;
+                                               } else if (!strcasecmp(word, "t38")) {
+                                                       peer->faxdetect |= FAXDETECT_T38;
+                                               } else {
+                                                       ast_log(LOG_WARNING, "Unknown faxdetect mode '%s' on line %d.\n", word, v->lineno);
+                                               }
+                                       }
+
+                               }
+                       } else if (!strcasecmp(v->name, "t38support")) {
+                               if (!strcasecmp(v->value, "disabled"))
+                                       peer->t38support = T38_DISABLED;
+                               if (!strcasecmp(v->value, "no"))
+                                       peer->t38support = T38_DISABLED;
+                               else if (!strcasecmp(v->value, "faxgw"))
+                                       peer->t38support = T38_FAXGW;
+                               else if (!strcasecmp(v->value, "yes"))
+                                       peer->t38support = T38_ENABLED;
                        }
                        v = v->next;
                }
@@ -1688,7 +2545,7 @@ static int ooh323_do_reload(void)
                ast_verbose("---   ooh323_do_reload\n");
        }
 
-       reload_config(1);
+       reload_config(1);
 
        if (gH323Debug) {
                ast_verbose("+++   ooh323_do_reload\n");
@@ -1697,19 +2554,32 @@ static int ooh323_do_reload(void)
        return 0;
 }
 
-#if 0
 /*--- h323_reload: Force reload of module from cli ---*/
-static int ooh323_reload(int fd, int argc, char *argv[])
+
+char *handle_cli_ooh323_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 
+       switch (cmd) {
+       case CLI_INIT:
+               e->command = "ooh323 reload";
+               e->usage =
+                       "Usage: ooh323 reload\n"
+                       "                Reload OOH323 config.\n";
+               return NULL;
+       case CLI_GENERATE:
+               return NULL;
+       }
+
+       if (a->argc != 2)
+               return CLI_SHOWUSAGE;
+
        if (gH323Debug)
                ast_verbose("---   ooh323_reload\n");
 
        ast_mutex_lock(&h323_reload_lock);
        if (h323_reloading) {
                ast_verbose("Previous OOH323 reload not yet done\n");
-       } 
-       else {
+   } else {
                h323_reloading = 1;
        }
        ast_mutex_unlock(&h323_reload_lock);
@@ -1720,19 +2590,11 @@ static int ooh323_reload(int fd, int argc, char *argv[])
 
        return 0;
 }
-#endif
-
-#if 0
-static int reload(void *mod)
-{
-       return ooh323_reload(0, 0, NULL);
-}
-#endif
 
 int reload_config(int reload)
 {
        int format;
-       struct ooAliases  *pNewAlias = NULL;
+       struct ooAliases  *pNewAlias = NULL, *cur, *prev;
        struct ast_config *cfg;
        struct ast_variable *v;
        struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
@@ -1740,6 +2602,7 @@ int reload_config(int reload)
        struct ooh323_peer *peer = NULL;
        char *cat;
        const char *utype;
+       struct ast_format tmpfmt;
 
        if (gH323Debug)
                ast_verbose("---   reload_config\n");
@@ -1756,6 +2619,17 @@ int reload_config(int reload)
        if (reload) {
                delete_users();
                delete_peers();
+               if (gH323Debug) {
+                       ast_verbose("  reload_config - Freeing up alias list\n");
+               }
+               cur = gAliasList;
+               while (cur) {
+                       prev = cur;
+                       cur = cur->next;
+                       free(prev->value);
+                       free(prev);
+               }
+               gAliasList = NULL;
        }
 
        /* Inintialize everything to default */
@@ -1763,12 +2637,18 @@ int reload_config(int reload)
        gPort = 1720;
        gIP[0] = '\0';
        strcpy(gCallerID, DEFAULT_H323ID);
-       gCapability = AST_FORMAT_ULAW;
+       ast_format_cap_set(gCap, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
        memset(&gPrefs, 0, sizeof(struct ast_codec_pref));
        gDTMFMode = H323_DTMF_RFC2833;
+       gDTMFCodec = 101;
+       gFAXdetect = FAXDETECT_CNG;
+       gT38Support = T38_FAXGW;
+       gTRCLVL = OOTRCLVLERR;
        gRasGkMode = RasNoGatekeeper;
        gGatekeeper[0] = '\0';
        gRTPTimeout = 60;
+       gRTDRInterval = 0;
+       gRTDRCount = 0;
        strcpy(gAccountcode, DEFAULT_H323ACCNT);
        gFastStart = 1;
        gTunneling = 1;
@@ -1778,17 +2658,30 @@ int reload_config(int reload)
        gMediaWaitForConnect = 0;
        ooconfig.mTCPPortStart = 12030;
        ooconfig.mTCPPortEnd = 12230;
+       memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
 
        v = ast_variable_browse(cfg, "general");
        while (v) {
+
+               if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
+                       v = v->next;
+                       continue;
+               }
        
                if (!strcasecmp(v->name, "port")) {
                        gPort = (int)strtol(v->value, NULL, 10);
                } else if (!strcasecmp(v->name, "bindaddr")) {
                        ast_copy_string(gIP, v->value, sizeof(gIP));
+                       if (ast_parse_arg(v->value, PARSE_ADDR, &bindaddr)) {
+                               ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
+                               return 1;
+                       }
+                       if (ast_sockaddr_is_ipv6(&bindaddr)) {
+                               v6mode = 1;
+                       }
                } else if (!strcasecmp(v->name, "h225portrange")) {
                        char* endlimit = 0;
-                       char temp[256];
+                       char temp[512];
                        ast_copy_string(temp, v->value, sizeof(temp));
                        endlimit = strchr(temp, ',');
                        if (endlimit) {
@@ -1797,16 +2690,12 @@ int reload_config(int reload)
                                ooconfig.mTCPPortStart = atoi(temp);
                                ooconfig.mTCPPortEnd = atoi(endlimit);
 
-                               if (ooH323EpSetTCPPortRange(ooconfig.mTCPPortStart, 
-                                                                                                       ooconfig.mTCPPortEnd) == OO_FAILED) {
-                                       ast_log(LOG_ERROR, "h225portrange: Failed to set range\n");
-                               }
                        } else {
                                ast_log(LOG_ERROR, "h225portrange: Invalid format, separate port range with \",\"\n");
                        }
                } else if (!strcasecmp(v->name, "gateway")) {
                        gIsGateway = ast_true(v->value);
-               } else if (!strcasecmp(v->name, "faststart")) {
+               } else if (!strcasecmp(v->name, "faststart")) {
                        gFastStart = ast_true(v->value);
                        if (gFastStart)
                                ooH323EpEnableFastStart();
@@ -1824,19 +2713,32 @@ int reload_config(int reload)
                                ooH323EpEnableH245Tunneling();
                        else
                                ooH323EpDisableH245Tunneling();
+               } else if (!strcasecmp(v->name, "g729onlyA")) {
+                       g729onlyA = ast_true(v->value);
+               } else if (!strcasecmp(v->name, "roundtrip")) {
+                       sscanf(v->value, "%d,%d", &gRTDRCount, &gRTDRInterval);
+               } else if (!strcasecmp(v->name, "trybemaster")) {
+                       gBeMaster = ast_true(v->value);
+                       if (gBeMaster)
+                               ooH323EpTryBeMaster(1);
+                       else 
+                               ooH323EpTryBeMaster(0);
                } else if (!strcasecmp(v->name, "h323id")) {
-                       pNewAlias = malloc(sizeof(*pNewAlias));
+                       pNewAlias = ast_calloc(1, sizeof(struct ooAliases));
                        if (!pNewAlias) {
                                ast_log(LOG_ERROR, "Failed to allocate memory for h323id alias\n");
                                return 1;
                        }
+                       if (gAliasList == NULL) { /* first h323id - set as callerid if callerid is not set */
+                               ast_copy_string(gCallerID, v->value, sizeof(gCallerID));
+                       }
                        pNewAlias->type =  T_H225AliasAddress_h323_ID;
                        pNewAlias->value = strdup(v->value);
                        pNewAlias->next = gAliasList;
                        gAliasList = pNewAlias;
                        pNewAlias = NULL;
                } else if (!strcasecmp(v->name, "e164")) {
-                       pNewAlias = malloc(sizeof(*pNewAlias));
+                       pNewAlias = ast_calloc(1, sizeof(struct ooAliases));
                        if (!pNewAlias) {
                                ast_log(LOG_ERROR, "Failed to allocate memory for e164 alias\n");
                                return 1;
@@ -1847,7 +2749,7 @@ int reload_config(int reload)
                        gAliasList = pNewAlias;
                        pNewAlias = NULL;
                } else if (!strcasecmp(v->name, "email")) {
-                       pNewAlias = malloc(sizeof(*pNewAlias));
+                       pNewAlias = ast_calloc(1, sizeof(struct ooAliases));
                        if (!pNewAlias) {
                                ast_log(LOG_ERROR, "Failed to allocate memory for email alias\n");
                                return 1;
@@ -1857,6 +2759,16 @@ int reload_config(int reload)
                        pNewAlias->next = gAliasList;
                        gAliasList = pNewAlias;
                        pNewAlias = NULL;
+      } else if (!strcasecmp(v->name, "t35country")) {
+         t35countrycode = atoi(v->value);
+      } else if (!strcasecmp(v->name, "t35extensions")) {
+         t35extensions = atoi(v->value);
+      } else if (!strcasecmp(v->name, "manufacturer")) {
+         manufacturer = atoi(v->value);
+      } else if (!strcasecmp(v->name, "vendorid")) {
+         ast_copy_string(vendor, v->value, sizeof(vendor));
+      } else if (!strcasecmp(v->name, "versionid")) {
+         ast_copy_string(version, v->value, sizeof(version));
                } else if (!strcasecmp(v->name, "callerid")) {
                        ast_copy_string(gCallerID, v->value, sizeof(gCallerID));
                } else if (!strcasecmp(v->name, "incominglimit")) {
@@ -1870,19 +2782,20 @@ int reload_config(int reload)
                                gRasGkMode = RasDiscoverGatekeeper;
                        } else {
                                gRasGkMode = RasUseSpecificGatekeeper;
-                               ast_copy_string(gGatekeeper, v->value, sizeof(gGatekeeper));
+                               strncpy(gGatekeeper, v->value, sizeof(gGatekeeper)-1);
                        }
                } else if (!strcasecmp(v->name, "logfile")) {
-                       ast_copy_string(gLogFile, v->value, sizeof(gLogFile));
+         strncpy(gLogFile, v->value, sizeof(gLogFile)-1);
                } else if (!strcasecmp(v->name, "context")) {
-                       ast_copy_string(gContext, v->value, sizeof(gContext));
-                       ast_verb(3, "  == Setting default context to %s\n", gContext);
+         strncpy(gContext, v->value, sizeof(gContext)-1);
+         ast_verbose(VERBOSE_PREFIX_3 "  == Setting default context to %s\n", 
+                                                      gContext);
                } else if (!strcasecmp(v->name, "rtptimeout")) {
                        gRTPTimeout = atoi(v->value);
                        if (gRTPTimeout <= 0)
                                gRTPTimeout = 60;
                } else if (!strcasecmp(v->name, "tos")) {
-                       if (sscanf(v->value, "%i", &format) == 1)
+                       if (sscanf(v->value, "%30i", &format) == 1)
                                gTOS = format & 0xff;
                        else if (!strcasecmp(v->value, "lowdelay"))
                                gTOS = IPTOS_LOWDELAY;
@@ -1901,20 +2814,22 @@ int reload_config(int reload)
                } else if (!strcasecmp(v->name, "amaflags")) {
                        gAMAFLAGS = ast_cdr_amaflags2int(v->value);
                } else if (!strcasecmp(v->name, "accountcode")) {
-                       ast_copy_string(gAccountcode, v->value, sizeof(gAccountcode)-1);
+         ast_copy_string(gAccountcode, v->value, sizeof(gAccountcode));
                } else if (!strcasecmp(v->name, "disallow")) {
-                       ast_parse_allow_disallow(&gPrefs, &gCapability, v->value, 0);
+                       ast_parse_allow_disallow(&gPrefs, gCap, v->value, 0);
                } else if (!strcasecmp(v->name, "allow")) {
                        const char* tcodecs = v->value;
                        if (!strcasecmp(v->value, "all")) {
                                tcodecs = "ulaw,alaw,g729,g723,gsm";
                        }
-                       ast_parse_allow_disallow(&gPrefs, &gCapability, tcodecs, 1);
+                       ast_parse_allow_disallow(&gPrefs, gCap, tcodecs, 1);
                } else if (!strcasecmp(v->name, "dtmfmode")) {
                        if (!strcasecmp(v->value, "inband"))
                                gDTMFMode = H323_DTMF_INBAND;
                        else if (!strcasecmp(v->value, "rfc2833"))
                                gDTMFMode = H323_DTMF_RFC2833;
+                       else if (!strcasecmp(v->value, "cisco"))
+                               gDTMFMode = H323_DTMF_CISCO;
                        else if (!strcasecmp(v->value, "q931keypad"))
                                gDTMFMode = H323_DTMF_Q931;
                        else if (!strcasecmp(v->value, "h245alphanumeric"))
@@ -1922,10 +2837,47 @@ int reload_config(int reload)
                        else if (!strcasecmp(v->value, "h245signal"))
                                gDTMFMode = H323_DTMF_H245SIGNAL;
                        else {
-                               ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value);
+            ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", 
+                                                                    v->value);
                                gDTMFMode = H323_DTMF_RFC2833;
                        }
-               }  
+               } else if (!strcasecmp(v->name, "relaxdtmf")) {
+                       gDTMFMode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0;
+               } else if (!strcasecmp(v->name, "dtmfcodec") && atoi(v->value)) {
+                       gDTMFCodec = atoi(v->value);
+               } else if (!strcasecmp(v->name, "faxdetect")) {
+                       if (ast_true(v->value)) {
+                               gFAXdetect = FAXDETECT_CNG | FAXDETECT_T38;
+                       } else if (ast_false(v->value)) {
+                               gFAXdetect = 0;
+                       } else {
+                               char *buf = ast_strdupa(v->value);
+                               char *word, *next = buf;
+                               gFAXdetect = 0;
+                               while ((word = strsep(&next, ","))) {
+                                       if (!strcasecmp(word, "cng")) {
+                                               gFAXdetect |= FAXDETECT_CNG;
+                                       } else if (!strcasecmp(word, "t38")) {
+                                               gFAXdetect |= FAXDETECT_T38;
+                                       } else {
+                                               ast_log(LOG_WARNING, "Unknown faxdetect mode '%s' on line %d.\n", word, v->lineno);
+                                       }
+                               }
+
+                       }
+               } else if (!strcasecmp(v->name, "t38support")) {
+                       if (!strcasecmp(v->value, "disabled"))
+                               gT38Support = T38_DISABLED;
+                       if (!strcasecmp(v->value, "no"))
+                               gT38Support = T38_DISABLED;
+                       else if (!strcasecmp(v->value, "faxgw"))
+                               gT38Support = T38_FAXGW;
+                       else if (!strcasecmp(v->value, "yes"))
+                               gT38Support = T38_ENABLED;
+               } else if (!strcasecmp(v->name, "tracelevel")) {
+                       gTRCLVL = atoi(v->value);
+                       ooH323EpSetTraceLevel(gTRCLVL);
+               }
                v = v->next;
        }
        
@@ -1966,7 +2918,7 @@ int reload_config(int reload)
        /* Determine ip address if neccessary */
        if (ast_strlen_zero(gIP)) {
                ooGetLocalIPAddress(gIP);
-               if (!strcmp(gIP, "127.0.0.1")) {
+               if (!strcmp(gIP, "127.0.0.1") || !strcmp(gIP, "::1")) {
                        ast_log(LOG_NOTICE, "Failed to determine local ip address. Please "
                                                                         "specify it in ooh323.conf. OOH323 Disabled\n");
                        return 1;
@@ -1977,8 +2929,10 @@ int reload_config(int reload)
                ast_verbose("+++   reload_config\n");
 
        return 0;
+
 }
 
+
 static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
        char ip_port[30];
@@ -2002,9 +2956,9 @@ static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struc
        peer = peerl.peers;
        while (peer) {
                ast_mutex_lock(&peer->lock);
-               if (!strcmp(peer->name, a->argv[3]))
+               if (!strcmp(peer->name, a->argv[3])) {
                        break;
-               else {
+               } else {
                        prev = peer;
                        peer = peer->next;
                        ast_mutex_unlock(&prev->lock);
@@ -2012,28 +2966,60 @@ static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struc
        }
 
        if (peer) {
-               snprintf(ip_port, sizeof(ip_port), "%s:%d", peer->ip, peer->port);
+               sprintf(ip_port, "%s:%d", peer->ip, peer->port);
                ast_cli(a->fd, "%-15.15s%s\n", "Name: ", peer->name);
+               ast_cli(a->fd, "%s:%s,%s\n", "FastStart/H.245 Tunneling", peer->faststart?"yes":"no",
+                                       peer->h245tunneling?"yes":"no");
                ast_cli(a->fd, "%-15.15s%s", "Format Prefs: ", "(");
                print_codec_to_cli(a->fd, &peer->prefs);
                ast_cli(a->fd, ")\n");
                ast_cli(a->fd, "%-15.15s", "DTMF Mode: ");
-               if (peer->dtmfmode & H323_DTMF_RFC2833)
+               if (peer->dtmfmode & H323_DTMF_CISCO) {
+                       ast_cli(a->fd, "%s\n", "cisco");
+                       ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", peer->dtmfcodec);
+               } else if (peer->dtmfmode & H323_DTMF_RFC2833) {
                        ast_cli(a->fd, "%s\n", "rfc2833");
-               else if (peer->dtmfmode & H323_DTMF_Q931)
+                       ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", peer->dtmfcodec);
+               } else if (peer->dtmfmode & H323_DTMF_Q931) {
                        ast_cli(a->fd, "%s\n", "q931keypad");
-               else if (peer->dtmfmode & H323_DTMF_H245ALPHANUMERIC)
+               } else if (peer->dtmfmode & H323_DTMF_H245ALPHANUMERIC) {
                        ast_cli(a->fd, "%s\n", "h245alphanumeric");
-               else if (peer->dtmfmode & H323_DTMF_H245SIGNAL)
+               } else if (peer->dtmfmode & H323_DTMF_H245SIGNAL) {
                        ast_cli(a->fd, "%s\n", "h245signal");
-               else
+               } else if (peer->dtmfmode & H323_DTMF_INBAND && peer->dtmfmode & H323_DTMF_INBANDRELAX) {
+                       ast_cli(a->fd, "%s\n", "inband-relaxed");
+               } else if (peer->dtmfmode & H323_DTMF_INBAND) {
+                       ast_cli(a->fd, "%s\n", "inband");
+               } else {
                        ast_cli(a->fd, "%s\n", "unknown");
+               }
+               ast_cli(a->fd,"%-15s", "T.38 Mode: ");
+               if (peer->t38support == T38_DISABLED) {
+                       ast_cli(a->fd, "%s\n", "disabled");
+               } else if (peer->t38support == T38_FAXGW) {
+                       ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible");
+               }
+               if (peer->faxdetect == (FAXDETECT_CNG | FAXDETECT_T38)) {
+                       ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Yes");
+               } else if (peer->faxdetect & FAXDETECT_CNG) {
+                       ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Cng");
+               } else if (peer->faxdetect & FAXDETECT_T38) {
+                       ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "T.38");
+               } else {
+                       ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "No");
+               }
+
                ast_cli(a->fd, "%-15.15s%s\n", "AccountCode: ", peer->accountcode);
-               ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ",
-               ast_cdr_flags2str(peer->amaflags));
-               ast_cli(a->fd, "%-15.15s%s\n", "Ip:Port: ", ip_port);
+               ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ", ast_cdr_flags2str(peer->amaflags));
+               ast_cli(a->fd, "%-15.15s%s\n", "IP:Port: ", ip_port);
                ast_cli(a->fd, "%-15.15s%d\n", "OutgoingLimit: ", peer->outgoinglimit);
                ast_cli(a->fd, "%-15.15s%d\n", "rtptimeout: ", peer->rtptimeout);
+               if (peer->rtpmaskstr[0]) {
+                       ast_cli(a->fd, "%-15.15s%s\n", "rtpmask: ", peer->rtpmaskstr);
+               }
+               if (peer->rtdrcount && peer->rtdrinterval) {
+                       ast_cli(a->fd, "%-15.15s%d,%d\n", "RoundTrip: ", peer->rtdrcount, peer->rtdrinterval);
+               }
                ast_mutex_unlock(&peer->lock);
        } else {
                ast_cli(a->fd, "Peer %s not found\n", a->argv[3]);
@@ -2046,10 +3032,9 @@ static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struc
 
 static char *handle_cli_ooh323_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-       char ip_port[30];
-       char formats[512];
        struct ooh323_peer *prev = NULL, *peer = NULL;
-
+   char formats[FORMAT_STRING_SIZE];
+   char ip_port[30];
 #define FORMAT  "%-15.15s  %-15.15s  %-23.23s  %-s\n"
 
        switch (cmd) {
@@ -2066,40 +3051,39 @@ static char *handle_cli_ooh323_show_peers(struct ast_cli_entry *e, int cmd, stru
        if (a->argc != 3)
                return CLI_SHOWUSAGE;
 
-       ast_cli(a->fd, FORMAT, "Name", "Accountcode", "ip:port", "Formats");
+   ast_cli(a->fd, FORMAT, "Name", "Accountcode", "ip:port", "Formats");
 
        ast_mutex_lock(&peerl.lock);
        peer = peerl.peers;
        while (peer) {
                ast_mutex_lock(&peer->lock);
                snprintf(ip_port, sizeof(ip_port), "%s:%d", peer->ip, peer->port);
-               ast_cli(a->fd, FORMAT, peer->name,
+     ast_cli(a->fd, FORMAT, peer->name, 
                                        peer->accountcode,
                                        ip_port,
-                                       ast_getformatname_multiple(formats, sizeof(formats), peer->capability));
+                 ast_getformatname_multiple(formats,FORMAT_STRING_SIZE,peer->cap));
                prev = peer;
                peer = peer->next;
                ast_mutex_unlock(&prev->lock);
+
        }
        ast_mutex_unlock(&peerl.lock);
-
 #undef FORMAT
-
        return CLI_SUCCESS;
 }
 
 /*! \brief Print codec list from preference to CLI/manager */
 static void print_codec_to_cli(int fd, struct ast_codec_pref *pref)
 {
-       int x, codec;
-
+       int x;
+       struct ast_format tmpfmt;
        for (x = 0; x < 32; x++) {
-               codec = ast_codec_pref_index(pref, x);
-               if (!codec)
+               ast_codec_pref_index(pref, x, &tmpfmt);
+               if (!tmpfmt.id)
                        break;
-               ast_cli(fd, "%s", ast_getformatname(codec));
+               ast_cli(fd, "%s", ast_getformatname(&tmpfmt));
                ast_cli(fd, ":%d", pref->framing[x]);
-               if (x < 31 && ast_codec_pref_index(pref, x + 1))
+               if (x < 31 && ast_codec_pref_index(pref, x + 1, &tmpfmt))
                        ast_cli(fd, ",");
        }
        if (!x)
@@ -2124,13 +3108,14 @@ static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struc
        if (a->argc != 4)
                return CLI_SHOWUSAGE;
 
+
        ast_mutex_lock(&userl.lock);
        user = userl.users;
        while (user) {
                ast_mutex_lock(&user->lock);
-               if (!strcmp(user->name, a->argv[3]))
+               if (!strcmp(user->name, a->argv[3])) {
                        break;
-               else {
+               } else {
                        prev = user;
                        user = user->next;
                        ast_mutex_unlock(&prev->lock);
@@ -2139,26 +3124,60 @@ static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struc
 
        if (user) {
                ast_cli(a->fd, "%-15.15s%s\n", "Name: ", user->name);
+               ast_cli(a->fd, "%s:%s,%s\n", "FastStart/H.245 Tunneling", user->faststart?"yes":"no",
+                                       user->h245tunneling?"yes":"no");
                ast_cli(a->fd, "%-15.15s%s", "Format Prefs: ", "(");
                print_codec_to_cli(a->fd, &user->prefs);
                ast_cli(a->fd, ")\n");
                ast_cli(a->fd, "%-15.15s", "DTMF Mode: ");
-               if (user->dtmfmode & H323_DTMF_RFC2833)
+               if (user->dtmfmode & H323_DTMF_CISCO) {
+                       ast_cli(a->fd, "%s\n", "cisco");
+                       ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", user->dtmfcodec);
+               } else if (user->dtmfmode & H323_DTMF_RFC2833) {
                        ast_cli(a->fd, "%s\n", "rfc2833");
-               else if (user->dtmfmode & H323_DTMF_Q931)
+                       ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", user->dtmfcodec);
+               } else if (user->dtmfmode & H323_DTMF_Q931) {
                        ast_cli(a->fd, "%s\n", "q931keypad");
-               else if (user->dtmfmode & H323_DTMF_H245ALPHANUMERIC)
+               } else if (user->dtmfmode & H323_DTMF_H245ALPHANUMERIC) {
                        ast_cli(a->fd, "%s\n", "h245alphanumeric");
-               else if (user->dtmfmode & H323_DTMF_H245SIGNAL)
+               } else if (user->dtmfmode & H323_DTMF_H245SIGNAL) {
                        ast_cli(a->fd, "%s\n", "h245signal");
-               else
+               } else if (user->dtmfmode & H323_DTMF_INBAND && user->dtmfmode & H323_DTMF_INBANDRELAX) {
+                       ast_cli(a->fd, "%s\n", "inband-relaxed");
+               } else if (user->dtmfmode & H323_DTMF_INBAND) {
+                       ast_cli(a->fd, "%s\n", "inband");
+               } else {
                        ast_cli(a->fd, "%s\n", "unknown");
+               }
+               ast_cli(a->fd,"%-15s", "T.38 Mode: ");
+               if (user->t38support == T38_DISABLED) {
+                       ast_cli(a->fd, "%s\n", "disabled");
+               } else if (user->t38support == T38_FAXGW) {
+                       ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible");
+               }
+               if (user->faxdetect == (FAXDETECT_CNG | FAXDETECT_T38)) {
+                       ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Yes");
+               } else if (user->faxdetect & FAXDETECT_CNG) {
+                       ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Cng");
+               } else if (user->faxdetect & FAXDETECT_T38) {
+                       ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "T.38");
+               } else {
+                       ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "No");
+               }
+
                ast_cli(a->fd, "%-15.15s%s\n", "AccountCode: ", user->accountcode);
                ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ", ast_cdr_flags2str(user->amaflags));
                ast_cli(a->fd, "%-15.15s%s\n", "Context: ", user->context);
                ast_cli(a->fd, "%-15.15s%d\n", "IncomingLimit: ", user->incominglimit);
+               ast_cli(a->fd, "%-15.15s%d\n", "InUse: ", user->inUse);
                ast_cli(a->fd, "%-15.15s%d\n", "rtptimeout: ", user->rtptimeout);
+               if (user->rtpmaskstr[0]) {
+                       ast_cli(a->fd, "%-15.15s%s\n", "rtpmask: ", user->rtpmaskstr);
+               }
                ast_mutex_unlock(&user->lock);
+               if (user->rtdrcount && user->rtdrinterval) {
+                       ast_cli(a->fd, "%-15.15s%d,%d\n", "RoundTrip: ", user->rtdrcount, user->rtdrinterval);
+               }
        } else {
                ast_cli(a->fd, "User %s not found\n", a->argv[3]);
                ast_cli(a->fd, "\n");
@@ -2170,9 +3189,8 @@ static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struc
 
 static char *handle_cli_ooh323_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-       char formats[512];
        struct ooh323_user *prev = NULL, *user = NULL;
-
+   char formats[FORMAT_STRING_SIZE];
 #define FORMAT1  "%-15.15s  %-15.15s  %-15.15s  %-s\n"
 
        switch (cmd) {
@@ -2189,24 +3207,26 @@ static char *handle_cli_ooh323_show_users(struct ast_cli_entry *e, int cmd, stru
        if (a->argc != 3)
                return CLI_SHOWUSAGE;
 
-       ast_cli(a->fd, FORMAT1, "Username", "Accountcode", "Context", "Formats");
+
+   ast_cli(a->fd, FORMAT1, "Username", "Accountcode", "Context", "Formats");
 
        ast_mutex_lock(&userl.lock);
        user = userl.users;
-       while (user) {
+   while(user)
+   {
                ast_mutex_lock(&user->lock);
-               ast_cli(a->fd, FORMAT1, user->name,
+               ast_cli(a->fd, FORMAT1, user->name, 
                                        user->accountcode, user->context,
-                                       ast_getformatname_multiple(formats, 512, user->capability));
+                                       ast_getformatname_multiple(formats, FORMAT_STRING_SIZE, user->cap));
                prev = user;
                user = user->next;
                ast_mutex_unlock(&prev->lock);
+
        }
        ast_mutex_unlock(&userl.lock);
-
 #undef FORMAT1
+   return RESULT_SUCCESS;
 
-       return CLI_SUCCESS;
 }
 
 static char *handle_cli_ooh323_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
@@ -2242,7 +3262,7 @@ static int ooh323_show_channels(int fd, int argc, char *argv[])
 
 static char *handle_cli_ooh323_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-       char value[512];
+       char value[FORMAT_STRING_SIZE];
        ooAliases *pAlias = NULL, *pAliasNext = NULL;;
 
        switch (cmd) {
@@ -2259,66 +3279,96 @@ static char *handle_cli_ooh323_show_config(struct ast_cli_entry *e, int cmd, str
        if (a->argc != 3)
                return CLI_SHOWUSAGE;
 
-       snprintf(value, sizeof(value), "%s:%d", gIP, gPort);
        ast_cli(a->fd, "\nObjective Open H.323 Channel Driver's Config:\n");
+       snprintf(value, sizeof(value), "%s:%d", gIP, gPort);
        ast_cli(a->fd, "%-20s%s\n", "IP:Port: ", value);
+       ast_cli(a->fd, "%-20s%d-%d\n", "H.225 port range: ", ooconfig.mTCPPortStart, ooconfig.mTCPPortEnd);
        ast_cli(a->fd, "%-20s%s\n", "FastStart", gFastStart?"yes":"no");
        ast_cli(a->fd, "%-20s%s\n", "Tunneling", gTunneling?"yes":"no");
        ast_cli(a->fd, "%-20s%s\n", "CallerId", gCallerID);
-       ast_cli(a->fd, "%-20s%s\n", "MediaWaitForConnect", gMediaWaitForConnect ? "yes" : "no");
+       ast_cli(a->fd, "%-20s%s\n", "MediaWaitForConnect", gMediaWaitForConnect?"yes":"no");
 
-#if 0
-       {
+#if (0)
                extern OOH323EndPoint gH323ep;
-
-               ast_cli(a->fd, "%-20s%s\n", "FASTSTART",
-                       (OO_TESTFLAG(gH323ep.flags, OO_M_FASTSTART) != 0) ? "yes" : "no");
-               ast_cli(a->fd, "%-20s%s\n", "TUNNELING",
-                       (OO_TESTFLAG(gH323ep.flags, OO_M_TUNNELING) != 0) ? "yes" : "no");
-               ast_cli(a->fd, "%-20s%s\n", "MEDIAWAITFORCONN",
-                       (OO_TESTFLAG(gH323ep.flags, OO_M_MEDIAWAITFORCONN) != 0) ? "yes" : "no");
-       }
+       ast_cli(a->fd, "%-20s%s\n", "FASTSTART",
+               (OO_TESTFLAG(gH323ep.flags, OO_M_FASTSTART) != 0) ? "yes" : "no");
+       ast_cli(a->fd, "%-20s%s\n", "TUNNELING",
+               (OO_TESTFLAG(gH323ep.flags, OO_M_TUNNELING) != 0) ? "yes" : "no");
+       ast_cli(a->fd, "%-20s%s\n", "MEDIAWAITFORCONN",
+               (OO_TESTFLAG(gH323ep.flags, OO_M_MEDIAWAITFORCONN) != 0) ? "yes" : "no");
 #endif
 
-       if (gRasGkMode == RasNoGatekeeper)
+       if (gRasGkMode == RasNoGatekeeper) {
                snprintf(value, sizeof(value), "%s", "No Gatekeeper");
-       else if (gRasGkMode == RasDiscoverGatekeeper)
+       } else if (gRasGkMode == RasDiscoverGatekeeper) {
                snprintf(value, sizeof(value), "%s", "Discover");
-       else
+       } else {
                snprintf(value, sizeof(value), "%s", gGatekeeper);
-
-       ast_cli(a->fd, "%-20s%s\n", "Gatekeeper:", value);
-       ast_cli(a->fd, "%-20s%s\n", "H.323 LogFile:", gLogFile);
-       ast_cli(a->fd, "%-20s%s\n", "Context:", gContext);
-       ast_cli(a->fd, "%-20s%s\n", "Capability:", ast_getformatname_multiple(value, sizeof(value), gCapability));
+       }
+       ast_cli(a->fd,  "%-20s%s\n", "Gatekeeper:", value);
+       ast_cli(a->fd,  "%-20s%s\n", "H.323 LogFile:", gLogFile);
+       ast_cli(a->fd,  "%-20s%s\n", "Context:", gContext);
+       ast_cli(a->fd,  "%-20s%s\n", "Capability:",
+               ast_getformatname_multiple(value,FORMAT_STRING_SIZE,gCap));
        ast_cli(a->fd, "%-20s", "DTMF Mode: ");
-       if (gDTMFMode & H323_DTMF_RFC2833)
+       if (gDTMFMode & H323_DTMF_CISCO) {
+               ast_cli(a->fd, "%s\n", "cisco");
+               ast_cli(a->fd, "%-20.15s%d\n", "DTMF Codec: ", gDTMFCodec);
+       } else if (gDTMFMode & H323_DTMF_RFC2833) {
                ast_cli(a->fd, "%s\n", "rfc2833");
-       else if (gDTMFMode & H323_DTMF_Q931)
+               ast_cli(a->fd, "%-20.15s%d\n", "DTMF Codec: ", gDTMFCodec);
+       } else if (gDTMFMode & H323_DTMF_Q931) {
                ast_cli(a->fd, "%s\n", "q931keypad");
-       else if (gDTMFMode & H323_DTMF_H245ALPHANUMERIC)
+       } else if (gDTMFMode & H323_DTMF_H245ALPHANUMERIC) {
                ast_cli(a->fd, "%s\n", "h245alphanumeric");
-       else if (gDTMFMode & H323_DTMF_H245SIGNAL)
+       } else if (gDTMFMode & H323_DTMF_H245SIGNAL) {
                ast_cli(a->fd, "%s\n", "h245signal");
-       else
+       } else if (gDTMFMode & H323_DTMF_INBAND && gDTMFMode & H323_DTMF_INBANDRELAX) {
+               ast_cli(a->fd, "%s\n", "inband-relaxed");
+       } else if (gDTMFMode & H323_DTMF_INBAND) {
+               ast_cli(a->fd, "%s\n", "inband");
+       } else {
                ast_cli(a->fd, "%s\n", "unknown");
+       }
+
+       ast_cli(a->fd,"%-20s", "T.38 Mode: ");
+       if (gT38Support == T38_DISABLED) {
+               ast_cli(a->fd, "%s\n", "disabled");
+       } else if (gT38Support == T38_FAXGW) {
+               ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible");
+       }
+       if (gFAXdetect == (FAXDETECT_CNG | FAXDETECT_T38)) {
+               ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Yes");
+       } else if (gFAXdetect & FAXDETECT_CNG) {
+               ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Cng");
+       } else if (gFAXdetect & FAXDETECT_T38) {
+               ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "T.38");
+       } else {
+               ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "No");
+       }
+
+       if (gRTDRCount && gRTDRInterval) {
+               ast_cli(a->fd, "%-20.15s%d,%d\n", "RoundTrip: ", gRTDRCount, gRTDRInterval);
+       }
+
+       ast_cli(a->fd, "%-20s%ld\n", "Call counter: ", callnumber);
        ast_cli(a->fd, "%-20s%s\n", "AccountCode: ", gAccountcode);
        ast_cli(a->fd, "%-20s%s\n", "AMA flags: ", ast_cdr_flags2str(gAMAFLAGS));
 
        pAlias = gAliasList;
-       if (pAlias)
+       if(pAlias) {
                ast_cli(a->fd, "%-20s\n", "Aliases: ");
+       }
        while (pAlias) {
                pAliasNext = pAlias->next;
                if (pAliasNext) {
-                       ast_cli(a->fd, "\t%-30s\t%-30s\n", pAlias->value, pAliasNext->value);
+                       ast_cli(a->fd,"\t%-30s\t%-30s\n",pAlias->value, pAliasNext->value);
                        pAlias = pAliasNext->next;
                } else {
-                       ast_cli(a->fd, "\t%-30s\n", pAlias->value);
+                       ast_cli(a->fd,"\t%-30s\n",pAlias->value);
                        pAlias = pAlias->next;
                }
        }
-
        return CLI_SUCCESS;
 }
 
@@ -2329,33 +3379,142 @@ static struct ast_cli_entry cli_ooh323[] = {
        AST_CLI_DEFINE(handle_cli_ooh323_show_peers,  "Show defined OOH323 peers"),
        AST_CLI_DEFINE(handle_cli_ooh323_show_user,     "Show details on specific OOH323 user"),
        AST_CLI_DEFINE(handle_cli_ooh323_show_users,  "Show defined OOH323 users"),
+        AST_CLI_DEFINE(handle_cli_ooh323_reload, "reload ooh323 config")
 };
 
+/*! \brief OOH323 Dialplan function - reads ooh323 settings */
+static int function_ooh323_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+       struct ooh323_pvt *p = chan->tech_pvt;
+
+       ast_channel_lock(chan);
+       if (!p) {
+               ast_channel_unlock(chan);
+               return -1;
+       }
+
+       if (strcmp(chan->tech->type, "OOH323")) {
+               ast_log(LOG_ERROR, "This function is only supported on OOH323 channels, Channel is %s\n", chan->tech->type);
+               ast_channel_unlock(chan);
+               return -1;
+       }
+
+       ast_mutex_lock(&p->lock);
+       if (!strcasecmp(data, "faxdetect")) {
+               ast_copy_string(buf, p->faxdetect ? "1" : "0", len);
+       } else if (!strcasecmp(data, "t38support")) {
+               ast_copy_string(buf, p->t38support ? "1" : "0", len);
+       } else if (!strcasecmp(data, "caller_h323id")) {
+               ast_copy_string(buf, p->caller_h323id, len);
+       } else if (!strcasecmp(data, "caller_dialeddigits")) {
+               ast_copy_string(buf, p->caller_dialedDigits, len);
+       } else if (!strcasecmp(data, "caller_email")) {
+               ast_copy_string(buf, p->caller_email, len);
+       } else if (!strcasecmp(data, "h323id_url")) {
+               ast_copy_string(buf, p->caller_url, len);
+       } else if (!strcasecmp(data, "callee_h323id")) {
+               ast_copy_string(buf, p->callee_h323id, len);
+       } else if (!strcasecmp(data, "callee_dialeddigits")) {
+               ast_copy_string(buf, p->callee_dialedDigits, len);
+       } else if (!strcasecmp(data, "callee_email")) {
+               ast_copy_string(buf, p->callee_email, len);
+       } else if (!strcasecmp(data, "callee_url")) {
+               ast_copy_string(buf, p->callee_url, len);
+       }
+       ast_mutex_unlock(&p->lock);
+
+       ast_channel_unlock(chan);
+       return 0;
+}
+
+/*! \brief OOH323 Dialplan function - writes ooh323 settings */
+static int function_ooh323_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+       struct ooh323_pvt *p = chan->tech_pvt;
+       int res = -1;
+
+       ast_channel_lock(chan);
+       if (!p) {
+               ast_channel_unlock(chan);
+               return -1;
+       }
+
+       if (strcmp(chan->tech->type, "OOH323")) {
+               ast_log(LOG_ERROR, "This function is only supported on OOH323 channels, Channel is %s\n", chan->tech->type);
+               ast_channel_unlock(chan);
+               return -1;
+       }
+
+       ast_mutex_lock(&p->lock);
+       if (!strcasecmp(data, "faxdetect")) {
+               if (ast_true(value)) {
+                       p->faxdetect = 1;
+                       res = 0;
+               } else if (ast_false(value)) {
+                       p->faxdetect = 0;
+                       res = 0;
+               } else {
+                       char *buf = ast_strdupa(value);
+                       char *word, *next = buf;
+                       p->faxdetect = 0;
+                       res = 0;
+                       while ((word = strsep(&next, ","))) {
+                               if (!strcasecmp(word, "cng")) {
+                                       p->faxdetect |= FAXDETECT_CNG;
+                               } else if (!strcasecmp(word, "t38")) {
+                                       p->faxdetect |= FAXDETECT_T38;
+                               } else {
+                                       ast_log(LOG_WARNING, "Unknown faxdetect mode '%s'.\n", word);
+                                       res = -1;
+                               }
+                       }
+
+               }
+       } else if (!strcasecmp(data, "t38support")) {
+               if (ast_true(value)) {
+                       p->t38support = 1;
+                       res = 0;
+               } else {
+                       p->t38support = 0;
+                       res = 0;
+               }
+       }
+       ast_mutex_unlock(&p->lock);
+       ast_channel_unlock(chan);
+
+       return res;
+}
+
 static int load_module(void)
 {
        int res;
        struct ooAliases * pNewAlias = NULL;
        struct ooh323_peer *peer = NULL;
+       struct ast_format tmpfmt;
        OOH225MsgCallbacks h225Callbacks = {0, 0, 0, 0};
 
        OOH323CALLBACKS h323Callbacks = {
                .onNewCallCreated = onNewCallCreated,
                .onAlerting = onAlerting,
+               .onProgress = onProgress,
                .onIncomingCall = NULL,
-               .onOutgoingCall = NULL,
+               .onOutgoingCall = onOutgoingCall,
                .onCallEstablished = onCallEstablished,
                .onCallCleared = onCallCleared,
                .openLogicalChannels = NULL,
-               .onReceivedDTMF = &ooh323_onReceivedDigit
+               .onReceivedDTMF = ooh323_onReceivedDigit,
+               .onModeChanged = onModeChanged
        };
+       if (!(gCap = ast_format_cap_alloc())) {
+               return 1; 
+       }
+       if (!(ooh323_tech.capabilities = ast_format_cap_alloc())) {
+               return 1;
+       }
+       ast_format_cap_add(gCap, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
+       ast_format_cap_add_all(ooh323_tech.capabilities);
 
-       ast_log(LOG_NOTICE, 
-               "---------------------------------------------------------------------------------\n"
-               "---  ******* IMPORTANT NOTE ***********\n"
-               "---\n"
-               "---  This module is currently unsupported.  Use it at your own risk.\n"
-               "---\n"
-               "---------------------------------------------------------------------------------\n");
+       myself = ast_module_info->self;
 
        h225Callbacks.onReceivedSetup = &ooh323_onReceivedSetup;
 
@@ -2368,7 +3527,7 @@ static int load_module(void)
        ast_register_atexit(&ast_ooh323c_exit);
 #endif
 
-       if (!(sched = sched_context_create())) {
+       if (!(sched = ast_sched_context_create())) {
                ast_log(LOG_WARNING, "Unable to create schedule context\n");
        }
        if (!(io = io_context_create())) {
@@ -2382,24 +3541,36 @@ static int load_module(void)
                        ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
                        return 0;
                }
-               ast_rtp_proto_register(&ooh323_rtp);
+               ast_rtp_glue_register(&ooh323_rtp);
+               ast_udptl_proto_register(&ooh323_udptl);
                ast_cli_register_multiple(cli_ooh323, sizeof(cli_ooh323) / sizeof(struct ast_cli_entry));
 
                 /* fire up the H.323 Endpoint */                
                if (OO_OK != ooH323EpInitialize(OO_CALLMODE_AUDIOCALL, gLogFile)) {
-                       ast_log(LOG_ERROR, "Failed to initialize OOH323 endpoint-OOH323 Disabled\n");
+         ast_log(LOG_ERROR, "Failed to initialize OOH323 endpoint-"
+                            "OOH323 Disabled\n");
                        return 1;
                }
 
                if (gIsGateway)
                        ooH323EpSetAsGateway();
 
+               ooH323EpSetVersionInfo(t35countrycode, t35extensions, manufacturer,
+                                                                        vendor, version);
                ooH323EpDisableAutoAnswer();
                ooH323EpSetH225MsgCallbacks(h225Callbacks);
-               ooH323EpSetTraceLevel(OOTRCLVLDBGC);
+               ooH323EpSetTraceLevel(gTRCLVL);
                ooH323EpSetLocalAddress(gIP, gPort);
+               if (v6mode) {
+                       ast_debug(1, "OOH323 channel is in IP6 mode\n");
+               }
                ooH323EpSetCallerID(gCallerID);
  
+      if(ooH323EpSetTCPPortRange(ooconfig.mTCPPortStart, 
+                                 ooconfig.mTCPPortEnd) == OO_FAILED) {
+         ast_log(LOG_ERROR, "h225portrange: Failed to set range\n");
+      }
+
                /* Set aliases if any */
                for (pNewAlias = gAliasList; pNewAlias; pNewAlias = pNewAlias->next) {
                        switch (pNewAlias->type) {
@@ -2412,20 +3583,18 @@ static int load_module(void)
                        case T_H225AliasAddress_email_ID:       
                                ooH323EpAddAliasEmailID(pNewAlias->value);
                                break;
+         default:
+            ;
                        }
                }
 
                ast_mutex_lock(&peerl.lock);
                peer = peerl.peers;
                while (peer) {
-                       if (peer->h323id)
-                               ooH323EpAddAliasH323ID(peer->h323id);
-                       if (peer->email)
-                               ooH323EpAddAliasEmailID(peer->email);
-                       if (peer->e164)
-                               ooH323EpAddAliasDialedDigits(peer->e164);
-                       if (peer->url)
-                               ooH323EpAddAliasURLID(peer->url);
+         if(peer->h323id) ooH323EpAddAliasH323ID(peer->h323id);
+         if(peer->email)  ooH323EpAddAliasEmailID(peer->email);
+         if(peer->e164)   ooH323EpAddAliasDialedDigits(peer->e164);
+         if(peer->url)    ooH323EpAddAliasURLID(peer->url);
                        peer = peer->next;
                }
                ast_mutex_unlock(&peerl.lock);
@@ -2445,6 +3614,11 @@ static int load_module(void)
                if (!gTunneling)
                        ooH323EpDisableH245Tunneling();
 
+               if (gBeMaster)
+                       ooH323EpTryBeMaster(1);
+
+               ooH323EpEnableManualRingback();
+
                /* Gatekeeper */
                if (gRasGkMode == RasUseSpecificGatekeeper)
                        ooGkClientInit(gRasGkMode, gGatekeeper, 0);
@@ -2455,22 +3629,23 @@ static int load_module(void)
                ooH323EpSetH323Callbacks(h323Callbacks);
 
                /* Add endpoint capabilities */
-               if (ooh323c_set_capability(&gPrefs, gCapability, gDTMFMode) < 0) {
+               if (ooh323c_set_capability(&gPrefs, gCap, gDTMFMode, gDTMFCodec) < 0) {
                        ast_log(LOG_ERROR, "Capabilities failure for OOH323. OOH323 Disabled.\n");
                        return 1;
                }
   
-
                /* Create H.323 listener */
                if (ooCreateH323Listener() != OO_OK) {
-                       ast_log(LOG_ERROR, "OOH323 Listener Creation failure. OOH323 DISABLED\n");
+         ast_log(LOG_ERROR, "OOH323 Listener Creation failure. "
+                            "OOH323 DISABLED\n");
                
                        ooH323EpDestroy();
                        return 1;
                }
 
                if (ooh323c_start_stack_thread() < 0) {
-                       ast_log(LOG_ERROR, "Failed to start OOH323 stack thread. OOH323 DISABLED\n");
+         ast_log(LOG_ERROR, "Failed to start OOH323 stack thread. "
+                            "OOH323 DISABLED\n");
                        ooH323EpDestroy();
                        return 1;
                }
@@ -2500,6 +3675,7 @@ static void *do_monitor(void *data)
                        ast_verb(1, "Reloading H.323\n");
                        ooh323_do_reload();
                }
+
                /* Check for interfaces needing to be killed */
                ast_mutex_lock(&iflock);
                time(&t);
@@ -2510,11 +3686,21 @@ static void *do_monitor(void *data)
                        /* TODO: Need to add rtptimeout keepalive support */
                        if (ast_test_flag(h323, H323_NEEDDESTROY)) {
                                ooh323_destroy (h323);
-                       }
+         } /* else if (ast_test_flag(h323, H323_NEEDSTART) && h323->owner) {
+         ast_channel_lock(h323->owner);
+          if (ast_pbx_start(h323->owner)) {
+            ast_log(LOG_WARNING, "Unable to start PBX on %s\n", h323->owner->name);
+            ast_channel_unlock(h323->owner);
+            ast_hangup(h323->owner);
+          }
+          ast_channel_unlock(h323->owner);
+         ast_clear_flag(h323, H323_NEEDSTART);
+        } */
                        h323 = h323_next;
                }
                ast_mutex_unlock(&iflock);
                pthread_testcancel();
+
                /* Wait for sched or io */
                res = ast_sched_wait(sched);
                if ((res < 0) || (res > 1000)) {
@@ -2571,7 +3757,7 @@ int ooh323_destroy(struct ooh323_pvt *p)
 {
        /* NOTE: Assumes iflock already acquired */
        struct ooh323_pvt *prev = NULL, *cur = NULL;
-
+       struct ooh323_user *user = NULL;
 
        if (gH323Debug) {
                ast_verbose("---   ooh323_destroy \n");
@@ -2595,7 +3781,9 @@ int ooh323_destroy(struct ooh323_pvt *p)
                        iflist = cur->next;
 
                if (cur->callToken) {
-                       free(cur->callToken);
+                       if (gH323Debug) 
+                               ast_verbose(" Destroying %s\n", cur->callToken);
+                       ast_free(cur->callToken);
                        cur->callToken = 0;
                }
 
@@ -2619,29 +3807,54 @@ int ooh323_destroy(struct ooh323_pvt *p)
                        cur->callerid_num = 0;
                }
 
-
                if (cur->rtp) {
-                       ast_rtp_destroy(cur->rtp);
-                       cur->rtp = 0;
+                       ast_rtp_instance_destroy(cur->rtp);
+                       cur->rtp = NULL;
+               }
+
+               if (cur->udptl) {
+                       ast_udptl_destroy(cur->udptl);
+                       cur->udptl = NULL;
                }
        
                /* Unlink us from the owner if we have one */
                if (cur->owner) {
-                       ast_channel_lock(cur->owner);
+                       while(ast_channel_trylock(cur->owner)) {
+                               ast_debug(1, "Failed to grab lock, trying again\n");
+                               DEADLOCK_AVOIDANCE(&cur->lock);
+                       }           
                        ast_debug(1, "Detaching from %s\n", cur->owner->name);
                        cur->owner->tech_pvt = NULL;
                        ast_channel_unlock(cur->owner);
                        cur->owner = NULL;
+                       ast_module_unref(myself);
                }
   
                if (cur->vad) {
                        ast_dsp_free(cur->vad);
                        cur->vad = NULL;
                }
+
+/* decrement user/peer count */
+
+      if(!ast_test_flag(cur, H323_OUTGOING)) {
+        if (cur->neighbor.user) {
+         user = find_user(p->callerid_name, cur->neighbor.user);
+         if(user && user->inUse > 0) {
+               ast_mutex_lock(&user->lock);
+               user->inUse--;
+               ast_mutex_unlock(&user->lock);
+         }
+         free(cur->neighbor.user);
+        }
+      } else {
+/* outgoing limit decrement here !!! */
+      }
+
                ast_mutex_unlock(&cur->lock);
                ast_mutex_destroy(&cur->lock);
-
-               free(cur);
+               cur->cap = ast_format_cap_destroy(cur->cap);
+               ast_free(cur);
        }
 
        if (gH323Debug)
@@ -2660,14 +3873,20 @@ int delete_peers()
                cur = cur->next;
 
                ast_mutex_destroy(&prev->lock);
-               if (prev->h323id)
-                       free(prev->h323id);
-               if (prev->email)
-                       free(prev->email);
-               if (prev->url)
-                       free(prev->url);
-               if (prev->e164)
-                       free(prev->e164);
+      if(prev->h323id)   free(prev->h323id);
+      if(prev->email)    free(prev->email);
+      if(prev->url)      free(prev->url);
+      if(prev->e164)     free(prev->e164);
+      if(prev->rtpmask) {
+               ast_mutex_lock(&prev->rtpmask->lock);
+               prev->rtpmask->inuse--;
+               ast_mutex_unlock(&prev->rtpmask->lock);
+               if (prev->rtpmask->inuse == 0) {
+                       regfree(&prev->rtpmask->regex);
+                       ast_mutex_destroy(&prev->rtpmask->lock);
+                       free(prev->rtpmask);
+               }
+      }
                free(prev);
 
                if (cur == peerl.peers) {
@@ -2688,6 +3907,18 @@ int delete_users()
                prev = cur;
                cur = cur->next;
                ast_mutex_destroy(&prev->lock);
+
+               if(prev->rtpmask) {
+                       ast_mutex_lock(&prev->rtpmask->lock);
+                       prev->rtpmask->inuse--;
+                       ast_mutex_unlock(&prev->rtpmask->lock);
+                       if (prev->rtpmask->inuse == 0) {
+                               regfree(&prev->rtpmask->regex);
+                               ast_mutex_destroy(&prev->rtpmask->lock);
+                               free(prev->rtpmask);
+                       }
+               }
+               prev->cap = ast_format_cap_destroy(prev->cap);
                free(prev);
                if (cur == userl.users) {
                        break;
@@ -2697,7 +3928,7 @@ int delete_users()
        ast_mutex_unlock(&userl.lock);
        return 0;
 }
-  
+
 static int unload_module(void)
 {
        struct ooh323_pvt *p;
@@ -2708,9 +3939,9 @@ static int unload_module(void)
        }
        /* First, take us out of the channel loop */
        ast_cli_unregister_multiple(cli_ooh323, sizeof(cli_ooh323) / sizeof(struct ast_cli_entry));
-       ast_rtp_proto_unregister(&ooh323_rtp);
+       ast_rtp_glue_unregister(&ooh323_rtp);
+       ast_udptl_proto_unregister(&ooh323_udptl);
        ast_channel_unregister(&ooh323_tech);
-
 #if 0
        ast_unregister_atexit(&ast_ooh323c_exit);
 #endif
@@ -2813,46 +4044,53 @@ static int unload_module(void)
        ooH323EpDestroy();
 
        if (gH323Debug) {
-               ast_verbose("+++ ooh323  unload_module \n");    
+               ast_verbose("+++ ooh323  unload_module \n");
        }
 
+       gCap = ast_format_cap_destroy(gCap);
+       ooh323_tech.capabilities = ast_format_cap_destroy(ooh323_tech.capabilities);
        return 0;
 }
 
 
 
-static enum ast_rtp_get_result ooh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
+static enum ast_rtp_glue_result ooh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **rtp)
 {
        struct ooh323_pvt *p = NULL;
-       enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL;
+       enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL;
 
        if (!(p = (struct ooh323_pvt *) chan->tech_pvt))
-       return AST_RTP_GET_FAILED;
-
-       *rtp = p->rtp;
+               return AST_RTP_GLUE_RESULT_FORBID;
 
        if (!(p->rtp)) {
-               return AST_RTP_GET_FAILED;
+               return AST_RTP_GLUE_RESULT_FORBID;
+       }
+
+       *rtp = p->rtp ? ao2_ref(p->rtp, +1), p->rtp : NULL;
+
+       res = AST_RTP_GLUE_RESULT_LOCAL;
+
+       if (ast_test_flag(&global_jbconf, AST_JB_FORCED)) {
+               res = AST_RTP_GLUE_RESULT_FORBID;
        }
-       res = AST_RTP_TRY_NATIVE;
 
        return res;
 }
 
-static enum ast_rtp_get_result ooh323_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
+static enum ast_rtp_glue_result ooh323_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp_instance **rtp)
 {
        struct ooh323_pvt *p = NULL;
-       enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL;
+       enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL;
 
        if (!(p = (struct ooh323_pvt *) chan->tech_pvt))
-               return AST_RTP_GET_FAILED;
-
-       *rtp = p->vrtp;
+               return AST_RTP_GLUE_RESULT_FORBID;
 
        if (!(p->rtp)) {
-               return AST_RTP_GET_FAILED;
+               return AST_RTP_GLUE_RESULT_FORBID;
        }
-       res = AST_RTP_TRY_NATIVE;
+
+       *rtp = p->vrtp ? ao2_ref(p->vrtp, +1), p->vrtp : NULL;
+       res = AST_RTP_GLUE_RESULT_LOCAL;
 
        return res;
 }
@@ -2862,48 +4100,61 @@ int ooh323_update_capPrefsOrderForCall
        (ooCallData *call, struct ast_codec_pref *prefs)
 {
        int i = 0;
-       int codec = ast_codec_pref_index(prefs, i);
+       struct ast_format tmpfmt;
+
+       ast_codec_pref_index(prefs, i, &tmpfmt);
 
        ooResetCapPrefs(call);
-       while (codec) {
-               ooAppendCapToCapPrefs(call, ooh323_convertAsteriskCapToH323Cap(codec));
-               codec = ast_codec_pref_index(prefs, ++i);
+       while (tmpfmt.id) {
+               ooAppendCapToCapPrefs(call, ooh323_convertAsteriskCapToH323Cap(&tmpfmt));
+               ast_codec_pref_index(prefs, ++i, &tmpfmt);
        }
 
        return 0;
 }
 
 
-int ooh323_convertAsteriskCapToH323Cap(int cap)
+int ooh323_convertAsteriskCapToH323Cap(struct ast_format *format)
 {
-       char formats[512];
-       switch (cap) {
+       switch (format->id) {
        case AST_FORMAT_ULAW:
                return OO_G711ULAW64K;
        case AST_FORMAT_ALAW:
                return OO_G711ALAW64K;
        case AST_FORMAT_GSM:
                return OO_GSMFULLRATE;
+
+#ifdef AST_FORMAT_AMRNB
+       case AST_FORMAT_AMRNB:
+               return OO_AMRNB;
+#endif
+#ifdef AST_FORMAT_SPEEX
+       case AST_FORMAT_SPEEX:
+               return OO_SPEEX;
+#endif
+
        case AST_FORMAT_G729A:
                return OO_G729A;
+       case AST_FORMAT_G726:
+               return OO_G726;
+       case AST_FORMAT_G726_AAL2:
+               return OO_G726AAL2;
        case AST_FORMAT_G723_1:
                return OO_G7231;
        case AST_FORMAT_H263:
                return OO_H263VIDEO;
        default:
-               ast_log(LOG_NOTICE, "Don't know how to deal with mode %s\n", 
-                                                       ast_getformatname_multiple(formats, sizeof(formats), cap));
+               ast_log(LOG_NOTICE, "Don't know how to deal with mode %s\n", ast_getformatname(format));
                return -1;
        }
 }
 
-static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp,
-        struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active)
+static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp,
+        struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, const struct ast_format_cap *cap, int nat_active)
 {
        /* XXX Deal with Video */
        struct ooh323_pvt *p;
-       struct sockaddr_in them;
-       struct sockaddr_in us;
+       struct ast_sockaddr tmp;
        int mode;
 
        if (gH323Debug)
@@ -2913,15 +4164,20 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp,
                return 0;
        }
 
-       mode = ooh323_convertAsteriskCapToH323Cap(chan->writeformat); 
+       mode = ooh323_convertAsteriskCapToH323Cap(&chan->writeformat); 
        p = (struct ooh323_pvt *) chan->tech_pvt;
        if (!p) {
                ast_log(LOG_ERROR, "No Private Structure, this is bad\n");
                return -1;
        }
-       ast_rtp_get_peer(rtp, &them);
-       ast_rtp_get_us(rtp, &us);
+       ast_rtp_instance_get_remote_address(rtp, &tmp);
+       ast_rtp_instance_get_local_address(rtp, &tmp);
        return 0;
+
+/*     May 20101003 */
+/*     What we should to do here? */
+
+
 }
 
 
@@ -2929,26 +4185,95 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp,
 
 int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
 {
-       struct sockaddr_in us;
+       char lhost[INET6_ADDRSTRLEN], *lport=NULL;
+       struct ast_sockaddr tmp;
        ooMediaInfo mediaInfo;
-       int x, format = 0;        
+       int x;
+       struct ast_format tmpfmt;
+
+       ast_format_clear(&tmpfmt);
 
        if (gH323Debug)
                ast_verbose("---   configure_local_rtp\n");
 
+
+       if (ast_parse_arg(call->localIP, PARSE_ADDR, &tmp)) {
+               ast_sockaddr_copy(&tmp, &bindaddr);
+       }
+       if (!(p->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
+               ast_log(LOG_WARNING, "Unable to create RTP session: %s\n",
+                       strerror(errno));
+               return 0;
+       }
+
+       ast_rtp_instance_set_qos(p->rtp, gTOS, 0, "ooh323-rtp");
+
+       if (!(p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, &tmp))) {
+               ast_log(LOG_WARNING, "Unable to create UDPTL session: %s\n",
+                       strerror(errno));
+               return 0;
+       }
+       ast_udptl_set_far_max_datagram(p->udptl, 144);
+
+       if (p->owner) {
+               while (p->owner && ast_channel_trylock(p->owner)) {
+                       ast_debug(1,"Failed to grab lock, trying again\n");
+                       DEADLOCK_AVOIDANCE(&p->lock);
+               }
+               if (!p->owner) {
+                       ast_mutex_unlock(&p->lock);
+                       ast_log(LOG_ERROR, "Channel has no owner\n");
+                       return 0;
+               }
+       } else {
+               ast_log(LOG_ERROR, "Channel has no owner\n");
+               return 0;
+       }
+
+       ast_channel_set_fd(p->owner, 0, ast_rtp_instance_fd(p->rtp, 0));
+       ast_channel_set_fd(p->owner, 1, ast_rtp_instance_fd(p->rtp, 1));
+       ast_channel_set_fd(p->owner, 5, ast_udptl_fd(p->udptl));
+
+       ast_channel_unlock(p->owner);
+
        if (p->rtp) {
-               ast_rtp_codec_setpref(p->rtp, &p->prefs);
+               ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &p->prefs);
+               if (p->dtmfmode & H323_DTMF_RFC2833 && p->dtmfcodec) {
+                       ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF, 1);
+                       ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp),
+                                p->rtp, p->dtmfcodec, "audio", "telephone-event", 0);
+               }
+               if (p->dtmfmode & H323_DTMF_CISCO && p->dtmfcodec) {
+                       ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF, 1);
+                       ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp),
+                                p->rtp, p->dtmfcodec, "audio", "cisco-telephone-event", 0);
+               }
+               /* figure out our local RTP port and tell the H.323 stack about it*/
+               ast_rtp_instance_get_local_address(p->rtp, &tmp);
+               strncpy(lhost, ast_sockaddr_stringify_addr(&tmp), sizeof(lhost));
+               lport = ast_sockaddr_stringify_port(&tmp);
+
+               if (p->rtptimeout) {
+                       ast_rtp_instance_set_timeout(p->rtp, p->rtptimeout);
+               }
+               ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 1);
+               
+       }
+
+       if (p->rtdrcount) {
+               if (gH323Debug)
+                       ast_verbose("Setup RTDR info: %d, %d\n", p->rtdrinterval, p->rtdrcount);
+               call->rtdrInterval = p->rtdrinterval;
+               call->rtdrCount = p->rtdrcount;
        }
 
-       /* figure out our local RTP port and tell the H.323 stack about it*/
-       ast_rtp_get_us(p->rtp, &us);
 
-       ast_copy_string(mediaInfo.lMediaIP, ast_inet_ntoa(us.sin_addr), sizeof(mediaInfo.lMediaIP));
-       mediaInfo.lMediaPort = ntohs(us.sin_port);
+       ast_copy_string(mediaInfo.lMediaIP, lhost, sizeof(mediaInfo.lMediaIP));
+       mediaInfo.lMediaPort = atoi(lport);
        mediaInfo.lMediaCntrlPort = mediaInfo.lMediaPort +1;
-       for (x = 0; 0 != (format = ast_codec_pref_index(&p->prefs, x)); x++) {
+       for (x = 0; ast_codec_pref_index(&p->prefs, x, &tmpfmt); x++) {
                strcpy(mediaInfo.dir, "transmit");
-               mediaInfo.cap = ooh323_convertAsteriskCapToH323Cap(format);
+               mediaInfo.cap = ooh323_convertAsteriskCapToH323Cap(&tmpfmt);
                ooAddMediaInfo(call, mediaInfo);
                strcpy(mediaInfo.dir, "receive");
                ooAddMediaInfo(call, mediaInfo);
@@ -2958,9 +4283,29 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
                        ooAddMediaInfo(call, mediaInfo);
                        strcpy(mediaInfo.dir, "receive");
                        ooAddMediaInfo(call, mediaInfo);
+
+                       strcpy(mediaInfo.dir, "transmit");
+                       mediaInfo.cap = OO_G729B;
+                       ooAddMediaInfo(call, mediaInfo);
+                       strcpy(mediaInfo.dir, "receive");
+                       ooAddMediaInfo(call, mediaInfo);
                }
        }
 
+       if (p->udptl) {
+               ast_udptl_get_us(p->udptl, &tmp);
+               strncpy(lhost, ast_sockaddr_stringify_addr(&tmp), sizeof(lhost));
+               lport = ast_sockaddr_stringify_port(&tmp);
+               ast_copy_string(mediaInfo.lMediaIP, lhost, sizeof(mediaInfo.lMediaIP));
+               mediaInfo.lMediaPort = atoi(lport);
+               mediaInfo.lMediaCntrlPort = mediaInfo.lMediaPort +1;
+               mediaInfo.cap = OO_T38;
+               strcpy(mediaInfo.dir, "transmit");
+               ooAddMediaInfo(call, mediaInfo);
+               strcpy(mediaInfo.dir, "receive");
+               ooAddMediaInfo(call, mediaInfo);
+       }
+
        if (gH323Debug)
                ast_verbose("+++   configure_local_rtp\n");
 
@@ -2971,10 +4316,10 @@ void setup_rtp_connection(ooCallData *call, const char *remoteIp,
                                                                  int remotePort)
 {
        struct ooh323_pvt *p = NULL;
-       struct sockaddr_in them;
+       struct ast_sockaddr tmp;
 
        if (gH323Debug)
-               ast_verbose("---   setup_rtp_connection\n");
+               ast_verbose("---   setup_rtp_connection %s:%d\n", remoteIp, remotePort);
 
        /* Find the call or allocate a private structure if call not found */
        p = find_call(call); 
@@ -2984,14 +4329,16 @@ void setup_rtp_connection(ooCallData *call, const char *remoteIp,
                return;
        }
 
-       them.sin_family = AF_INET;
-       them.sin_addr.s_addr = inet_addr(remoteIp); /* only works for IPv4 */
-       them.sin_port = htons(remotePort);
-       ast_rtp_set_peer(p->rtp, &them);
+       ast_parse_arg(remoteIp, PARSE_ADDR, &tmp);
+       ast_sockaddr_set_port(&tmp, remotePort);
+       ast_rtp_instance_set_remote_address(p->rtp, &tmp);
 
-       if (gH323Debug) {
+       if (p->writeformat.id == AST_FORMAT_G726_AAL2) 
+                ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, 2,
+                                                       "audio", "G726-32", AST_RTP_OPT_G726_NONSTANDARD);
+
+       if(gH323Debug)
                ast_verbose("+++   setup_rtp_connection\n");
-       }
 
        return;
 }
@@ -3000,28 +4347,174 @@ void close_rtp_connection(ooCallData *call)
 {
        struct ooh323_pvt *p = NULL;
 
-       if (gH323Debug) {
+   if(gH323Debug)
                ast_verbose("---   close_rtp_connection\n");
-       }
 
        p = find_call(call);
        if (!p) {
-               ast_log(LOG_ERROR, "Couldn't find matching call to close rtp connection\n");
+      ast_log(LOG_ERROR, "Couldn't find matching call to close rtp "
+                         "connection\n");
                return;
        }
        ast_mutex_lock(&p->lock);
        if (p->rtp) {
-               ast_rtp_stop(p->rtp);
+               ast_rtp_instance_stop(p->rtp);
        }
        ast_mutex_unlock(&p->lock);
 
-       if (gH323Debug) {
+   if(gH323Debug)
                ast_verbose("+++   close_rtp_connection\n");
+
+       return;
+}
+
+/*
+ udptl handling functions
+ */
+
+static struct ast_udptl *ooh323_get_udptl_peer(struct ast_channel *chan)
+{
+       struct ooh323_pvt *p;
+       struct ast_udptl *udptl = NULL;
+
+       p = chan->tech_pvt;
+       if (!p)
+               return NULL;
+
+       ast_mutex_lock(&p->lock);
+       if (p->udptl)
+               udptl = p->udptl;
+       ast_mutex_unlock(&p->lock);
+       return udptl;
+}
+
+static int ooh323_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl)
+{
+       struct ooh323_pvt *p;
+
+       p = chan->tech_pvt;
+       if (!p)
+               return -1;
+       ast_mutex_lock(&p->lock);
+
+       if (udptl) {
+               ast_udptl_get_peer(udptl, &p->udptlredirip);
+       } else
+               memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
+
+       ast_mutex_unlock(&p->lock);
+       /* free(callToken); */
+       return 0;
+}
+
+void setup_udptl_connection(ooCallData *call, const char *remoteIp, 
+                                                                 int remotePort)
+{
+       struct ooh323_pvt *p = NULL;
+       struct ast_sockaddr them;
+
+       if (gH323Debug)
+               ast_verbose("---   setup_udptl_connection\n");
+
+       /* Find the call or allocate a private structure if call not found */
+       p = find_call(call); 
+
+       if (!p) {
+               ast_log(LOG_ERROR, "Something is wrong: rtp\n");
+               return;
+       }
+
+       ast_mutex_lock(&p->lock);
+       if (p->owner) {
+               while (p->owner && ast_channel_trylock(p->owner)) {
+                       ast_debug(1, "Failed to grab lock, trying again\n");
+                       DEADLOCK_AVOIDANCE(&p->lock);
+               }
+               if (!p->owner) {
+                       ast_mutex_unlock(&p->lock);
+                       ast_log(LOG_ERROR, "Channel has no owner\n");
+                       return;
+               }
+       } else {
+               ast_mutex_unlock(&p->lock);
+               ast_log(LOG_ERROR, "Channel has no owner\n");
+               return;
+       }
+
+       ast_parse_arg(remoteIp, PARSE_ADDR, &them);
+       ast_sockaddr_set_port(&them, remotePort);
+
+       ast_udptl_set_peer(p->udptl, &them);
+       ast_udptl_set_tag(p->udptl, "%s", p->owner->name);
+       p->t38_tx_enable = 1;
+       p->lastTxT38 = time(NULL);
+       if (p->t38support == T38_ENABLED) {
+               struct ast_control_t38_parameters parameters = { .request_response = 0 };
+               parameters.request_response = AST_T38_NEGOTIATED;
+               parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl);
+               parameters.rate = AST_T38_RATE_14400;
+               ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
+       }
+       if (gH323Debug)
+               ast_debug(1, "Receiving UDPTL  %s:%s\n", ast_sockaddr_stringify_host(&them),
+                                                       ast_sockaddr_stringify_port(&them));
+
+       ast_channel_unlock(p->owner);
+       ast_mutex_unlock(&p->lock);
+
+       if(gH323Debug)
+               ast_verbose("+++   setup_udptl_connection\n");
+
+       return;
+}
+
+void close_udptl_connection(ooCallData *call)
+{
+       struct ooh323_pvt *p = NULL;
+
+       if(gH323Debug)
+               ast_verbose("---   close_udptl_connection\n");
+
+       p = find_call(call);
+       if (!p) {
+               ast_log(LOG_ERROR, "Couldn't find matching call to close udptl "
+                         "connection\n");
+               return;
+       }
+       ast_mutex_lock(&p->lock);
+       if (p->owner) {
+               while (p->owner && ast_channel_trylock(p->owner)) {
+                       ast_debug(1, "Failed to grab lock, trying again\n");
+                       DEADLOCK_AVOIDANCE(&p->lock);
+               }
+               if (!p->owner) {
+                       ast_mutex_unlock(&p->lock);
+                       ast_log(LOG_ERROR, "Channel has no owner\n");
+                       return;
+               }
+       } else {
+               ast_mutex_unlock(&p->lock);
+               ast_log(LOG_ERROR, "Channel has no owner\n");
+               return;
+       }
+
+       p->t38_tx_enable = 0;
+       if (p->t38support == T38_ENABLED) {
+               struct ast_control_t38_parameters parameters = { .request_response = 0 };
+               parameters.request_response = AST_T38_TERMINATED;
+               ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
        }
 
+       ast_channel_unlock(p->owner);
+       ast_mutex_unlock(&p->lock);
+
+       if(gH323Debug)
+               ast_verbose("+++   close_udptl_connection\n");
+
        return;
 }
 
+/* end of udptl handling */
 
 int update_our_aliases(ooCallData *call, struct ooh323_pvt *p)
 {
@@ -3036,7 +4529,8 @@ int update_our_aliases(ooCallData *call, struct ooh323_pvt *p)
                        updated = 1;
                }
                if (psAlias->type == T_H225AliasAddress_dialedDigits) {
-                       ast_copy_string(p->callee_dialedDigits, psAlias->value, sizeof(p->callee_dialedDigits));
+         ast_copy_string(p->callee_dialedDigits, psAlias->value, 
+                                        sizeof(p->callee_dialedDigits));
                        updated = 1;
                }
                if (psAlias->type == T_H225AliasAddress_url_ID) {
@@ -3055,47 +4549,192 @@ struct ast_frame *ooh323_rtp_read(struct ast_channel *ast, struct ooh323_pvt *p)
 {
        /* Retrieve audio/etc from channel.  Assumes p->lock is already held. */
        struct ast_frame *f;
+       struct ast_frame *dfr = NULL;
        static struct ast_frame null_frame = { AST_FRAME_NULL, };
        switch (ast->fdno) {
        case 0:
-               f = ast_rtp_read(p->rtp);       /* RTP Audio */
+               f = ast_rtp_instance_read(p->rtp, 0);   /* RTP Audio */
                break;
        case 1:
-               f = ast_rtcp_read(p->rtp);      /* RTCP Control Channel */
+               f = ast_rtp_instance_read(p->rtp, 1);   /* RTCP Control Channel */
                break;
        case 2:
-               f = ast_rtp_read(p->vrtp);      /* RTP Video */
+               f = ast_rtp_instance_read(p->vrtp, 0);  /* RTP Video */
                break;
        case 3:
-               f = ast_rtcp_read(p->vrtp);     /* RTCP Control Channel for video */
+               f = ast_rtp_instance_read(p->vrtp, 1);  /* RTCP Control Channel for video */
                break;
+       case 5:
+               f = ast_udptl_read(p->udptl);           /* UDPTL t.38 data */
+               if (gH323Debug) {
+                        ast_debug(1, "Got UDPTL %d/%d len %d for %s\n",
+                               f->frametype, f->subclass.integer, f->datalen, ast->name);
+               }
+               break;
+
        default:
                f = &null_frame;
        }
-       /* Don't send RFC2833 if we're not supposed to */
-       if (f && (f->frametype == AST_FRAME_DTMF) && !(p->dtmfmode & H323_DTMF_RFC2833)) {
-               return &null_frame;
-       }
-       if (p->owner) {
+
+       if (p->owner && !p->faxmode && (f->frametype == AST_FRAME_VOICE)) {
                /* We already hold the channel lock */
-               if (f->frametype == AST_FRAME_VOICE) {
-                       if (f->subclass != p->owner->nativeformats) {
-                               ast_debug(1, "Oooh, format changed to %d\n", f->subclass);
-                               p->owner->nativeformats = f->subclass;
-                               ast_set_read_format(p->owner, p->owner->readformat);
-                               ast_set_write_format(p->owner, p->owner->writeformat);
-                       }
-                       if ((p->dtmfmode & H323_DTMF_INBAND) && p->vad) {
-                               f = ast_dsp_process(p->owner, p->vad, f);
-                               if (f && (f->frametype == AST_FRAME_DTMF)) {
-                                       ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass);
+               if (!(ast_format_cap_iscompatible(p->owner->nativeformats, &f->subclass.format))) {
+                       ast_debug(1, "Oooh, voice format changed to %s\n", ast_getformatname(&f->subclass.format));
+                       ast_format_cap_set(p->owner->nativeformats, &f->subclass.format);
+                       ast_set_read_format(p->owner, &p->owner->readformat);
+                       ast_set_write_format(p->owner, &p->owner->writeformat);
+               }
+               if (((p->dtmfmode & H323_DTMF_INBAND) || (p->faxdetect & FAXDETECT_CNG)) && p->vad &&
+                   (f->subclass.format.id == AST_FORMAT_SLINEAR || f->subclass.format.id == AST_FORMAT_ALAW ||
+                    f->subclass.format.id == AST_FORMAT_ULAW)) {
+                       dfr = ast_frdup(f);
+                       dfr = ast_dsp_process(p->owner, p->vad, dfr);
+               }
+       } else {
+               return f;
+       }
+
+       /* process INBAND DTMF*/
+       if (dfr && (dfr->frametype == AST_FRAME_DTMF) && ((dfr->subclass.integer == 'f') || (dfr->subclass.integer == 'e'))) {
+               ast_debug(1, "* Detected FAX Tone %s\n", (dfr->subclass.integer == 'e') ? "CED" : "CNG");
+               /* Switch to T.38 ON CED*/
+               if (!p->faxmode && !p->chmodepend && (dfr->subclass.integer == 'e') && (p->t38support != T38_DISABLED)) {
+                       if (gH323Debug)
+                               ast_verbose("request to change %s to t.38 because fax ced\n", p->callToken);
+                       p->chmodepend = 1;
+                       p->faxdetected = 1;
+                       ooRequestChangeMode(p->callToken, 1);
+               } else if ((dfr->subclass.integer == 'f') && !p->faxdetected) {
+                       const char *target_context = S_OR(p->owner->macrocontext, p->owner->context);
+                       if ((strcmp(p->owner->exten, "fax")) &&
+                           (ast_exists_extension(p->owner, target_context, "fax", 1,
+                           S_COR(p->owner->caller.id.number.valid, p->owner->caller.id.number.str, NULL)))) {
+                               ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n", p->owner->name);
+                               pbx_builtin_setvar_helper(p->owner, "FAXEXTEN", p->owner->exten);
+                               if (ast_async_goto(p->owner, target_context, "fax", 1)) {
+                                       ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", p->owner->name,target_context);
+                               }
+                               p->faxdetected = 1;
+                               if (dfr) {
+                                       ast_frfree(dfr);
                                }
+                               return &ast_null_frame;
                        }
                }
+       } else if (dfr && dfr->frametype == AST_FRAME_DTMF) {
+               ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass.integer);
+               ast_frfree(f);
+               return dfr;
+       }
+
+       if (dfr) {
+               ast_frfree(dfr);
        }
        return f;
 }
 
+void onModeChanged(ooCallData *call, int t38mode) {
+        struct ooh323_pvt *p;
+
+       p = find_call(call);
+       if (!p) {
+               ast_log(LOG_ERROR, "No matching call found for %s\n", call->callToken);
+               return;
+       }
+
+       ast_mutex_lock(&p->lock);
+
+       if (gH323Debug)
+                       ast_debug(1, "change mode to %d for %s\n", t38mode, call->callToken);
+
+       if (t38mode == p->faxmode) {
+               if (gH323Debug)
+                       ast_debug(1, "mode for %s is already %d\n", call->callToken,
+                                       t38mode);
+               p->chmodepend = 0;
+               ast_mutex_unlock(&p->lock);
+               return;
+       }
+
+       if (p->owner) {
+               while (p->owner && ast_channel_trylock(p->owner)) {
+                       ast_debug(1,"Failed to grab lock, trying again\n");
+                       DEADLOCK_AVOIDANCE(&p->lock);
+               }
+               if (!p->owner) {
+                       p->chmodepend = 0;
+                       ast_mutex_unlock(&p->lock);
+                       ast_log(LOG_ERROR, "Channel has no owner\n");
+                       return;
+               }
+       } else {
+               p->chmodepend = 0;
+               ast_mutex_unlock(&p->lock);
+               ast_log(LOG_ERROR, "Channel has no owner\n");
+               return;
+       }
+
+       if (t38mode) {
+
+
+               if (p->t38support == T38_ENABLED) {
+                       struct ast_control_t38_parameters parameters = { .request_response = 0 };
+
+                       if ((p->faxdetect & FAXDETECT_T38) && !p->faxdetected) {
+                                       const char *target_context;
+                               ast_debug(1, "* Detected T.38 Request\n");
+                               target_context = S_OR(p->owner->macrocontext, p->owner->context);
+                               if ((strcmp(p->owner->exten, "fax")) &&
+                                       (ast_exists_extension(p->owner, target_context, "fax", 1,
+                                       S_COR(p->owner->caller.id.number.valid, p->owner->caller.id.number.str, NULL)))) {
+                                       ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n", p->owner->name);
+                                       pbx_builtin_setvar_helper(p->owner, "FAXEXTEN", p->owner->exten);
+                                       if (ast_async_goto(p->owner, target_context, "fax", 1)) {
+                                               ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", p->owner->name,target_context);
+                                       }
+                                }
+                                p->faxdetected = 1;
+                       }
+
+/* AST_T38_CONTROL mode */
+
+                       parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
+                       if (call->T38FarMaxDatagram) {
+                               ast_udptl_set_far_max_datagram(p->udptl, call->T38FarMaxDatagram);
+                       } else {
+                               ast_udptl_set_far_max_datagram(p->udptl, 144);
+                       }
+                       if (call->T38Version) {
+                               parameters.version = call->T38Version;
+                       }
+                       parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl);
+                       parameters.rate = AST_T38_RATE_14400;
+                       ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, 
+                                                       &parameters, sizeof(parameters));
+                       p->faxmode = 1;
+
+
+               }
+       } else {
+               if (p->t38support == T38_ENABLED) {
+                       struct ast_control_t38_parameters parameters = { .request_response = 0 };
+                       parameters.request_response = AST_T38_REQUEST_TERMINATE;
+                       parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl);
+                       parameters.rate = AST_T38_RATE_14400;
+                       ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, 
+                                                       &parameters, sizeof(parameters));
+               }
+               p->faxmode = 0;
+               p->faxdetected = 0;
+               p->t38_init = 0;
+       }
+
+       p->chmodepend = 0;
+       ast_channel_unlock(p->owner);
+       ast_mutex_unlock(&p->lock);
+}
+
+
 
 int ooh323_convert_hangupcause_asteriskToH323(int cause)
 {
@@ -3120,6 +4759,8 @@ int ooh323_convert_hangupcause_asteriskToH323(int cause)
        }
 
        return 0;
+
+
 }
 
 int ooh323_convert_hangupcause_h323ToAsterisk(int cause)