Merged revisions 338995 via svnmerge from
[asterisk/asterisk.git] / addons / chan_ooh323.c
index 1b6c0ce..621459a 100644 (file)
@@ -19,6 +19,7 @@
 
 /*** MODULEINFO
        <defaultenabled>no</defaultenabled>
+       <support_level>extended</support_level>
  ***/
 
 #include "chan_ooh323.h"
@@ -49,6 +50,9 @@
 #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";
@@ -78,6 +82,8 @@ 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);
@@ -111,7 +117,8 @@ static struct ast_channel_tech ooh323_tech = {
        .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_glue ooh323_rtp = {
@@ -138,12 +145,14 @@ static struct ooh323_pvt {
        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 sockaddr_in udptlredirip;
+       struct ast_sockaddr udptlredirip;
        time_t lastTxT38;
        int chmodepend;
 
@@ -199,25 +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;
+       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         dtmfcodec;
-       int         t38support;
-       int         rtptimeout;
-       int         mUseIP;        /* Use IP address or H323-ID to search user */
-       char        mIP[20];
-       struct OOH323Regex          *rtpmask;
-       char        rtpmaskstr[120];
-       int         rtdrcount, rtdrinterval;
-       int         faststart, h245tunneling;
-       int         g729onlyA;
+       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;
 };
 
@@ -233,9 +243,10 @@ struct ooh323_peer{
        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*/
@@ -286,13 +297,16 @@ void onModeChanged(ooCallData *call, int t38mode);
 
 static char gLogFile[256] = DEFAULT_LOGFILE;
 static int  gPort = 1720;
-static char gIP[20];
+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 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;
@@ -341,10 +355,12 @@ static pthread_t monitor_thread = AST_PTHREADT_NULL;
 
 
 static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
-                                             const char *host, struct ast_format_cap *cap, const char *linkedid) 
+                                             const char *host, struct ast_format_cap *cap, const char *linkedid)
 {
        struct ast_channel *ch = NULL;
        struct ast_format tmpfmt;
+       int features = 0;
+
        if (gH323Debug)
                ast_verbose("---   ooh323_new - %s\n", host);
 
@@ -373,10 +389,6 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
                ast_format_copy(&ch->rawwriteformat, &tmpfmt);
                ast_format_copy(&ch->rawreadformat, &tmpfmt);
 
-               ast_channel_set_fd(ch, 0, ast_rtp_instance_fd(i->rtp, 0));
-               ast_channel_set_fd(ch, 1, ast_rtp_instance_fd(i->rtp, 1));
-               ast_channel_set_fd(ch, 5, ast_udptl_fd(i->udptl));
-
                ast_jb_configure(ch, &global_jbconf);
 
                if (state == AST_STATE_RING)
@@ -390,16 +402,27 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
                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);
-                               ast_dsp_set_features(i->vad,
-                                               DSP_FEATURE_DIGIT_DETECT | DSP_FEATURE_FAX_DETECT);
-                       ast_dsp_set_faxmode(i->vad,
-                                               DSP_FAXMODE_DETECT_CNG | DSP_FAXMODE_DETECT_CED);
+               }
 
