Skip to content
Snippets Groups Projects
chan_ooh323.c 148 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		ast_log(LOG_ERROR, "Couldn't create rtp structure\n");
    		return -1;
    	}
    
    
    	ast_mutex_unlock(&p->lock);
    
    	if (gH323Debug)
    
    		ast_verb(0, "+++   ooh323_onReceivedSetup - Determined context %s, "
    
    int onOutgoingCall(ooCallData *call)
    {
    	struct ooh323_pvt *p = NULL;
    	int i = 0;
    
    	if (gH323Debug)
    
    		ast_verb(0, "---   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, "Failed to find a matching call.\n");
    			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(!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_verb(0, "Setting dialed digits %s\n", p->caller_dialedDigits);
    
    			}
    			ooCallAddAliasDialedDigits(call, p->caller_dialedDigits);
    		} else if (!ast_strlen_zero(p->callerid_num)) {
    
    Josh Soref's avatar
    Josh Soref committed
    			if (ooIsDialedDigit(p->callerid_num)) {
    
    				if (gH323Debug) {
    
    					ast_verb(0, "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 (!p->rtp && !configure_local_rtp(p, call)) {
    
    			ast_mutex_unlock(&p->lock);
    			return OO_FAILED;
    		}
    
    
    		ast_mutex_unlock(&p->lock);
    	}
    
    	if (gH323Debug)
    
    		ast_verb(0, "+++   onOutgoingCall %s\n", call->callToken);
    
    int onNewCallCreated(ooCallData *call)
    {
    	struct ooh323_pvt *p = NULL;
    	int i = 0;
    
    	if (gH323Debug)
    
    		ast_verb(0, "---   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);
    
    		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; }
    
             		if(*(p->callerid_num+i) == '\0')
    
    				ooCallSetCallingPartyNumber(call, p->callerid_num);
    
                			if(ast_strlen_zero(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_verb(0, "Setting dialed digits %s\n", p->caller_dialedDigits);
    
    			}
    			ooCallAddAliasDialedDigits(call, p->caller_dialedDigits);
    
    		} else if (!ast_strlen_zero(p->callerid_num)) {
    
    Josh Soref's avatar
    Josh Soref committed
    			if (ooIsDialedDigit(p->callerid_num)) {
    
    					ast_verb(0, "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);
    			}
    		}
    
    Josh Soref's avatar
    Josh Soref committed
    			if (ooIsDialedDigit(p->exten)) {
    
    				ooCallSetCalledPartyNumber(call, p->exten);
    				ooCallAddRemoteAliasDialedDigits(call, p->exten);
    			} else {
    			  ooCallAddRemoteAliasH323ID(call, p->exten);
    			}
    		}
    
    		if (gH323Debug) {
    
    			struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
    
    			ast_verb(0, " Outgoing call %s(%s) - Codec prefs - %s\n",
    
    				p->username?p->username:"NULL", call->callToken,
    				ast_format_cap_get_names(p->cap, &codec_buf));
    
          		ooh323c_set_capability_for_call(call, p->cap,
    
                                         p->dtmfmode, p->dtmfcodec, p->t38support, p->g729onlyA);
    
    		configure_local_rtp(p, call);
    		ast_cond_signal(&p->rtpcond);
    
    
       	ast_mutex_unlock(&call->Lock);
    
    		ast_verb(0, "+++   onNewCallCreated %s\n", call->callToken);
    
    	return OO_OK;
    }
    
    int onCallEstablished(ooCallData *call)
    {
    	struct ooh323_pvt *p = NULL;
    
    	if (gH323Debug)
    
    		ast_verb(0, "---   onCallEstablished %s\n", call->callToken);
    
    	if (!(p = find_call(call))) {
    		ast_log(LOG_ERROR, "Failed to find a matching call.\n");
    		return -1;
    	}
    
       	if(ast_test_flag(p, H323_OUTGOING)) {
    
    		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_publish_snapshot(c);
    
    			ast_channel_unlock(p->owner);
    
    		ast_verb(0, "+++   onCallEstablished %s\n", call->callToken);
    
    
    	return OO_OK;
    }
    
    int onCallCleared(ooCallData *call)
    {
    	struct ooh323_pvt *p = NULL;
    	int ownerLock = 0;
    
    	if (gH323Debug)
    
    		ast_verb(0, "---   onCallCleared %s \n", call->callToken);
    
    
       if ((p = find_call(call))) {
    
    	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");
    
    			DEADLOCK_AVOIDANCE(&p->lock);
    
             		ownerLock = 1; break;
    
    		if (!ast_test_flag(p, H323_ALREADYGONE)) {
    
    			ast_channel_hangupcause_set(p->owner, call->q931cause);
    
    			ast_channel_softhangup_internal_flag_add(p->owner, AST_SOFTHANGUP_DEV);
    
    			ast_queue_hangup_with_cause(p->owner,call->q931cause);
    
       	if(p->owner) {
    
        		ast_channel_tech_pvt_set(p->owner, NULL);
    
        		p->owner = NULL;
    
    		ast_module_unref(myself);
    
    	if (!p->rtp) {
    		ast_cond_signal(&p->rtpcond);
    	}
    
    
    	ast_set_flag(p, H323_NEEDDESTROY);
    
       	ooh323c_stop_call_thread(call);
    
       	ast_mutex_lock(&usecnt_lock);
       	usecnt--;
       	ast_mutex_unlock(&usecnt_lock);
    
    /* static void ooh323_delete_user(struct ooh323_user *user)
    
    {
    	struct ooh323_user *prev = NULL, *cur = NULL;
    
    	if (gH323Debug)
    
    		cur = userl.users;
    		ast_mutex_lock(&userl.lock);
    		while (cur) {
    			if (cur == user) break;
    			prev = cur;
    			cur = cur->next;
    		}
    
    		if (cur) {
    			if (prev)
    				prev->next = cur->next;
    			else
    				userl.users = cur->next;
    		}
    		ast_mutex_unlock(&userl.lock);
    
    
    
    void ooh323_delete_peer(struct ooh323_peer *peer)
    {
    	struct ooh323_peer *prev = NULL, *cur = NULL;
    
    	if (gH323Debug)
    
          cur = peerl.peers;
    
          while(cur) {
             if(cur==peer) break;
             prev = cur;
             cur = cur->next;
    
    				peerl.peers = cur->next;
    			}
    		ast_mutex_unlock(&peerl.lock);
    
    
    		ast_free(peer->h323id);
    		ast_free(peer->email);
    		ast_free(peer->url);
    		ast_free(peer->e164);
    
    		ao2_cleanup(peer->cap);
    		ast_free(peer);
    
    }
    
    
    
    static struct ooh323_user *build_user(const char *name, struct ast_variable *v)
    {
    	struct ooh323_user *user = NULL;
    
    	if (gH323Debug)
    
       	user = ast_calloc(1,sizeof(struct ooh323_user));
    
    		memset(user, 0, sizeof(struct ooh323_user));
    
    		if (!(user->cap = ast_format_cap_alloc(0))) {
    
    		ast_mutex_init(&user->lock);
    		ast_copy_string(user->name, name, sizeof(user->name));
    
    		ast_format_cap_append_from_cap(user->cap, gCap, AST_MEDIA_TYPE_UNKNOWN);
    
    		user->rtptimeout = gRTPTimeout;
    
    		user->dtmfcodec = gDTMFCodec;
    
    		user->faxdetect = gFAXdetect;
    
    		user->t38support = gT38Support;
    
    		user->faststart = gFastStart;
    		user->h245tunneling = gTunneling;
    
    		user->directrtp = gDirectRTP;
    		user->earlydirect = gEarlyDirect;
    
    		user->g729onlyA = g729onlyA;
    
    		/* set default context */
    		ast_copy_string(user->context, gContext, sizeof(user->context));
    		ast_copy_string(user->accountcode, gAccountcode, sizeof(user->accountcode));
    		user->amaflags = gAMAFLAGS;
    
    		while (v) {
    			if (!strcasecmp(v->name, "context")) {
    				ast_copy_string(user->context, v->value, sizeof(user->context));
    			} else if (!strcasecmp(v->name, "incominglimit")) {
    				user->incominglimit = atoi(v->value);
    				if (user->incominglimit < 0)
    					user->incominglimit = 0;
    			} else if (!strcasecmp(v->name, "accountcode")) {
    
                			ast_copy_string(user->accountcode, v->value, sizeof(user->accountcode));
    
    			} 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, "directrtp") || !strcasecmp(v->name, "directmedia")) {
    				user->directrtp = ast_true(v->value);
    				user->earlydirect = ast_true(v->value);
    			} else if (!strcasecmp(v->name, "earlydirect") || !strcasecmp(v->name, "directrtpsetup")) {
    				user->earlydirect = ast_true(v->value);
    
    			} else if (!strcasecmp(v->name, "g729onlyA")) {
    				user->g729onlyA = ast_true(v->value);
    
    			} else if (!strcasecmp(v->name, "nat")) {
    				user->nat = 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_format_cap_update_by_allow_disallow(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_format_cap_update_by_allow_disallow(user->cap,  tcodecs, 1);
    
    			} else if (!strcasecmp(v->name, "amaflags")) {
    
    				user->amaflags = ast_channel_string2amaflag(v->value);
    
             		} 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);
    
                				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;
    
    			} else if (!strcasecmp(v->name, "aniasdni")) {
    				user->aniasdni = ast_true(v->value);
    
    
    	return user;
    }
    
    static struct ooh323_peer *build_peer(const char *name, struct ast_variable *v, int friend_type)
    {
    	struct ooh323_peer *peer = NULL;
    
    	if (gH323Debug)
    
    
    	peer = ast_calloc(1, sizeof(*peer));
    	if (peer) {
    
    		memset(peer, 0, sizeof(struct ooh323_peer));
    
    		if (!(peer->cap = ast_format_cap_alloc(0))) {
    
    		ast_mutex_init(&peer->lock);
    		ast_copy_string(peer->name, name, sizeof(peer->name));
    
    		ast_format_cap_append_from_cap(peer->cap, gCap, AST_MEDIA_TYPE_UNKNOWN);
    
    		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->directrtp = gDirectRTP;
    		peer->earlydirect = gEarlyDirect;
    
    		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))) {
    
    					ast_log(LOG_ERROR, "Could not allocate memory for h323id of "
    											 "peer %s\n", name);
    					ooh323_delete_peer(peer);
    					return NULL;
    				}
    			} else if (!strcasecmp(v->name, "e164")) {
    
    				int valid = 1;
    				const char *tmp;
    				for(tmp = v->value; *tmp; tmp++) {
    					if (!isdigit(*tmp)) {
    						valid = 0;
    						break;
    					}
    				}
    				if (valid) {
    					if (!(peer->e164 = ast_strdup(v->value))) {
    						ast_log(LOG_ERROR, "Could not allocate memory for e164 of "
    
    						ooh323_delete_peer(peer);
    						return NULL;
    					}
    				} else {
    					ast_log(LOG_ERROR, "Invalid e164: %s for peer %s\n", v->value, name);
    
    				}
    			} else  if (!strcasecmp(v->name, "email")) {
    				if (!(peer->email = ast_strdup(v->value))) {
    					ast_log(LOG_ERROR, "Could not allocate memory for email of "
    											 "peer %s\n", name);
    					ooh323_delete_peer(peer);
    					return NULL;
    				}
    			} else if (!strcasecmp(v->name, "url")) {
    				if (!(peer->url = ast_strdup(v->value))) {
    					ast_log(LOG_ERROR, "Could not allocate memory for h323id of "
    											 "peer %s\n", name);
    					ooh323_delete_peer(peer);
    					return NULL;
    				}
    			} else if (!strcasecmp(v->name, "port")) {
    				peer->port = atoi(v->value);
    
             		} 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));
    
                				ast_copy_string(peer->ip, v->value, sizeof(peer->ip));
    				}
    
    			} else if (!strcasecmp(v->name, "outgoinglimit")) {
    
    				int val = atoi(v->value);
    				if (val < 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, "directrtp") || !strcasecmp(v->name, "directmedia")) {
    				peer->directrtp = ast_true(v->value);
    				peer->earlydirect = ast_true(v->value);
    			} else if (!strcasecmp(v->name, "earlydirect") || !strcasecmp(v->name, "directrtpsetup")) {
    				peer->earlydirect = ast_true(v->value);
    
    			} else if (!strcasecmp(v->name, "g729onlyA")) {
    				peer->g729onlyA = ast_true(v->value);
    
    			} else if (!strcasecmp(v->name, "nat")) {
    				peer->nat = ast_true(v->value);
    
    			} else if (!strcasecmp(v->name, "rtptimeout")) {
    
                			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_format_cap_update_by_allow_disallow(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_format_cap_update_by_allow_disallow(peer->cap, tcodecs, 1);
    
    			} else if (!strcasecmp(v->name,  "amaflags")) {
    
    				peer->amaflags = ast_channel_string2amaflag(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;
    
    	struct ooAliases * pNewAlias = NULL;
    	struct ooh323_peer *peer = NULL;
    
    
    	/* Gatekeeper */
    	if (gH323ep.gkClient) {
    		ooGkClientDestroy();
    	}
    
    
       	reload_config(1);
    
    	if (gRasGkMode == RasUseSpecificGatekeeper ||
    
    		gRasGkMode == RasDiscoverGatekeeper) {
    
    		ooGkClientInit(gRasGkMode, (gRasGkMode == RasUseSpecificGatekeeper) ?
    
    								gGatekeeper : 0, gRASIP, 0);
    
    	/* Set aliases if any */
    	if (gH323Debug) {
    		ast_verb(0, "updating local aliases\n");
    	}
    
    	for (pNewAlias = gAliasList; pNewAlias; pNewAlias = pNewAlias->next) {
    		switch (pNewAlias->type) {
    		case T_H225AliasAddress_h323_ID:
    			ooH323EpAddAliasH323ID(pNewAlias->value);
    			break;
    
    		case T_H225AliasAddress_dialedDigits:
    
    			ooH323EpAddAliasDialedDigits(pNewAlias->value);
    			break;
    
    		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);
    		}
    		peer = peer->next;
    	}
    	ast_mutex_unlock(&peerl.lock);
    
    
    	}
    
    	return 0;
    }
    
    /*--- h323_reload: Force reload of module from cli ---*/
    
    
    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;
    
    
    
    	ast_mutex_lock(&h323_reload_lock);
    	if (h323_reloading) {
    
    		ast_verb(0, "Previous OOH323 reload not yet done\n");
    
    		h323_reloading = 1;
    	}
    	ast_mutex_unlock(&h323_reload_lock);
    	restart_monitor();
    
    	if (gH323Debug)
    
    	struct ooAliases  *pNewAlias = NULL, *cur, *prev;
    
    	struct ast_config *cfg;
    	struct ast_variable *v;
    	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
    	struct ooh323_user *user = NULL;
    	struct ooh323_peer *peer = NULL;
    	char *cat;
    	const char *utype;
    
    	if (gH323Debug)
    
    	cfg = ast_config_load((char*)config, config_flags);
    
    
    	/* We *must* have a config file otherwise stop immediately */
    	if (!cfg) {
    		ast_log(LOG_NOTICE, "Unable to load config %s, OOH323 disabled\n", config);
    		return 1;
    	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
    		return RESULT_SUCCESS;
    
    	if (reload) {
    		delete_users();
    		delete_peers();
    
    		if (gH323Debug) {
    
    			ast_verb(0, "  reload_config - Freeing up alias list\n");
    
    		}
    		cur = gAliasList;
    		while (cur) {
    			prev = cur;
    	  		cur = cur->next;
    
    	  		ast_free(prev->value);
    	  		ast_free(prev);
    
    		}
    		gAliasList = NULL;
    
    	}
    
    	/* Inintialize everything to default */
    
    	snprintf(gLogFile, sizeof(gLogFile), "%s/%s", ast_config_AST_LOG_DIR, DEFAULT_LOGFILE);
    
    	gPort = 1720;
    	gIP[0] = '\0';
    	strcpy(gCallerID, DEFAULT_H323ID);
    
    	ast_format_cap_remove_by_type(gCap, AST_MEDIA_TYPE_UNKNOWN);
    	ast_format_cap_append(gCap, ast_format_ulaw, 0);
    
    	gDTMFMode = H323_DTMF_RFC2833;
    
    	gDTMFCodec = 101;
    
    	gFAXdetect = FAXDETECT_CNG;
    
    	gT38Support = T38_FAXGW;
    	gTRCLVL = OOTRCLVLERR;
    
    	gRasGkMode = RasNoGatekeeper;
    	gGatekeeper[0] = '\0';
    
    	gRTDRInterval = 0;
    	gRTDRCount = 0;
    
    	strcpy(gAccountcode, DEFAULT_H323ACCNT);
    	gFastStart = 1;
    	gTunneling = 1;
    	gTOS = 0;
    	strcpy(gContext, DEFAULT_CONTEXT);
    	gAliasList = NULL;
    	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);
    
    				ast_config_destroy(cfg);
    
    				return 1;
    			}
    			if (ast_sockaddr_is_ipv6(&bindaddr)) {
    				v6mode = 1;
    			}
    
    		} else if (!strcasecmp(v->name, "h225portrange")) {
    			char* endlimit = 0;
    
             		char temp[512];
    
    			ast_copy_string(temp, v->value, sizeof(temp));
    			endlimit = strchr(temp, ',');
    			if (endlimit) {
    				*endlimit = '\0';
    				endlimit++;
    				ooconfig.mTCPPortStart = atoi(temp);
    				ooconfig.mTCPPortEnd = atoi(endlimit);
    
    			} 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")) {
    
    			gFastStart = ast_true(v->value);
    			if (gFastStart)
    				ooH323EpEnableFastStart();
    			else
    				ooH323EpDisableFastStart();
    		} else if (!strcasecmp(v->name, "mediawaitforconnect")) {
    			gMediaWaitForConnect = ast_true(v->value);
    			if (gMediaWaitForConnect)
    				ooH323EpEnableMediaWaitForConnect();
    
    				ooH323EpDisableMediaWaitForConnect();
    		} else if (!strcasecmp(v->name, "h245tunneling")) {
    			gTunneling = ast_true(v->value);
    			if (gTunneling)
    				ooH323EpEnableH245Tunneling();
    			else
    				ooH323EpDisableH245Tunneling();
    
    		} else if (!strcasecmp(v->name, "directrtp") || !strcasecmp(v->name, "directmedia")) {
    			gDirectRTP = ast_true(v->value);
    			gEarlyDirect = ast_true(v->value);
    		} else if (!strcasecmp(v->name, "earlydirect") || !strcasecmp(v->name, "directrtpsetup")) {
    			gEarlyDirect = ast_true(v->value);
    
    		} 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);
    
    				ooH323EpTryBeMaster(0);
    
    		} else if (!strcasecmp(v->name, "h323id")) {
    
             		pNewAlias = ast_calloc(1, sizeof(struct ooAliases));
    
    			if (!pNewAlias) {
    				ast_log(LOG_ERROR, "Failed to allocate memory for h323id alias\n");
    
    				ast_config_destroy(cfg);
    
    	 		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 = ast_strdup(v->value);
    
    			pNewAlias->next = gAliasList;
    			gAliasList = pNewAlias;
    			pNewAlias = NULL;
    		} else if (!strcasecmp(v->name, "e164")) {
    
    			int valid = 1;
    			const char *tmp;
    			for(tmp = v->value; *tmp; tmp++) {
    				if (!isdigit(*tmp)) {
    					valid = 0;
    					break;
    				}
    			}
    			if (valid) {
             			pNewAlias = ast_calloc(1, sizeof(struct ooAliases));
    				if (!pNewAlias) {
    					ast_log(LOG_ERROR, "Failed to allocate memory for e164 alias\n");
    					ast_config_destroy(cfg);
    					return 1;
    				}
    				pNewAlias->type =  T_H225AliasAddress_dialedDigits;
    
    				pNewAlias->value = ast_strdup(v->value);
    
    				pNewAlias->next = gAliasList;
    				gAliasList = pNewAlias;
    				pNewAlias = NULL;
    			} else {
    				ast_log(LOG_ERROR, "Invalid e164: %s\n", v->value);
    
    			}
    		} else if (!strcasecmp(v->name, "email")) {
    
             		pNewAlias = ast_calloc(1, sizeof(struct ooAliases));
    
    			if (!pNewAlias) {
    				ast_log(LOG_ERROR, "Failed to allocate memory for email alias\n");
    
    				ast_config_destroy(cfg);
    
    				return 1;
    			}
    			pNewAlias->type =  T_H225AliasAddress_email_ID;
    
    			pNewAlias->value = ast_strdup(v->value);