Skip to content
Snippets Groups Projects
chan_ooh323.c 148 KiB
Newer Older
  • Learn to ignore specific revisions
  • 			pNewAlias->next = gAliasList;
    			gAliasList = pNewAlias;
    			pNewAlias = NULL;
    
          } else if (!strcasecmp(v->name, "t35country")) {
             t35countrycode = atoi(v->value);
          } else if (!strcasecmp(v->name, "t35extensions")) {
             t35extensions = atoi(v->value);
          } else if (!strcasecmp(v->name, "manufacturer")) {
             manufacturer = atoi(v->value);
          } else if (!strcasecmp(v->name, "vendorid")) {
             ast_copy_string(vendor, v->value, sizeof(vendor));
          } else if (!strcasecmp(v->name, "versionid")) {
             ast_copy_string(version, v->value, sizeof(version));
    
    		} else if (!strcasecmp(v->name, "callerid")) {
    			ast_copy_string(gCallerID, v->value, sizeof(gCallerID));
    		} else if (!strcasecmp(v->name, "incominglimit")) {
    			gIncomingLimit = atoi(v->value);
    		} else if (!strcasecmp(v->name, "outgoinglimit")) {
    			gOutgoingLimit = atoi(v->value);
    		} else if (!strcasecmp(v->name, "gatekeeper")) {
    			if (!strcasecmp(v->value, "DISABLE")) {
    				gRasGkMode = RasNoGatekeeper;
    			} else if (!strcasecmp(v->value, "DISCOVER")) {
    				gRasGkMode = RasDiscoverGatekeeper;
    			} else {
    				gRasGkMode = RasUseSpecificGatekeeper;
    
                			ast_copy_string(gGatekeeper, v->value, sizeof(gGatekeeper));
    
    		} else if (!strcasecmp(v->name, "localras")) {
    		        ast_copy_string(gRASIP, v->value, sizeof(gRASIP));
    			ast_verb(3, "  == Setting RAS IP to %s\n", gRASIP);
    
    		} else if (!strcasecmp(v->name, "logfile")) {
    
    			if (v->value[0] == '/') {
    				ast_copy_string(gLogFile, v->value, sizeof(gLogFile));
    			} else {
    				snprintf(gLogFile, sizeof(gLogFile), "%s/%s", ast_config_AST_LOG_DIR, v->value);
    			}
    
    		} else if (!strcasecmp(v->name, "context")) {
    
             		ast_copy_string(gContext, v->value, sizeof(gContext));
    
             		ast_verb(3, "  == Setting default context to %s\n", gContext);
    		} else if (!strcasecmp(v->name, "nat")) {
    			gNat = ast_true(v->value);
    
    		} else if (!strcasecmp(v->name, "rtptimeout")) {
    			gRTPTimeout = atoi(v->value);
    
    				gRTPTimeout = 60;
    		} else if (!strcasecmp(v->name, "tos")) {
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    			if (sscanf(v->value, "%30i", &format) == 1)
    
    				gTOS = format & 0xff;
    			else if (!strcasecmp(v->value, "lowdelay"))
    				gTOS = IPTOS_LOWDELAY;
    			else if (!strcasecmp(v->value, "throughput"))
    				gTOS = IPTOS_THROUGHPUT;
    			else if (!strcasecmp(v->value, "reliability"))
    				gTOS = IPTOS_RELIABILITY;
    			else if (!strcasecmp(v->value, "mincost"))
    				gTOS = IPTOS_MINCOST;
    			else if (!strcasecmp(v->value, "none"))
    				gTOS = 0;
    			else
    				ast_log(LOG_WARNING, "Invalid tos value at line %d, should be "
    											"'lowdelay', 'throughput', 'reliability', "
    											"'mincost', or 'none'\n", v->lineno);
    		} else if (!strcasecmp(v->name, "amaflags")) {
    
    			gAMAFLAGS = ast_channel_string2amaflag(v->value);
    
    		} else if (!strcasecmp(v->name, "accountcode")) {
    
             ast_copy_string(gAccountcode, v->value, sizeof(gAccountcode));
    
    		} else if (!strcasecmp(v->name, "disallow")) {
    
    			ast_format_cap_update_by_allow_disallow(gCap, v->value, 0);
    
    		} else if (!strcasecmp(v->name, "allow")) {
    			const char* tcodecs = v->value;
    			if (!strcasecmp(v->value, "all")) {
    				tcodecs = "ulaw,alaw,g729,g723,gsm";
    			}
    
    			ast_format_cap_update_by_allow_disallow(gCap, tcodecs, 1);
    
    		} else if (!strcasecmp(v->name, "dtmfmode")) {
    			if (!strcasecmp(v->value, "inband"))
    				gDTMFMode = H323_DTMF_INBAND;
    			else if (!strcasecmp(v->value, "rfc2833"))
    				gDTMFMode = H323_DTMF_RFC2833;
    
    			else if (!strcasecmp(v->value, "cisco"))
    				gDTMFMode = H323_DTMF_CISCO;
    
    			else if (!strcasecmp(v->value, "q931keypad"))
    				gDTMFMode = H323_DTMF_Q931;
    			else if (!strcasecmp(v->value, "h245alphanumeric"))
    				gDTMFMode = H323_DTMF_H245ALPHANUMERIC;
    			else if (!strcasecmp(v->value, "h245signal"))
    				gDTMFMode = H323_DTMF_H245SIGNAL;
    			else {
    
                ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n",
    
    		} else if (!strcasecmp(v->name, "relaxdtmf")) {
    			gDTMFMode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0;
    		} else if (!strcasecmp(v->name, "dtmfcodec") && atoi(v->value)) {
    			gDTMFCodec = atoi(v->value);
    
    		} else if (!strcasecmp(v->name, "faxdetect")) {
    			if (ast_true(v->value)) {
    				gFAXdetect = FAXDETECT_CNG | FAXDETECT_T38;
    			} else if (ast_false(v->value)) {
    				gFAXdetect = 0;
    			} else {
    				char *buf = ast_strdupa(v->value);
    				char *word, *next = buf;
    				gFAXdetect = 0;
    				while ((word = strsep(&next, ","))) {
    					if (!strcasecmp(word, "cng")) {
    						gFAXdetect |= FAXDETECT_CNG;
    					} else if (!strcasecmp(word, "t38")) {
    						gFAXdetect |= FAXDETECT_T38;
    					} else {
    						ast_log(LOG_WARNING, "Unknown faxdetect mode '%s' on line %d.\n", word, v->lineno);
    					}
    				}
    
    			}
    		} else if (!strcasecmp(v->name, "t38support")) {
    
    			if (!strcasecmp(v->value, "disabled"))
    				gT38Support = T38_DISABLED;
    			if (!strcasecmp(v->value, "no"))
    				gT38Support = T38_DISABLED;
    			else if (!strcasecmp(v->value, "faxgw"))
    				gT38Support = T38_FAXGW;
    			else if (!strcasecmp(v->value, "yes"))
    				gT38Support = T38_ENABLED;
    		} else if (!strcasecmp(v->name, "tracelevel")) {
    			gTRCLVL = atoi(v->value);
    			ooH323EpSetTraceLevel(gTRCLVL);
    
    		} else if (!strcasecmp(v->name, "aniasdni")) {
    			gANIasDNI = ast_true(v->value);
    
    	for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
    		if (strcasecmp(cat, "general")) {
    			int friend_type = 0;
    			utype = ast_variable_retrieve(cfg, cat, "type");
    			if (utype) {
    				friend_type = strcasecmp(utype, "friend");
    				if (!strcmp(utype, "user") || 0 == friend_type) {
    					user = build_user(cat, ast_variable_browse(cfg, cat));
    					if (user) {
    						ast_mutex_lock(&userl.lock);
    						user->next = userl.users;
    						userl.users = user;
    						ast_mutex_unlock(&userl.lock);
    					} else {
    						ast_log(LOG_WARNING, "Failed to build user %s\n", cat);
    					}
    				}
    				if (!strcasecmp(utype, "peer") || 0 == friend_type) {
    					peer = build_peer(cat, ast_variable_browse(cfg, cat), friend_type);
    					if (peer) {
    						ast_mutex_lock(&peerl.lock);
    						peer->next = peerl.peers;
    						peerl.peers = peer;
    						ast_mutex_unlock(&peerl.lock);
    					} else {
    						ast_log(LOG_WARNING, "Failed to build peer %s\n", cat);
    					}
    				}
    			}
    		}
    	}
    	ast_config_destroy(cfg);
    
    
    
    	/* Determine ip address if neccessary */
    
    	if (ast_strlen_zero(gIP)) {
    		ooGetLocalIPAddress(gIP);
    
    		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;
    		}
    	}
    
    	if (gH323Debug)
    
    static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    {
    
    	char ip_port[64];
    
    	struct ooh323_peer *prev = NULL, *peer = NULL;
    
    	switch (cmd) {
    	case CLI_INIT:
    		e->command = "ooh323 show peer";
    		e->usage =
    			"Usage: ooh323 show peer <name>\n"
    			"		 List details of specific OOH323 peer.\n";
    		return NULL;
    	case CLI_GENERATE:
    		return NULL;
    	}
    
    	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])) {
    
    			prev = peer;
    			peer = peer->next;
    			ast_mutex_unlock(&prev->lock);
    		}
    	}
    
    	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",
    
    					peer->h245tunneling?"yes":"no");
    
    		ast_cli(a->fd, "%-15s%s\n", "DirectRTP", peer->directrtp ? "yes" : "no");
    		ast_cli(a->fd, "%-15s%s\n", "EarlyDirectRTP", peer->earlydirect ? "yes" : "no");
    
    		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);
    
    		} 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");
    		}
    		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_channel_amaflags2string(peer->amaflags));
    
    		ast_cli(a->fd, "%-15.15s%s\n", "IP:Port: ", ip_port);
    
    		ast_cli(a->fd, "%-15.15s%u\n", "OutgoingLimit: ", peer->outgoinglimit);
    
    		ast_cli(a->fd, "%-15.15s%d\n", "rtptimeout: ", peer->rtptimeout);
    
    		ast_cli(a->fd, "%-15.15s%s\n", "nat: ", peer->nat?"yes":"no");
    
    		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, "Peer %s not found\n", a->argv[3]);
    		ast_cli(a->fd, "\n");
    
    	}
    	ast_mutex_unlock(&peerl.lock);
    
    	return CLI_SUCCESS;
    }
    
    static char *handle_cli_ooh323_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    {
    	struct ooh323_peer *prev = NULL, *peer = NULL;
    
    	struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
    
       char ip_port[64];
    
    #define FORMAT  "%-15.15s  %-15.15s  %-23.23s  %-s\n"
    
    	switch (cmd) {
    	case CLI_INIT:
    		e->command = "ooh323 show peers";
    		e->usage =
    			"Usage: ooh323 show peers\n"
    			"		 Lists all known OOH323 peers.\n";
    		return NULL;
    	case CLI_GENERATE:
    		return NULL;
    	}
    
    	if (a->argc != 3)
    		return CLI_SHOWUSAGE;
    
    
       ast_cli(a->fd, FORMAT, "Name", "Accountcode", "ip:port", "Formats");
    
    
    	ast_mutex_lock(&peerl.lock);
    	peer = peerl.peers;
    	while (peer) {
    		ast_mutex_lock(&peer->lock);
    
    		snprintf(ip_port, sizeof(ip_port), "%s:%d", peer->ip, peer->port);
    
    		ast_cli(a->fd, FORMAT, peer->name,
    
    					ast_format_cap_get_names(peer->cap, &codec_buf));
    
    		prev = peer;
    		peer = peer->next;
    		ast_mutex_unlock(&prev->lock);
    
    	}
    	ast_mutex_unlock(&peerl.lock);
    #undef FORMAT
    	return CLI_SUCCESS;
    }
    
    static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    {
    	struct ooh323_user *prev = NULL, *user = NULL;
    
    	switch (cmd) {
    	case CLI_INIT:
    		e->command = "ooh323 show user";
    		e->usage =
    			"Usage: ooh323 show user <name>\n"
    			"		 List details of specific OOH323 user.\n";
    		return NULL;
    	case CLI_GENERATE:
    		return NULL;
    	}
    
    	if (a->argc != 4)
    		return CLI_SHOWUSAGE;
    
    
    	ast_mutex_lock(&userl.lock);
    	user = userl.users;
    	while (user) {
    		ast_mutex_lock(&user->lock);
    
    		if (!strcmp(user->name, a->argv[3])) {
    
    			prev = user;
    			user = user->next;
    			ast_mutex_unlock(&prev->lock);
    		}
    	}
    
    	if (user) {
    
    		ast_cli(a->fd, "%-15.15s%s\n", "Name: ", user->name);
    		ast_cli(a->fd, "%s:%s,%s\n", "FastStart/H.245 Tunneling", user->faststart?"yes":"no",
    
    					user->h245tunneling?"yes":"no");
    
    		ast_cli(a->fd, "%-15s%s\n", "DirectRTP", user->directrtp ? "yes" : "no");
    		ast_cli(a->fd, "%-15s%s\n", "EarlyDirectRTP", user->earlydirect ? "yes" : "no");
    
    		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);
    
    		} 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");
    		}
    		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_channel_amaflags2string(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%u\n", "InUse: ", user->inUse);
    
    		ast_cli(a->fd, "%-15.15s%d\n", "rtptimeout: ", user->rtptimeout);
    
    		ast_cli(a->fd, "%-15.15s%s\n", "nat: ", user->nat?"yes":"no");
    
    		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);
    		}
    
    		ast_cli(a->fd, "User %s not found\n", a->argv[3]);
    		ast_cli(a->fd, "\n");
    
    	}
    	ast_mutex_unlock(&userl.lock);
    
    	return CLI_SUCCESS;
    }
    
    static char *handle_cli_ooh323_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    {
    	struct ooh323_user *prev = NULL, *user = NULL;
    
    	struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
    
    #define FORMAT1  "%-15.15s  %-15.15s  %-15.15s  %-s\n"
    
    	switch (cmd) {
    	case CLI_INIT:
    		e->command = "ooh323 show users";
    		e->usage =
    			"Usage: ooh323 show users \n"
    			"		 Lists all known OOH323 users.\n";
    		return NULL;
    	case CLI_GENERATE:
    		return NULL;
    	}
    
    	if (a->argc != 3)
    		return CLI_SHOWUSAGE;
    
    
    
       ast_cli(a->fd, FORMAT1, "Username", "Accountcode", "Context", "Formats");
    
    
    	ast_mutex_lock(&userl.lock);
    	user = userl.users;
    
         		ast_cli(a->fd, FORMAT1, user->name,
    
    					user->accountcode, user->context,
    
    					ast_format_cap_get_names(user->cap, &codec_buf));
    
    		prev = user;
    		user = user->next;
    		ast_mutex_unlock(&prev->lock);
    
    	}
    	ast_mutex_unlock(&userl.lock);
    #undef FORMAT1
    
       return RESULT_SUCCESS;
    
    
    }
    
    static char *handle_cli_ooh323_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    {
    	switch (cmd) {
    	case CLI_INIT:
    		e->command = "ooh323 set debug [off]";
    		e->usage =
    			"Usage: ooh323 set debug [off]\n"
    			"		 Enables/Disables debugging of OOH323 channel driver\n";
    		return NULL;
    	case CLI_GENERATE:
    		return NULL;
    	}
    
    	if (a->argc < 3 || a->argc > 4)
    		return CLI_SHOWUSAGE;
    	if (a->argc == 4 && strcasecmp(a->argv[3], "off"))
    		return CLI_SHOWUSAGE;
    
    	gH323Debug = (a->argc == 4) ? FALSE : TRUE;
    	ast_cli(a->fd, "OOH323 Debugging %s\n", gH323Debug ? "Enabled" : "Disabled");
    
    	return CLI_SUCCESS;
    }
    
    #if 0
    static int ooh323_show_channels(int fd, int argc, char *argv[])
    {
    	return RESULT_SUCCESS;
    }
    #endif
    
    
    static char *handle_cli_ooh323_show_gk(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    {
    	char value[FORMAT_STRING_SIZE];
    
    	switch (cmd) {
    	case CLI_INIT:
    		e->command = "ooh323 show gk";
    		e->usage =
    			"Usage: ooh323 show gk\n"
    			"		 Shows Gatekeeper connection state\n";
    		return NULL;
    	case CLI_GENERATE:
    		return NULL;
    	}
    
    	if (a->argc != 3)
    		return CLI_SHOWUSAGE;
    
    	ast_cli(a->fd, "\nGateKeeper connection state:\n");
    	if (!gH323ep.gkClient) {
    		ast_cli(a->fd, "No Gatekeeper is configured\n");
    		return CLI_SUCCESS;
    	}
    
    	if (gRasGkMode == RasNoGatekeeper) {
    		snprintf(value, sizeof(value), "%s", "No Gatekeeper");
    	} else if (gRasGkMode == RasDiscoverGatekeeper) {
    		snprintf(value, sizeof(value), "%s", "Discover");
    	} else {
    		snprintf(value, sizeof(value), "%s", gGatekeeper);
    	}
    	ast_cli(a->fd,  "%-20s%s\n", "Gatekeeper:", value);
    	switch(gH323ep.gkClient->state) {
    	case GkClientIdle:
    		ast_cli(a->fd, "%-20s%s\n", "GK state:", "Idle");
    		break;
    	case GkClientDiscovered:
    		ast_cli(a->fd, "%-20s%s\n", "GK state:", "Discovered");
    		break;
    	case GkClientRegistered:
    		ast_cli(a->fd, "%-20s%s\n", "GK state:", "Registered");
    		break;
    	case GkClientUnregistered:
    		ast_cli(a->fd, "%-20s%s\n", "GK state:", "Unregistered");
    		break;
    	case GkClientGkErr:
    		ast_cli(a->fd, "%-20s%s\n", "GK state:", "Error");
    		break;
    	case GkClientFailed:
    		ast_cli(a->fd, "%-20s%s\n", "GK state:", "Failed");
    		break;
    
    	case GkClientStopped:
    		ast_cli(a->fd, "%-20s%s\n", "GK state:", "Shutdown");
    		break;
    
    static char *handle_cli_ooh323_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    {
    
    	char value[FORMAT_STRING_SIZE];
    
    	struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
    
    	ooAliases *pAlias = NULL, *pAliasNext = NULL;;
    
    	switch (cmd) {
    	case CLI_INIT:
    		e->command = "ooh323 show config";
    		e->usage =
    			"Usage: ooh323 show config\n"
    			"		 Shows global configuration of H.323 channel driver\n";
    		return NULL;
    	case CLI_GENERATE:
    		return NULL;
    	}
    
    	if (a->argc != 3)
    		return CLI_SHOWUSAGE;
    
    
    	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", "DirectRTP", gDirectRTP ? "yes" : "no");
    	ast_cli(a->fd, "%-20s%s\n", "EarlyDirectRTP", gEarlyDirect ? "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");
    
    	if (gRasGkMode == RasNoGatekeeper) {
    
    		snprintf(value, sizeof(value), "%s", "No Gatekeeper");
    
    	} else if (gRasGkMode == RasDiscoverGatekeeper) {
    
    		snprintf(value, sizeof(value), "%s", "Discover");
    
    		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_format_cap_get_names(gCap, &codec_buf));
    
    	ast_cli(a->fd, "%-20s", "DTMF Mode: ");
    
    	if (gDTMFMode & H323_DTMF_CISCO) {
    
    		ast_cli(a->fd, "%s\n", "cisco");
    		ast_cli(a->fd, "%-20.15s%d\n", "DTMF Codec: ", gDTMFCodec);
    
    	} else if (gDTMFMode & H323_DTMF_RFC2833) {
    
    		ast_cli(a->fd, "%s\n", "rfc2833");
    		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, "%s\n", "disabled");
    
    	} else if (gT38Support == T38_FAXGW) {
    
    		ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible");
    
    	}
    	if (gFAXdetect == (FAXDETECT_CNG | FAXDETECT_T38)) {
    		ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Yes");
    	} else if (gFAXdetect & FAXDETECT_CNG) {
    		ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Cng");
    	} else if (gFAXdetect & FAXDETECT_T38) {
    		ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "T.38");
    	} else {
    		ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "No");
    	}
    
    	if (gRTDRCount && gRTDRInterval) {
    		ast_cli(a->fd, "%-20.15s%d,%d\n", "RoundTrip: ", gRTDRCount, gRTDRInterval);
    	}
    
    	ast_cli(a->fd, "%-20s%ld\n", "Call counter: ", callnumber);
    	ast_cli(a->fd, "%-20s%s\n", "AccountCode: ", gAccountcode);
    
    	ast_cli(a->fd, "%-20s%s\n", "AMA flags: ", ast_channel_amaflags2string(gAMAFLAGS));
    
    	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);
    
    		} else {
    			ast_cli(a->fd,"\t%-30s\n",pAlias->value);
    
    			pAlias = pAlias->next;
    		}
    	}
    	return CLI_SUCCESS;
    }
    
    static struct ast_cli_entry cli_ooh323[] = {
    	AST_CLI_DEFINE(handle_cli_ooh323_set_debug,	"Enable/Disable OOH323 debugging"),
    	AST_CLI_DEFINE(handle_cli_ooh323_show_config, "Show details on global configuration of H.323 channel driver"),
    
    	AST_CLI_DEFINE(handle_cli_ooh323_show_gk, "Show OOH323 Gatekeeper connection status"),
    
    	AST_CLI_DEFINE(handle_cli_ooh323_show_peer,	"Show details on specific OOH323 peer"),
    	AST_CLI_DEFINE(handle_cli_ooh323_show_peers,  "Show defined OOH323 peers"),
    	AST_CLI_DEFINE(handle_cli_ooh323_show_user,	"Show details on specific OOH323 user"),
    	AST_CLI_DEFINE(handle_cli_ooh323_show_users,  "Show defined OOH323 users"),
    
            AST_CLI_DEFINE(handle_cli_ooh323_reload, "reload ooh323 config")
    
    /*! \brief OOH323 Dialplan function - reads ooh323 settings */
    static int function_ooh323_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
    {
    
    	struct ooh323_pvt *p = ast_channel_tech_pvt(chan);
    
    
    	ast_channel_lock(chan);
    	if (!p) {
    		ast_channel_unlock(chan);
    		return -1;
    	}
    
    
    	if (strcmp(ast_channel_tech(chan)->type, "OOH323")) {
    		ast_log(LOG_ERROR, "This function is only supported on OOH323 channels, Channel is %s\n", ast_channel_tech(chan)->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 = ast_channel_tech_pvt(chan);
    
    	int res = -1;
    
    	ast_channel_lock(chan);
    	if (!p) {
    		ast_channel_unlock(chan);
    		return -1;
    	}
    
    
    	if (strcmp(ast_channel_tech(chan)->type, "OOH323")) {
    		ast_log(LOG_ERROR, "This function is only supported on OOH323 channels, Channel is %s\n", ast_channel_tech(chan)->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)
    {
    	struct ooAliases * pNewAlias = NULL;
    	struct ooh323_peer *peer = NULL;
    	OOH225MsgCallbacks h225Callbacks = {0, 0, 0, 0};
    
    	OOH323CALLBACKS h323Callbacks = {
    		.onNewCallCreated = onNewCallCreated,
    		.onAlerting = onAlerting,
    
    		.onProgress = onProgress,
    
    		.onOutgoingCall = onOutgoingCall,
    
    		.onCallEstablished = onCallEstablished,
    		.onCallCleared = onCallCleared,
    		.openLogicalChannels = NULL,
    
    		.onReceivedDTMF = ooh323_onReceivedDigit,
    
    		.onModeChanged = onModeChanged,
    		.onMediaChanged = (cb_OnMediaChanged) setup_rtp_remote,
    
    	if (!(gCap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
    
    		return AST_MODULE_LOAD_DECLINE;
    
    	if (!(ooh323_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
    		ao2_ref(gCap, -1);
    		gCap = NULL;
    
    		return AST_MODULE_LOAD_DECLINE;
    
    	ast_format_cap_append(gCap, ast_format_ulaw, 0);
    	ast_format_cap_append_by_type(ooh323_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN);
    
    	myself = ast_module_info->self;
    
    
    	h225Callbacks.onReceivedSetup = &ooh323_onReceivedSetup;
    
    	userl.users = NULL;
    	ast_mutex_init(&userl.lock);
    	peerl.peers = NULL;
    	ast_mutex_init(&peerl.lock);
    
    	ast_register_atexit(&ast_ooh323c_exit);
    #endif
    
    
    	if (!(sched = ast_sched_context_create())) {
    
    		ast_log(LOG_WARNING, "Unable to create schedule context\n");
    	}
    	if (!(io = io_context_create())) {
    		ast_log(LOG_WARNING, "Unable to create I/O context\n");
    	}
    
    
    
    		/* fire up the H.323 Endpoint */
    
    		if (OO_OK != ooH323EpInitialize(OO_CALLMODE_AUDIOCALL, gLogFile, gInitError, sizeof(gInitError))) {
    			ast_log(LOG_ERROR, "Failed to initialize OOH323 endpoint: %s"
    				"OOH323 Disabled\n", gInitError);
    
    			ao2_ref(gCap, -1);
    			gCap = NULL;
    			ao2_ref(ooh323_tech.capabilities, -1);
    			ooh323_tech.capabilities = NULL;
    
    			return AST_MODULE_LOAD_DECLINE;
    
    		/* Make sure we can register our OOH323 channel type */
    		if (ast_channel_register(&ooh323_tech)) {
    			ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
    
    			ao2_ref(gCap, -1);
    			gCap = NULL;
    			ao2_ref(ooh323_tech.capabilities, -1);
    			ooh323_tech.capabilities = NULL;
    
    			return AST_MODULE_LOAD_DECLINE;
    
    		ast_rtp_glue_register(&ooh323_rtp);
    
    		ast_cli_register_multiple(cli_ooh323, sizeof(cli_ooh323) / sizeof(struct ast_cli_entry));
    
    		if (gIsGateway)
    			ooH323EpSetAsGateway();
    
    
          		ooH323EpSetVersionInfo(t35countrycode, t35extensions, manufacturer,
    									 vendor, version);
    
    		ooH323EpDisableAutoAnswer();
    		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, ooconfig.mTCPPortEnd) == OO_FAILED) {
    			ast_log(LOG_ERROR, "h225portrange: Failed to set range\n");
    		}
    
    		/* Set aliases if any */
    		for (pNewAlias = gAliasList; pNewAlias; pNewAlias = pNewAlias->next) {
    			switch (pNewAlias->type) {
    			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;
    
    			}
    		}
    
    		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);
    
    
    		if (gMediaWaitForConnect)
    			ooH323EpEnableMediaWaitForConnect();
    
    			ooH323EpDisableMediaWaitForConnect();
    
    		/* Fast start and tunneling options */
    		if (gFastStart)
    			ooH323EpEnableFastStart();
    		else
    			ooH323EpDisableFastStart();
    
    		if (!gTunneling)
    			ooH323EpDisableH245Tunneling();
    
    
    		if (gBeMaster)
    			ooH323EpTryBeMaster(1);
    
          		ooH323EpEnableManualRingback();
    
    
    		/* Gatekeeper */
    		if (gRasGkMode == RasUseSpecificGatekeeper)
    
    			ooGkClientInit(gRasGkMode, gGatekeeper, gRASIP, 0);
    
    		else if (gRasGkMode == RasDiscoverGatekeeper)
    
    			ooGkClientInit(gRasGkMode, 0, gRASIP, 0);
    
    
    		/* Register callbacks */
    		ooH323EpSetH323Callbacks(h323Callbacks);
    
    		/* Add endpoint capabilities */
    
    		if (ooh323c_set_capability(gCap, gDTMFMode, gDTMFCodec) < 0) {
    
    			ast_log(LOG_ERROR, "Capabilities failure for OOH323. OOH323 Disabled.\n");
    
    			ao2_ref(gCap, -1);
    			gCap = NULL;
    			ao2_ref(ooh323_tech.capabilities, -1);
    			ooh323_tech.capabilities = NULL;
    
    		/* Create H.323 listener */
    		if (ooCreateH323Listener() != OO_OK) {
    
             		ast_log(LOG_ERROR, "OOH323 Listener Creation failure. "
    
                                "OOH323 DISABLED\n");
    
    			ao2_ref(gCap, -1);
    			gCap = NULL;
    			ao2_ref(ooh323_tech.capabilities, -1);
    			ooh323_tech.capabilities = NULL;
    
    			return 1;
    		}
    
    		if (ooh323c_start_stack_thread() < 0) {
    
    			ast_log(LOG_ERROR, "Failed to start OOH323 stack thread. "
    
                                "OOH323 DISABLED\n");
    
    			ao2_ref(gCap, -1);
    			gCap = NULL;
    			ao2_ref(ooh323_tech.capabilities, -1);
    			ooh323_tech.capabilities = NULL;
    
    			return 1;
    		}
    		/* And start the monitor for the first time */
    		restart_monitor();
    
    	} else {
    		ast_log(LOG_ERROR, "Can't load ooh323 config file, OOH323 Disabled\n");
    
    		return AST_MODULE_LOAD_DECLINE;
    
    static int reload_module(void)
    {
    	ast_mutex_lock(&h323_reload_lock);
    	if (h323_reloading) {
    		ast_verb(0, "Previous OOH323 reload not yet done\n");
    	} else {
    		h323_reloading = 1;
    	}
    	ast_mutex_unlock(&h323_reload_lock);
    	restart_monitor();
    
    	if (gH323Debug)
    		ast_verb(0, "+++   ooh323_reload\n");
    
    	return 0;
    }
    
    
    static void *do_monitor(void *data)
    {
    	int res;