-                       if (i->dtmfmode & H323_DTMF_INBANDRELAX)
+               /* 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);
@@ -468,9 +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 sockaddr_in ouraddr;
-       struct ast_sockaddr tmp;
-       struct in_addr ipAddr;
+
        if (gH323Debug)
                ast_verbose("---   ooh323_alloc\n");
 
@@ -487,41 +508,10 @@ static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken)
        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);
-               ast_free(pvt);
-               return NULL;
-       }
-
-       ouraddr.sin_family = AF_INET;
-       ouraddr.sin_addr = ipAddr;
-       ast_sockaddr_from_sin(&tmp, &ouraddr);
-       if (!(pvt->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
-               ast_log(LOG_WARNING, "Unable to create RTP session: %s\n", 
-                                 strerror(errno));
-               ast_mutex_unlock(&pvt->lock);
-               ast_mutex_destroy(&pvt->lock);
-               ast_free(pvt);
-               return NULL;
-       }
-       ast_rtp_instance_set_qos(pvt->rtp, gTOS, 0, "ooh323-rtp");
-
-       if (!(pvt->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, &tmp))) {
-               ast_log(LOG_WARNING, "Unable to create UDPTL session: %s\n",
-                               strerror(errno));
-               ast_mutex_unlock(&pvt->lock);
-               ast_mutex_destroy(&pvt->lock);
-               ast_free(pvt);
-               return NULL;
-       }
-
-       ast_udptl_set_error_correction_scheme(pvt->udptl, UDPTL_ERROR_CORRECTION_NONE);
-       ast_udptl_set_far_max_datagram(pvt->udptl, 144);
        pvt->faxmode = 0;
+       pvt->chmodepend = 0;
+       pvt->faxdetected = 0;
+       pvt->faxdetect = gFAXdetect;
        pvt->t38support = gT38Support;
        pvt->rtptimeout = gRTPTimeout;
        pvt->rtdrinterval = gRTDRInterval;
@@ -648,6 +638,7 @@ static struct ast_channel *ooh323_request(const char *type, struct ast_format_ca
                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;
@@ -677,6 +668,7 @@ static struct ast_channel *ooh323_request(const char *type, struct ast_format_ca
                p->g729onlyA = g729onlyA;
                p->dtmfmode = gDTMFMode;
                p->dtmfcodec = gDTMFCodec;
+               p->faxdetect = gFAXdetect;
                p->t38support = gT38Support;
                p->rtptimeout = gRTPTimeout;
                ast_format_cap_copy(p->cap, gCap);
@@ -866,17 +858,7 @@ static int ooh323_digit_begin(struct ast_channel *chan, char digit)
        }
        ast_mutex_lock(&p->lock);
 
-
-       if (digit == 'e' && !p->faxmode && p->t38support != T38_DISABLED)  {
-               if (!p->chmodepend) {
-                       if (gH323Debug)
-                               ast_verbose("request to change %s to t.38 because fax cng\n",
-                                               p->callToken);
-                       p->chmodepend = 1;
-                       ooRequestChangeMode(p->callToken, 1);
-               }
-
-       } else if (p->rtp && ((p->dtmfmode & H323_DTMF_RFC2833) || (p->dtmfmode & H323_DTMF_CISCO))) {
+       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) ||
@@ -1046,13 +1028,13 @@ static int ooh323_hangup(struct ast_channel *ast)
 
                if (gH323Debug)
                        ast_verbose("    hanging %s with cause: %d\n", p->username, q931cause);
-               ast->tech_pvt = NULL;
+               ast->tech_pvt = NULL; 
                if (!ast_test_flag(p, H323_ALREADYGONE)) {
-                       ooHangCall(p->callToken,
+                       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) {
@@ -1068,11 +1050,11 @@ static int ooh323_hangup(struct ast_channel *ast)
 
                /* Notify the module monitors that use count for resource has changed */
                ast_update_use_count();
-
+         
        } else {
                ast_debug(1, "No call to hangup\n" );
        }
-
+       
        if (gH323Debug)
                ast_verbose("+++   ooh323_hangup\n");
 
@@ -1082,6 +1064,7 @@ 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");
@@ -1089,13 +1072,27 @@ static int ooh323_answer(struct ast_channel *ast)
        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);
-                       ast_debug(1, "ooh323_answer(%s)\n", ast->name);
+                       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);
        }
 
@@ -1141,10 +1138,11 @@ static int ooh323_write(struct ast_channel *ast, struct ast_frame *f)
                        return res;
                }
 
+       
                if (f->frametype == AST_FRAME_VOICE) {
 /* sending progress for first */
                        if (!ast_test_flag(p, H323_OUTGOING) && !p->progsent &&
-                                       p->callToken) {
+                                       p->callToken) {
                                ooManualProgress(p->callToken);
                                p->progsent = 1;
                        }
@@ -1193,6 +1191,7 @@ 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;
 
@@ -1208,13 +1207,16 @@ 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);
+        
+       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)) {
-                       ooHangCall(callToken, OO_REASON_LOCAL_CONGESTED,
-                                               AST_CAUSE_SWITCH_CONGESTION);
+                       ooHangCall(callToken, OO_REASON_LOCAL_CONGESTED, AST_CAUSE_SWITCH_CONGESTION);
                        ast_set_flag(p, H323_ALREADYGONE);
                }
                break;
@@ -1232,15 +1234,15 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d
                break;
        case AST_CONTROL_PROGRESS:
                if (ast->_state != AST_STATE_UP) {
-                       if (!p->progsent) {
-                               if (gH323Debug) {
+                       if (!p->progsent) {
+                               if (gH323Debug) {
                                        ast_debug(1, "Sending manual progress for %s, res = %d\n", callToken,
-                                       ooManualProgress(callToken));
+                                       ooManualProgress(callToken));   
                                } else {
-                                       ooManualProgress(callToken);
+                                       ooManualProgress(callToken);
                                }
-                               p->progsent = 1;
-                       }
+                               p->progsent = 1;
+                       }
                }
            break;
       case AST_CONTROL_RINGING:
@@ -1255,13 +1257,18 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d
                                }
                                p->alertsent = 1;
                        }
+                       p->alertsent = 1;
                }
         break;
        case AST_CONTROL_SRCUPDATE:
-               ast_rtp_instance_update_source(p->rtp);
+               if (p->rtp) {
+                       ast_rtp_instance_update_source(p->rtp);
+               }
                break;
        case AST_CONTROL_SRCCHANGE:
-               ast_rtp_instance_change_source(p->rtp);
+               if (p->rtp) {
+                       ast_rtp_instance_change_source(p->rtp);
+               }
                break;
        case AST_CONTROL_CONNECTED_LINE:
                if (!ast->connected.id.name.valid
@@ -1289,25 +1296,50 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d
                                (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->chmodepend && !p->faxmode) {
-                                       ooRequestChangeMode(p->callToken, 1);
+                               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->chmodepend && p->faxmode) {
-                                       ooRequestChangeMode(p->callToken, 0);
+                               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:
                                ;
@@ -1330,7 +1362,7 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d
                ast_verbose("++++  ooh323_indicate %d on %s\n", condition, callToken);
 
        free(callToken);
-       return -1;
+       return res;
 }
 
 static int ooh323_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
@@ -1353,17 +1385,18 @@ static int ooh323_queryoption(struct ast_channel *ast, int option, void *data, i
                case AST_OPTION_T38_STATE:
 
                        if (*datalen != sizeof(enum ast_t38_state)) {
-                               ast_log(LOG_ERROR, "Invalid datalen for AST_OPTION_T38_STATE option."
+                               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)
-                               state = T38_STATE_UNKNOWN;
-                       if (p->faxmode)
-                               state = (p->chmodepend) ? T38_STATE_UNKNOWN : T38_STATE_NEGOTIATED;
-                       else if (p->chmodepend)
-                               state = T38_STATE_NEGOTIATING;
 
+                       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;
@@ -1386,8 +1419,8 @@ static int ooh323_queryoption(struct ast_channel *ast, int option, void *data, i
 
        if (gH323Debug)
                ast_verbose("+++++ ooh323_queryoption %d on channel %s\n", option, ast->name);
-
-       ast_mutex_unlock(&p->lock);
+        
+       ast_mutex_unlock(&p->lock);
 
        return res;
 }
@@ -1431,9 +1464,9 @@ void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txfra
        char formats[FORMAT_STRING_SIZE];
 
        if (gH323Debug)
-               ast_verbose("---   ooh323_update_writeformat %s/%d\n",
+               ast_verbose("---   ooh323_update_writeformat %s/%d\n", 
                                ast_getformatname(fmt), txframes);
-
+       
        p = find_call(call);
        if (!p) {
                ast_log(LOG_ERROR, "No matching call found for %s\n", call->callToken);
@@ -1446,7 +1479,7 @@ void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txfra
 
        if (p->owner) {
                while (p->owner && ast_channel_trylock(p->owner)) {
-                       ast_debug(1, "Failed to grab lock, trying again\n");
+                       ast_debug(1,"Failed to grab lock, trying again\n");
                        DEADLOCK_AVOIDANCE(&p->lock);
                }
                if (!p->owner) {
@@ -1455,7 +1488,7 @@ void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txfra
                        return;
                }
                if (gH323Debug)
-                       ast_verbose("Writeformat before update %s/%s\n",
+                       ast_verbose("Writeformat before update %s/%s\n", 
                          ast_getformatname(&p->owner->writeformat),
                          ast_getformatname_multiple(formats, sizeof(formats), p->owner->nativeformats));
                if (txframes)
@@ -1491,7 +1524,7 @@ void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt)
        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);
@@ -1504,7 +1537,7 @@ void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt)
 
        if (p->owner) {
                while (p->owner && ast_channel_trylock(p->owner)) {
-                       ast_debug(1, "Failed to grab lock, trying again\n");
+                       ast_debug(1,"Failed to grab lock, trying again\n");
                        DEADLOCK_AVOIDANCE(&p->lock);
                }
                if (!p->owner) {
@@ -1514,12 +1547,12 @@ void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt)
                }
 
                if (gH323Debug)
-                       ast_verbose("Readformat before update %s\n",
+                       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_set_read_format(p->owner, &p->owner->readformat);
                ast_channel_unlock(p->owner);
-       } else
+       } else
                ast_log(LOG_ERROR, "No owner found\n");
 
        ast_mutex_unlock(&p->lock);
@@ -1537,12 +1570,12 @@ int onAlerting(ooCallData *call)
        if (gH323Debug)
                ast_verbose("--- onAlerting %s\n", call->callToken);
 
-       p = find_call(call);
+       p = find_call(call);
 
-       if(!p) {
+       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);
@@ -1593,12 +1626,12 @@ int onProgress(ooCallData *call)
        if (gH323Debug)
                ast_verbose("--- onProgress %s\n", call->callToken);
 
-       p = find_call(call);
+       p = find_call(call);
 
-       if(!p) {
+       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);
@@ -1632,8 +1665,8 @@ int onProgress(ooCallData *call)
                ast_setstate(c, AST_STATE_RINGING);
 
        ast_queue_control(c, AST_CONTROL_PROGRESS);
-       ast_channel_unlock(c);
-       ast_mutex_unlock(&p->lock);
+       ast_channel_unlock(c);
+       ast_mutex_unlock(&p->lock);
 
        if (gH323Debug)
                ast_verbose("+++ onProgress %s\n", call->callToken);
@@ -1779,6 +1812,7 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg)
                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;
@@ -1812,10 +1846,14 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg)
        } else {
          ast_mutex_unlock(&p->lock);
          ast_log(LOG_ERROR, "Unacceptable ip %s\n", call->remoteIP);
-         if (!user) 
+         if (!user) {
           ooHangCall(call->callToken, ooh323_convert_hangupcause_asteriskToH323(AST_CAUSE_CALL_REJECTED), AST_CAUSE_CALL_REJECTED);
-         else
+          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;
         }
@@ -1823,15 +1861,19 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg)
 
        ooh323c_set_capability_for_call(call, &p->prefs, p->cap, p->dtmfmode, p->dtmfcodec,
                                         p->t38support, p->g729onlyA);
-       configure_local_rtp(p, call);
-
 /* 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);
 
        if (gH323Debug)
@@ -1902,6 +1944,11 @@ int onOutgoingCall(ooCallData *call)
                        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);
        }
 
@@ -1991,7 +2038,7 @@ int onNewCallCreated(ooCallData *call)
                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);
        }
 
@@ -2014,14 +2061,14 @@ int onCallEstablished(ooCallData *call)
                return -1;
        }
 
-       if(ast_test_flag(p, H323_OUTGOING)) {
+       if(ast_test_flag(p, H323_OUTGOING)) {
                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 (p->owner && ast_channel_trylock(p->owner)) {
                        ast_debug(1, "Failed to grab lock, trying again\n");
                        DEADLOCK_AVOIDANCE(&p->lock);
@@ -2043,7 +2090,7 @@ int onCallEstablished(ooCallData *call)
                        }
 
                        ast_queue_control(c, AST_CONTROL_ANSWER);
-                       ast_channel_unlock(p->owner);
+                       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);
                }
@@ -2068,42 +2115,42 @@ int onCallCleared(ooCallData *call)
 
    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_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)) {
+               if (!ast_test_flag(p, H323_ALREADYGONE)) { 
 
                        ast_set_flag(p, H323_ALREADYGONE);
                        p->owner->hangupcause = call->q931cause;
                        p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
                        ast_queue_hangup_with_cause(p->owner,call->q931cause);
                }
-       }
+       }
 
-       if(p->owner) {
-               p->owner->tech_pvt = NULL;
+       if(p->owner) {
+               p->owner->tech_pvt = NULL;
                ast_channel_unlock(p->owner);
-               p->owner = NULL;
+               p->owner = NULL;
                ast_module_unref(myself);
        }
 
        ast_set_flag(p, H323_NEEDDESTROY);
 
-       ooh323c_stop_call_thread(call);
+       ooh323c_stop_call_thread(call);
 
        ast_mutex_unlock(&p->lock);
-       ast_mutex_lock(&usecnt_lock);
-       usecnt--;
-       ast_mutex_unlock(&usecnt_lock);
+       ast_mutex_lock(&usecnt_lock);
+       usecnt--;
+       ast_mutex_unlock(&usecnt_lock);
 
     }
 
@@ -2206,6 +2253,7 @@ static struct ooh323_user *build_user(const char *name, struct ast_variable *v)
                user->rtptimeout = gRTPTimeout;
                user->dtmfmode = gDTMFMode;
                user->dtmfcodec = gDTMFCodec;
+               user->faxdetect = gFAXdetect;
                user->t38support = gT38Support;
                user->faststart = gFastStart;
                user->h245tunneling = gTunneling;
@@ -2258,12 +2306,14 @@ static struct ooh323_user *build_user(const char *name, struct ast_variable *v)
                                         user->cap,  tcodecs, 1);
                        } else if (!strcasecmp(v->name, "amaflags")) {
                                user->amaflags = ast_cdr_amaflags2int(v->value);
-                       } else if (!strcasecmp(v->name, "ip")) {
-                               strncpy(user->mIP, v->value, sizeof(user->mIP)-1);
+                       } 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, "host")) {
-                               strncpy(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;
@@ -2281,7 +2331,27 @@ static struct ooh323_user *build_user(const char *name, struct ast_variable *v)
                                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, "t38support")) {
+                       } 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"))
@@ -2324,11 +2394,12 @@ static struct ooh323_peer *build_peer(const char *name, struct ast_variable *v,
                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;
+               peer->port = 1720;
                if (0 == friend_type) {
                        peer->mFriend = 1;
                }
@@ -2364,10 +2435,14 @@ 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")) {
-                               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")) {
                                peer->outgoinglimit = atoi(v->value);
                                if (peer->outgoinglimit < 0)
@@ -2424,7 +2499,27 @@ static struct ooh323_peer *build_peer(const char *name, struct ast_variable *v,
                                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, "t38support")) {
+                       } 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"))
@@ -2546,6 +2641,7 @@ int reload_config(int reload)
        memset(&gPrefs, 0, sizeof(struct ast_codec_pref));
        gDTMFMode = H323_DTMF_RFC2833;
        gDTMFCodec = 101;
+       gFAXdetect = FAXDETECT_CNG;
        gT38Support = T38_FAXGW;
        gTRCLVL = OOTRCLVLERR;
        gRasGkMode = RasNoGatekeeper;
@@ -2576,6 +2672,13 @@ int reload_config(int reload)
                        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[512];
@@ -2742,7 +2845,27 @@ int reload_config(int reload)
                        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, "t38support")) {
+               } 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"))
@@ -2795,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;
@@ -2829,14 +2952,13 @@ static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struc
        if (a->argc != 4)
                return CLI_SHOWUSAGE;
 
        ast_mutex_lock(&peerl.lock);
        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);
@@ -2844,53 +2966,64 @@ static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struc
        }
 
        if (peer) {
-      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",
+               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: ");
+               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_CISCO) {
-         ast_cli(a->fd, "%s\n", "cisco");
-        ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", peer->dtmfcodec);
+                       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");
-        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)
-         ast_cli(a->fd, "%s\n", "h245alphanumeric");
-               else if (peer->dtmfmode & H323_DTMF_H245SIGNAL)
-         ast_cli(a->fd, "%s\n", "h245signal");
-               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");
+                       ast_cli(a->fd, "%s\n", "rfc2833");
+                       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) {
+                       ast_cli(a->fd, "%s\n", "h245alphanumeric");
+               } else if (peer->dtmfmode & H323_DTMF_H245SIGNAL) {
+                       ast_cli(a->fd, "%s\n", "h245signal");
+               } 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%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);
+               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%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]);
-       ast_cli(a->fd, "\n");
+               ast_cli(a->fd, "Peer %s not found\n", a->argv[3]);
+               ast_cli(a->fd, "\n");
        }
        ast_mutex_unlock(&peerl.lock);
 
@@ -2980,9 +3113,9 @@ static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struc
        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);
@@ -2990,53 +3123,64 @@ 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",
+               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: ");
+               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_CISCO) {
-         ast_cli(a->fd, "%s\n", "cisco");
-        ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", user->dtmfcodec);
+                       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");
-        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)
-         ast_cli(a->fd, "%s\n", "h245alphanumeric");
-               else if (user->dtmfmode & H323_DTMF_H245SIGNAL)
-         ast_cli(a->fd, "%s\n", "h245signal");
-               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");
+                       ast_cli(a->fd, "%s\n", "rfc2833");
+                       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) {
+                       ast_cli(a->fd, "%s\n", "h245alphanumeric");
+               } else if (user->dtmfmode & H323_DTMF_H245SIGNAL) {
+                       ast_cli(a->fd, "%s\n", "h245signal");
+               } 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_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);
+               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");
+               ast_cli(a->fd, "User %s not found\n", a->argv[3]);
+               ast_cli(a->fd, "\n");
        }
        ast_mutex_unlock(&userl.lock);
 
@@ -3135,91 +3279,93 @@ static char *handle_cli_ooh323_show_config(struct ast_cli_entry *e, int cmd, str
        if (a->argc != 3)
                return CLI_SHOWUSAGE;
 
-
-
-   ast_cli(a->fd, "\nObjective Open H.323 Channel Driver's Config:\n");
+       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", "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");
 
 #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,FORMAT_STRING_SIZE,gCap));
-
-   ast_cli(a->fd, "%-20s", "DTMF Mode: ");
+       }
+       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_CISCO) {
-      ast_cli(a->fd, "%s\n", "cisco");
-      ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", gDTMFCodec);
+               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");
-      ast_cli(a->fd, "%-15.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)
-      ast_cli(a->fd, "%s\n", "h245alphanumeric");
-       else if (gDTMFMode & H323_DTMF_H245SIGNAL)
-      ast_cli(a->fd, "%s\n", "h245signal");
-               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", "rfc2833");
+               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) {
+               ast_cli(a->fd, "%s\n", "h245alphanumeric");
+       } else if (gDTMFMode & H323_DTMF_H245SIGNAL) {
+               ast_cli(a->fd, "%s\n", "h245signal");
+       } 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,"%-20s", "T.38 Mode: ");
+       if (gT38Support == T38_DISABLED) {
                ast_cli(a->fd, "%s\n", "disabled");
-       else if (gT38Support == T38_FAXGW)
+       } 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, "%-15.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);
+       if (gRTDRCount && gRTDRInterval) {
+               ast_cli(a->fd, "%-20.15s%d,%d\n", "RoundTrip: ", gRTDRCount, gRTDRInterval);
+       }
 
-   ast_cli(a->fd, "%-20s%s\n", "AMA flags: ", ast_cdr_flags2str(gAMAFLAGS));
+       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) {
-     ast_cli(a->fd, "%-20s\n", "Aliases: ");
-   }
+       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);
+               } else {
+                       ast_cli(a->fd,"\t%-30s\n",pAlias->value);
                        pAlias = pAlias->next;
                }
        }
@@ -3236,6 +3382,108 @@ static struct ast_cli_entry cli_ooh323[] = {
         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)
 {
@@ -3313,6 +3561,9 @@ static int load_module(void)
                ooH323EpSetH225MsgCallbacks(h225Callbacks);
                ooH323EpSetTraceLevel(gTRCLVL);
                ooH323EpSetLocalAddress(gIP, gPort);
+               if (v6mode) {
+                       ast_debug(1, "OOH323 channel is in IP6 mode\n");
+               }
                ooH323EpSetCallerID(gCallerID);
  
       if(ooH323EpSetTCPPortRange(ooconfig.mTCPPortStart, 
@@ -3550,7 +3801,7 @@ int ooh323_destroy(struct ooh323_pvt *p)
                        free(cur->callerid_name);
                        cur->callerid_name = 0;
                }
-
+               
                if (cur->callerid_num) {
                        free(cur->callerid_num);
                        cur->callerid_num = 0;
@@ -3565,20 +3816,20 @@ int ooh323_destroy(struct ooh323_pvt *p)
                        ast_udptl_destroy(cur->udptl);
                        cur->udptl = NULL;
                }
-
+       
                /* Unlink us from the owner if we have one */
                if (cur->owner) {
-                       while(ast_channel_trylock(cur->owner)) {
-                               ast_debug(1, "Failed to grab lock, trying again\n");
+                       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;
@@ -3677,7 +3928,7 @@ int delete_users()
        ast_mutex_unlock(&userl.lock);
        return 0;
 }
-  
+
 static int unload_module(void)
 {
        struct ooh323_pvt *p;
@@ -3793,7 +4044,7 @@ 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);
@@ -3903,8 +4154,6 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance
 {
        /* XXX Deal with Video */
        struct ooh323_pvt *p;
-       struct sockaddr_in them;
-       struct sockaddr_in us;
        struct ast_sockaddr tmp;
        int mode;
 
@@ -3922,10 +4171,13 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance
                return -1;
        }
        ast_rtp_instance_get_remote_address(rtp, &tmp);
-       ast_sockaddr_to_sin(&tmp, &them);
        ast_rtp_instance_get_local_address(rtp, &tmp);
-       ast_sockaddr_to_sin(&tmp, &us);
        return 0;
+
+/*     May 20101003 */
+/*     What we should to do here? */
+
+
 }
 
 
@@ -3933,7 +4185,7 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance
 
 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;
@@ -3944,6 +4196,46 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
        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_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &p->prefs);
                if (p->dtmfmode & H323_DTMF_RFC2833 && p->dtmfcodec) {
@@ -3958,7 +4250,8 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
                }
                /* figure out our local RTP port and tell the H.323 stack about it*/
                ast_rtp_instance_get_local_address(p->rtp, &tmp);
-               ast_sockaddr_to_sin(&tmp, &us);
+               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);
@@ -3975,8 +4268,8 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
        }
 
 
-       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; ast_codec_pref_index(&p->prefs, x, &tmpfmt); x++) {
                strcpy(mediaInfo.dir, "transmit");
@@ -4000,19 +4293,18 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
        }
 
        if (p->udptl) {
-               struct ast_sockaddr us_tmp;
-               ast_sockaddr_from_sin(&us_tmp, &us);
-               ast_udptl_get_us(p->udptl, &us_tmp);
-               ast_sockaddr_to_sin(&us_tmp, &us);
+               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);
        }
-       ast_copy_string(mediaInfo.lMediaIP, ast_inet_ntoa(us.sin_addr), sizeof(mediaInfo.lMediaIP));
-       mediaInfo.lMediaPort = ntohs(us.sin_port);
-       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");
@@ -4024,7 +4316,6 @@ 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)
@@ -4038,10 +4329,8 @@ 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_sockaddr_from_sin(&tmp, &them);
+       ast_parse_arg(remoteIp, PARSE_ADDR, &tmp);
+       ast_sockaddr_set_port(&tmp, remotePort);
        ast_rtp_instance_set_remote_address(p->rtp, &tmp);
 
        if (p->writeformat.id == AST_FORMAT_G726_AAL2) 
@@ -4107,10 +4396,9 @@ static int ooh323_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udp
        if (!p)
                return -1;
        ast_mutex_lock(&p->lock);
+
        if (udptl) {
-               struct ast_sockaddr udptl_addr;
-               ast_udptl_get_peer(udptl, &udptl_addr);
-               ast_sockaddr_to_sin(&udptl_addr, &p->udptlredirip);
+               ast_udptl_get_peer(udptl, &p->udptlredirip);
        } else
                memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
 
@@ -4123,14 +4411,13 @@ void setup_udptl_connection(ooCallData *call, const char *remoteIp,
                                                                  int remotePort)
 {
        struct ooh323_pvt *p = NULL;
-       struct sockaddr_in them;
-       struct ast_sockaddr them_addr;
+       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);
+       p = find_call(call); 
 
        if (!p) {
                ast_log(LOG_ERROR, "Something is wrong: rtp\n");
@@ -4154,12 +4441,11 @@ void setup_udptl_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_sockaddr_from_sin(&them_addr, &them);
-       ast_udptl_set_peer(p->udptl, &them_addr);
-       ast_udptl_set_tag(p->udptl, p->owner->name);
+       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) {
@@ -4170,8 +4456,8 @@ void setup_udptl_connection(ooCallData *call, const char *remoteIp,
                ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
        }
        if (gH323Debug)
-               ast_debug(1, "Receiving UDPTL  %s:%d\n", ast_inet_ntoa(them.sin_addr),
-                                                        ntohs(them.sin_port));
+               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);
@@ -4186,12 +4472,12 @@ void close_udptl_connection(ooCallData *call)
 {
        struct ooh323_pvt *p = NULL;
 
-       if(gH323Debug)
+       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 "
+               ast_log(LOG_ERROR, "Couldn't find matching call to close udptl "
                          "connection\n");
                return;
        }
@@ -4263,6 +4549,7 @@ 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:
@@ -4280,7 +4567,7 @@ struct ast_frame *ooh323_rtp_read(struct ast_channel *ast, struct ooh323_pvt *p)
        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",
+                        ast_debug(1, "Got UDPTL %d/%d len %d for %s\n",
                                f->frametype, f->subclass.integer, f->datalen, ast->name);
                }
                break;
@@ -4289,25 +4576,59 @@ struct ast_frame *ooh323_rtp_read(struct ast_channel *ast, struct ooh323_pvt *p)
                f = &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 && !p->faxmode) {
-                       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 (!(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;
+       }
 
-                       if ((p->dtmfmode & H323_DTMF_INBAND) && p->vad &&
-                               (f->subclass.format.id == AST_FORMAT_SLINEAR || f->subclass.format.id == AST_FORMAT_ALAW ||
-                                       f->subclass.format.id == AST_FORMAT_ULAW)) {
-                               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.integer);
+       /* 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;
 }
@@ -4323,15 +4644,14 @@ void onModeChanged(ooCallData *call, int t38mode) {
 
        ast_mutex_lock(&p->lock);
 
-       if (gH323Debug) {
-               ast_debug(1, "change mode to %d for %s\n", t38mode, call->callToken);
-       }
+       if (gH323Debug)
+                       ast_debug(1, "change mode to %d for %s\n", t38mode, call->callToken);
 
        if (t38mode == p->faxmode) {
-               if (gH323Debug) {
+               if (gH323Debug)
                        ast_debug(1, "mode for %s is already %d\n", call->callToken,
                                        t38mode);
-               }
+               p->chmodepend = 0;
                ast_mutex_unlock(&p->lock);
                return;
        }
@@ -4342,11 +4662,13 @@ void onModeChanged(ooCallData *call, int t38mode) {
                        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;
@@ -4356,10 +4678,26 @@ void onModeChanged(ooCallData *call, int 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 */
 
-                       struct ast_control_t38_parameters parameters = { .request_response = 0 };
                        parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
                        if (call->T38FarMaxDatagram) {
                                ast_udptl_set_far_max_datagram(p->udptl, call->T38FarMaxDatagram);
@@ -4375,6 +4713,7 @@ void onModeChanged(ooCallData *call, int t38mode) {
                                                        &parameters, sizeof(parameters));
                        p->faxmode = 1;
 
+
                }
        } else {
                if (p->t38support == T38_ENABLED) {
@@ -4386,6 +4725,7 @@ void onModeChanged(ooCallData *call, int t38mode) {
                                                        &parameters, sizeof(parameters));
                }
                p->faxmode = 0;
+               p->faxdetected = 0;
                p->t38_init = 0;
        }