Index: channels/chan_h323.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_h323.c,v
retrieving revision 1.109
diff -u -r1.109 chan_h323.c
--- channels/chan_h323.c	29 Apr 2005 04:22:47 -0000	1.109
+++ channels/chan_h323.c	29 Apr 2005 14:08:42 -0000
@@ -83,6 +83,7 @@
 progress_cb on_progress;
 rfc2833_cb on_set_rfc2833_payload;
 hangup_cb on_hangup;
+setcapabilities_cb on_setcapabilities;
 
 /* global debug flag */
 int h323debug;
@@ -174,8 +175,9 @@
    when it's doing something critical. */
 AST_MUTEX_DEFINE_STATIC(monlock);
 
-/* Protect the H.323 capabilities list, to avoid more than one channel to set the capabilities simultaneaously in the h323 stack. */
-AST_MUTEX_DEFINE_STATIC(caplock);
+/* Protect incrementation of unique identifier */
+AST_MUTEX_DEFINE_STATIC(uniquelock);
+static unsigned int unique = 0;
 
 /* Protect the reload process */
 AST_MUTEX_DEFINE_STATIC(h323_reload_lock);
@@ -217,11 +219,8 @@
 #endif
 };
 
-static void oh323_update_info(struct ast_channel *c)
+static void __oh323_update_info(struct ast_channel *c, struct oh323_pvt *pvt)
 {
-	struct oh323_pvt *pvt = c->tech_pvt;
-
-	ast_mutex_lock(&pvt->lock);
 	if (c->nativeformats != pvt->nativeformats) {
 		if (h323debug)
 			ast_log(LOG_DEBUG, "Preparing %s for new native format\n", c->name);
@@ -237,7 +236,17 @@
 		ast_queue_hangup(c);
 		pvt->needhangup = 0;
 	}
-	ast_mutex_unlock(&pvt->lock);
+}
+
+static void oh323_update_info(struct ast_channel *c)
+{
+	struct oh323_pvt *pvt = c->tech_pvt;
+
+	if (pvt) {
+		ast_mutex_lock(&pvt->lock);
+		__oh323_update_info(c, pvt);
+		ast_mutex_unlock(&pvt->lock);
+	}
 }
 
 static void cleanup_call_details(call_details_t *cd) 
@@ -351,7 +360,7 @@
 static struct oh323_user *build_user(char *name, struct ast_variable *v)
 {
 	struct oh323_user *user;
-	int format;
+	int format, tmp;
 	
 	user = (struct oh323_user *)malloc(sizeof(struct oh323_user));
 	if (user) {
@@ -402,7 +411,11 @@
 			} else if (!strcasecmp(v->name, "progress_audio")) {
 				user->options.progress_audio = ast_true(v->value);
 			} else if (!strcasecmp(v->name, "dtmfcodec")) {
-				user->options.dtmfcodec = atoi(v->value);
+				tmp = atoi(v->value);
+				if (tmp < 96)
+					ast_log(LOG_WARNING, "Invalid dtmfcodec value %s for user %s\n", v->value, name);
+				else
+					user->options.dtmfcodec = tmp;
 			} else if (!strcasecmp(v->name, "host")) {
 				if (!strcasecmp(v->value, "dynamic")) {
 					ast_log(LOG_ERROR, "A dynamic host on a type=user does not make any sense\n");
@@ -434,7 +447,7 @@
 	struct oh323_peer *prev;
 	struct ast_ha *oldha = NULL;
 	int found=0;
-	int format;	
+	int format, tmp;
 
 	prev = NULL;
 	ast_mutex_lock(&peerl.lock);
@@ -508,7 +521,11 @@
 			} else if (!strcasecmp(v->name, "progress_audio")) {
 				peer->options.progress_audio = ast_true(v->value);
 			} else if (!strcasecmp(v->name, "dtmfcodec")) {
-				peer->options.dtmfcodec = atoi(v->value);
+				tmp = atoi(v->value);
+				if (tmp < 96)
+					ast_log(LOG_WARNING, "Invalid dtmfcodec value %s for peer %s\n", v->value, name);
+				else
+					peer->options.dtmfcodec = tmp;
 			} else if (!strcasecmp(v->name, "dtmfmode")) {
 				if (!strcasecmp(v->value, "inband")) {
 					peer->dtmfmode = H323_DTMF_INBAND;
@@ -601,6 +618,7 @@
                 ast_log(LOG_WARNING, "Line is already in use (%s)\n", c->name);
                 return -1;
         }
+        ast_mutex_lock(&pvt->lock);
         if (usingGk) {
                 pvt->options.port = h323_signalling_port;
                 if (ast_strlen_zero(pvt->exten)) {
@@ -631,6 +649,7 @@
 	pvt->outgoing = 1;
 
 	ast_log(LOG_DEBUG, "Placing outgoing call to %s, %d\n", called_addr, pvt->options.dtmfcodec);
+	ast_mutex_unlock(&pvt->lock);
 	res = h323_make_call(called_addr, &(pvt->cd), &pvt->options);
 	if (res) {
 		ast_log(LOG_NOTICE, "h323_make_call failed(%s)\n", c->name);
@@ -789,7 +808,7 @@
 	struct ast_frame *fr;
 	struct oh323_pvt *pvt = (struct oh323_pvt *)c->tech_pvt;
 	ast_mutex_lock(&pvt->lock);
-	oh323_update_info(c);
+	__oh323_update_info(c, pvt);
 	fr = oh323_rtp_read(pvt);
 	ast_mutex_unlock(&pvt->lock);
 	return fr;
@@ -1033,7 +1052,7 @@
 	return pvt;
 }
 
-static struct oh323_pvt *find_call(int call_reference, const char *token)
+static struct oh323_pvt *find_call_locked(int call_reference, const char *token)
 {  
         struct oh323_pvt *pvt;
 
@@ -1043,10 +1062,12 @@
                 if (!pvt->needdestroy && ((signed int)pvt->cd.call_reference == call_reference)) {
                         /* Found the call */             
                         if ((token != NULL) && (!strcmp(pvt->cd.call_token, token))) {
+                        	ast_mutex_lock(&pvt->lock);
         			ast_mutex_unlock(&iflock);
 	        		return pvt;
                         } else if (token == NULL) {
                                 ast_log(LOG_DEBUG, "Call Token is NULL\n");
+                                ast_mutex_lock(&pvt->lock);
                                 ast_mutex_unlock(&iflock);
                                 return pvt;
                         }
@@ -1057,21 +1078,21 @@
 	return NULL;
 }
 
-struct oh323_user *find_user(const call_details_t cd)
+struct oh323_user *find_user(const call_details_t *cd)
 {
 	struct oh323_user *u;
 	char iabuf[INET_ADDRSTRLEN];
 	u = userl.users;
 	if (userbyalias) {
 		while(u) {
-			if (!strcasecmp(u->name, cd.call_source_aliases)) {
+			if (!strcasecmp(u->name, cd->call_source_aliases)) {
 				break;
 			}
 			u = u->next;
 		}
 	} else {
 		while(u) {
-			if (!strcasecmp(cd.sourceIp, ast_inet_ntoa(iabuf, sizeof(iabuf), u->addr.sin_addr))) {
+			if (!strcasecmp(cd->sourceIp, ast_inet_ntoa(iabuf, sizeof(iabuf), u->addr.sin_addr))) {
 				break;
 			}
 			u = u->next;
@@ -1228,13 +1249,12 @@
 	else
 		memcpy(&pvt->options, &global_options, sizeof(pvt->options));
 
-	/* pass on our capabilites to the H.323 stack */
-	ast_mutex_lock(&caplock);
-	h323_set_capability(pvt->capability, pvt->dtmfmode);
-	ast_mutex_unlock(&caplock);
-	
+	ast_mutex_lock(&uniquelock);
+	snprintf(tmp, sizeof(tmp)-1, "%s-%u", host, ++unique);
+	ast_mutex_unlock(&uniquelock);
+
 	ast_mutex_lock(&pvt->lock);
-	tmpc = oh323_new(pvt, AST_STATE_DOWN, host);
+	tmpc = oh323_new(pvt, AST_STATE_DOWN, tmp);
 	ast_mutex_unlock(&pvt->lock);
 	if (!tmpc) {
 		oh323_destroy(pvt);
@@ -1267,9 +1287,10 @@
 {
 	struct oh323_pvt *pvt;
 	struct ast_frame f;
+	int res;
 
 	ast_log(LOG_DEBUG, "Recieved Digit: %c\n", digit);
-	pvt = find_call(call_reference, token); 
+	pvt = find_call_locked(call_reference, token); 
 	if (!pvt) {
 		ast_log(LOG_ERROR, "Private structure not found in send_digit.\n");
 		return -1;
@@ -1283,7 +1304,9 @@
  	f.data = NULL;
     	f.mallocd = 0;
     	f.src = "SEND_DIGIT";	
-	return ast_queue_frame(pvt->owner, &f);	
+    	res = ast_queue_frame(pvt->owner, &f);
+    	ast_mutex_unlock(&pvt->lock);
+	return res;
 }
 
 /**
@@ -1294,28 +1317,27 @@
 struct rtp_info *external_rtp_create(unsigned call_reference, const char * token)
 {	
 	struct oh323_pvt *pvt;
-	struct sockaddr_in us;
 	struct rtp_info *info;
-	char iabuf[INET_ADDRSTRLEN];
+       	char iabuf[INET_ADDRSTRLEN];
 
 	info = (struct rtp_info *)malloc(sizeof(struct rtp_info));
 	if (!info) {
 		ast_log(LOG_ERROR, "Unable to allocated info structure, this is very bad\n");
 		return NULL;
 	}
-	pvt = find_call(call_reference, token); 
+	pvt = find_call_locked(call_reference, token); 
 	if (!pvt) {
 		ast_log(LOG_ERROR, "Unable to find call %s(%d)\n", token, call_reference);
 		return NULL;
 	}
-	ast_mutex_lock(&pvt->lock);
 	/* figure out our local RTP port and tell the H.323 stack about it */
-	ast_rtp_get_us(pvt->rtp, &us);
+	ast_rtp_get_us(pvt->rtp, &info->rtp_addr);
+	if (info->rtp_addr.sin_addr.s_addr == INADDR_ANY)
+		info->rtp_addr.sin_addr = bindaddr.sin_addr;	/* hmm... do we need this? */
 	ast_mutex_unlock(&pvt->lock);
 	/* evil hack, until I (or someone?) figures out a better way */
-	info->addr = ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr);
-	info->port = ntohs(us.sin_port);
-	ast_log(LOG_DEBUG, "Sending RTP 'US' %s:%d\n", info->addr, info->port);
+	ast_inet_ntoa(iabuf, sizeof(iabuf), info->rtp_addr.sin_addr);
+	ast_log(LOG_DEBUG, "Sending RTP 'US' %s:%d\n", iabuf, ntohs(info->rtp_addr.sin_port));
 	return info;
 }
 
@@ -1343,12 +1365,11 @@
 	if (h323debug)
 		ast_log(LOG_DEBUG, "Setting up RTP connection for %s\n", token);
 	/* Find the call or allocate a private structure if call not found */
-	pvt = find_call(call_reference, token); 
+	pvt = find_call_locked(call_reference, token); 
 	if (!pvt) {
 		ast_log(LOG_ERROR, "Something is wrong: rtp\n");
 		return;
 	}
-	ast_mutex_lock(&pvt->lock);
 	if (pvt->alreadygone) {
 		ast_mutex_unlock(&pvt->lock);
 		return;
@@ -1361,6 +1382,8 @@
 		ast_set_write_format(pvt->owner, pvt->owner->writeformat);
 		ast_mutex_unlock(&pvt->owner->lock);
 	}
+	else if (h323debug)
+		ast_log(LOG_DEBUG, "RTP connection preparation for %s is pending...\n", token);
 
 	them.sin_family = AF_INET;
 	/* only works for IPv4 */
@@ -1392,14 +1415,12 @@
 	if (h323debug)
 		ast_log(LOG_DEBUG, "Call %s answered\n", token);
 	
-	pvt = find_call(call_reference, token); 
-	
+	pvt = find_call_locked(call_reference, token); 
 	if (!pvt) {
 		ast_log(LOG_ERROR, "Something is wrong: connection\n");
 		return;
 	}
 
-	ast_mutex_lock(&pvt->lock);
 	/* Inform asterisk about remote party connected only on outgoing calls */
 	if (!pvt->outgoing) {
 		ast_mutex_unlock(&pvt->lock);
@@ -1424,13 +1445,11 @@
 	struct oh323_pvt *p;
 
 	ast_log(LOG_DEBUG, "Received ALERT/PROGRESS message for %s tones\n", (inband ? "inband" : "self-generated"));
-	p = find_call(call_reference, token);
-
+	p = find_call_locked(call_reference, token);
 	if (!p) {
 		ast_log(LOG_ERROR, "Private structure not found in progress.\n");
 		return -1;
 	}
-	ast_mutex_lock(&p->lock);
 	if (!p->owner) {
 		ast_mutex_unlock(&p->lock);
 		ast_log(LOG_ERROR, "No Asterisk channel associated with private structure.\n");
@@ -1449,7 +1468,7 @@
  *
  *  Returns 1 on success
  */
-call_options_t *setup_incoming_call(call_details_t cd)
+call_options_t *setup_incoming_call(call_details_t *cd)
 {
 	struct oh323_pvt *pvt = NULL;
 	struct oh323_user *user = NULL;
@@ -1458,10 +1477,10 @@
 	char iabuf[INET_ADDRSTRLEN];
 
 	if (h323debug)
-		ast_log(LOG_DEBUG, "Setting up incoming call for %s\n", cd.call_token);
+		ast_log(LOG_DEBUG, "Setting up incoming call for %s\n", cd->call_token);
 
 	/* allocate the call*/
-	pvt = oh323_alloc(cd.call_reference);
+	pvt = oh323_alloc(cd->call_reference);
 
 	if (!pvt) {
 		ast_log(LOG_ERROR, "Unable to allocate private structure, this is bad.\n");
@@ -1469,12 +1488,8 @@
 	}
 
 	/* Populate the call details in the private structure */
-	pvt->cd.call_token = strdup(cd.call_token);
-	pvt->cd.call_source_aliases = strdup(cd.call_source_aliases);
-	pvt->cd.call_dest_alias = strdup(cd.call_dest_alias);
-	pvt->cd.call_source_name = strdup(cd.call_source_name);
-	pvt->cd.call_source_e164 = strdup(cd.call_source_e164);
-	pvt->cd.call_dest_e164 = strdup(cd.call_dest_e164);
+	memcpy(&pvt->cd, cd, sizeof(pvt->cd));
+	memcpy(&pvt->options, &global_options, sizeof(pvt->options));
 	call_options = &pvt->options;
 
 	if (h323debug) {
@@ -1487,14 +1502,14 @@
 	}
 
 	/* Decide if we are allowing Gatekeeper routed calls*/
-	if ((!strcasecmp(cd.sourceIp, gatekeeper)) && (gkroute == -1) && (usingGk)) {		
-		if (!ast_strlen_zero(cd.call_dest_e164)) {
-			strncpy(pvt->exten, cd.call_dest_e164, sizeof(pvt->exten) - 1);
+	if ((!strcasecmp(cd->sourceIp, gatekeeper)) && (gkroute == -1) && (usingGk)) {		
+		if (!ast_strlen_zero(cd->call_dest_e164)) {
+			strncpy(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten) - 1);
 			strncpy(pvt->context, default_context, sizeof(pvt->context) - 1); 
 		} else {
-			alias = find_alias(cd.call_dest_alias);
+			alias = find_alias(cd->call_dest_alias);
 			if (!alias) {
-				ast_log(LOG_ERROR, "Call for %s rejected, alias not found\n", cd.call_dest_alias);
+				ast_log(LOG_ERROR, "Call for %s rejected, alias not found\n", cd->call_dest_alias);
 				return NULL;
 			}
 			strncpy(pvt->exten, alias->name, sizeof(pvt->exten) - 1);
@@ -1506,23 +1521,23 @@
 		user  = find_user(cd);
 		if (!user) {
 			if (!ast_strlen_zero(pvt->cd.call_dest_e164)) {
-				strncpy(pvt->exten, cd.call_dest_e164, sizeof(pvt->exten) - 1);
+				strncpy(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten) - 1);
 			} else {
-				strncpy(pvt->exten, cd.call_dest_alias, sizeof(pvt->exten) - 1);
+				strncpy(pvt->exten, cd->call_dest_alias, sizeof(pvt->exten) - 1);
 			}
 			if (ast_strlen_zero(default_context)) {
 				ast_log(LOG_ERROR, "Call from '%s' rejected due to no default context\n", pvt->cd.call_source_aliases);
 				return NULL;
 			}
 			strncpy(pvt->context, default_context, sizeof(pvt->context) - 1);
-			ast_log(LOG_DEBUG, "Sending %s to context [%s]\n", cd.call_source_aliases, pvt->context);
+			ast_log(LOG_DEBUG, "Sending %s to context [%s]\n", cd->call_source_aliases, pvt->context);
 			memset(&pvt->options, 0, sizeof(pvt->options));
 		} else {					
 			if (user->host) {
-				if (strcasecmp(cd.sourceIp, ast_inet_ntoa(iabuf, sizeof(iabuf), user->addr.sin_addr))){					
+				if (strcasecmp(cd->sourceIp, ast_inet_ntoa(iabuf, sizeof(iabuf), user->addr.sin_addr))){					
 					if (ast_strlen_zero(user->context)) {
 						if (ast_strlen_zero(default_context)) {					
-							ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s) and no default context\n", user->name, cd.sourceIp);
+							ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s) and no default context\n", user->name, cd->sourceIp);
                 					return NULL;
 						}
 						strncpy(pvt->context, default_context, sizeof(pvt->context) - 1);
@@ -1531,7 +1546,7 @@
 					}
 					pvt->exten[0] = 'i';
 					pvt->exten[1] = '\0';
-					ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s)s\n", user->name, cd.sourceIp);
+					ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s)s\n", user->name, cd->sourceIp);
 					return NULL;
 				}
 			}
@@ -1539,9 +1554,9 @@
 			pvt->bridge = user->bridge;
                       	pvt->nat = user->nat;
 			if (!ast_strlen_zero(pvt->cd.call_dest_e164)) {
-				strncpy(pvt->exten, cd.call_dest_e164, sizeof(pvt->exten) - 1);
+				strncpy(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten) - 1);
 			} else {
-				strncpy(pvt->exten, cd.call_dest_alias, sizeof(pvt->exten) - 1);
+				strncpy(pvt->exten, cd->call_dest_alias, sizeof(pvt->exten) - 1);
 			}
 			if (!ast_strlen_zero(user->accountcode)) {
 				strncpy(pvt->accountcode, user->accountcode, sizeof(pvt->accountcode) - 1);
@@ -1569,14 +1584,11 @@
 		ast_log(LOG_DEBUG, "Preparing Asterisk to answer for %s\n", token);
 
 	/* Find the call or allocate a private structure if call not found */
-	pvt = find_call(call_reference, token); 
+	pvt = find_call_locked(call_reference, token); 
 	if (!pvt) {
 		ast_log(LOG_ERROR, "Something is wrong: answer_call\n");
 		return 0;
 	}
-	/* Briefly lock call for oh323_new() */
-	ast_mutex_lock(&pvt->lock);
-
 	/* allocate a channel and tell asterisk about it */
 	c = oh323_new(pvt, AST_STATE_RINGING, pvt->cd.call_token);
 
@@ -1611,11 +1623,10 @@
 	if (h323debug)
 		ast_log(LOG_DEBUG, "Ringing on %s\n", token);
 
-        pvt = find_call(call_reference, token); 
+        pvt = find_call_locked(call_reference, token); 
         if (!pvt) {
                 ast_log(LOG_ERROR, "Something is wrong: ringing\n");
 	}
-	ast_mutex_lock(&pvt->lock);
         if (!pvt->owner) {
         	ast_mutex_unlock(&pvt->lock);
                 ast_log(LOG_ERROR, "Channel has no owner\n");
@@ -1634,26 +1645,26 @@
   * Call-back function to cleanup communication
   * Returns nothing,
   */
-static void cleanup_connection(call_details_t cd)
+static void cleanup_connection(unsigned call_reference, const char *call_token)
 {	
 	struct oh323_pvt *pvt = NULL;
 	struct ast_rtp *rtp = NULL;
 
-	ast_log(LOG_DEBUG, "Cleaning connection to %s\n", cd.call_token);
+	ast_log(LOG_DEBUG, "Cleaning connection to %s\n", call_token);
 	
 	while (1) {
-		pvt = find_call(cd.call_reference, cd.call_token); 
+		pvt = find_call_locked(call_reference, call_token); 
 		if (!pvt) {
+			ast_log(LOG_DEBUG, "No connection for %s\n", call_token);
 			return;
 		}
-		ast_mutex_lock(&pvt->lock);
 		if (!pvt->owner || !ast_mutex_trylock(&pvt->owner->lock))
 			break;
 #if 1
 #ifdef DEBUG_THREADS
-		ast_log(LOG_NOTICE, "Avoiding H.323 destory deadlock on %s, locked at %ld/%d by %s (%s:%d)\n", cd.call_token, pvt->owner->lock.thread, pvt->owner->lock.reentrancy, pvt->owner->lock.func, pvt->owner->lock.file, pvt->owner->lock.lineno);
+		ast_log(LOG_NOTICE, "Avoiding H.323 destory deadlock on %s, locked at %ld/%d by %s (%s:%d)\n", call_token, pvt->owner->lock.thread, pvt->owner->lock.reentrancy, pvt->owner->lock.func, pvt->owner->lock.file, pvt->owner->lock.lineno);
 #else
-		ast_log(LOG_NOTICE, "Avoiding H.323 destory deadlock on %s\n", cd.call_token);
+		ast_log(LOG_NOTICE, "Avoiding H.323 destory deadlock on %s\n", call_token);
 #endif
 #endif
 		ast_mutex_unlock(&pvt->lock);
@@ -1679,6 +1690,7 @@
 		ast_mutex_unlock(&pvt->owner->lock);
 	}
 	ast_mutex_unlock(&pvt->lock);
+	ast_log(LOG_DEBUG, "Connection to %s cleaned\n", call_token);
 	return;	
 }
 
@@ -1688,11 +1700,10 @@
 
 	ast_log(LOG_DEBUG, "Hanging up connection to %s with cause %d\n", token, cause);
 	
-	pvt = find_call(call_reference, token); 
+	pvt = find_call_locked(call_reference, token); 
 	if (!pvt) {
 		return;
 	}
-	ast_mutex_lock(&pvt->lock);
 	if (pvt->owner && !ast_mutex_trylock(&pvt->owner->lock)) {
 		pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV;
 		pvt->owner->hangupcause = pvt->hangupcause = cause;
@@ -1702,7 +1713,7 @@
 	else {
 		pvt->needhangup = 1;
 		pvt->hangupcause = cause;
-		ast_log(LOG_DEBUG, "Hangup for %s is pending\n", token);
+		ast_log(LOG_DEBUG, "Hangup for %s is pending, owner=0x%p\n", token, pvt->owner);
 	}
 	ast_mutex_unlock(&pvt->lock);
 }
@@ -1714,11 +1725,10 @@
 	if (h323debug)
 		ast_log(LOG_DEBUG, "Setting DTMF payload to %d on %s\n", payload, token);
 
-	pvt = find_call(call_reference, token);
+	pvt = find_call_locked(call_reference, token);
 	if (!pvt) {
 		return;
 	}
-	ast_mutex_lock(&pvt->lock);
 	if (pvt->rtp) {
 		ast_rtp_set_rtpmap_type(pvt->rtp, payload, "audio", "telephone-event");
 	}
@@ -1727,6 +1737,26 @@
 		ast_log(LOG_DEBUG, "DTMF payload on %s set to %d\n", token, payload);
 }
 
+static void set_local_capabilities(unsigned call_reference, const char *token)
+{
+	struct oh323_pvt *pvt = NULL;
+	int capability, dtmfmode;
+	
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Setting capabilities for connection %s\n", token);
+
+	pvt = find_call_locked(call_reference, token);
+	if (!pvt)
+		return;
+	capability = pvt->capability;
+	dtmfmode = pvt->dtmfmode;
+	ast_mutex_unlock(&pvt->lock);
+	h323_set_capability(token, capability, dtmfmode);
+
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Capabilities for connection %s is set\n", token);
+}
+
 static void *do_monitor(void *data)
 {
 	int res;
@@ -1945,7 +1975,7 @@
 
 int reload_config(void)
 {	
-	int format;
+	int format, tmp;
 	struct ast_config *cfg;
 	struct ast_variable *v;
 	struct oh323_peer *peer   = NULL;
@@ -2041,7 +2071,11 @@
 				dtmfmode = H323_DTMF_RFC2833;
 			}
 		} else if (!strcasecmp(v->name, "dtmfcodec")) {
-			global_options.dtmfcodec = atoi(v->value);
+			tmp = atoi(v->value);
+			if (tmp < 96)
+				ast_log(LOG_WARNING, "Invalid global dtmfcodec value %s\n", v->value);
+			else
+				global_options.dtmfcodec = tmp;
 		} else if (!strcasecmp(v->name, "UserByAlias")) {
                         userbyalias = ast_true(v->value);
                 } else if (!strcasecmp(v->name, "bridge")) {
@@ -2104,15 +2138,6 @@
 		}	
 		alias = alias->next;
 	}
-
-	/* Add our capabilities */
-	ast_mutex_lock(&caplock);
-	if (h323_set_capability(capability, dtmfmode)) {
-		ast_log(LOG_ERROR, "Capabilities failure, this is bad.\n");
-		ast_mutex_unlock(&caplock);
-		return -1;
-	}
-	ast_mutex_unlock(&caplock);
 	return 0;
 }
 
@@ -2328,7 +2353,8 @@
 				       answer_call,
 				       progress,
 				       set_dtmf_payload,
-				       hangup_connection);
+				       hangup_connection,
+				       set_local_capabilities);
 		/* start the h.323 listener */
 		if (h323_start_listener(h323_signalling_port, bindaddr)) {
 			ast_log(LOG_ERROR, "Unable to create H323 listener.\n");
@@ -2413,11 +2439,12 @@
 	io_context_destroy(io);
 	sched_context_destroy(sched);
 	delete_users();
-	delete_aliases();
-	prune_peers();
-	ast_mutex_destroy(&aliasl.lock);
+        delete_aliases();
+        prune_peers();
+        ast_mutex_destroy(&aliasl.lock);
 	ast_mutex_destroy(&userl.lock);
 	ast_mutex_destroy(&peerl.lock);
+	ast_log(LOG_DEBUG, "chan_h323 is unloaded\n");
 	return 0; 
 } 
 
Index: channels/h323/ast_h323.cpp
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/h323/ast_h323.cpp,v
retrieving revision 1.72
diff -u -r1.72 ast_h323.cpp
--- channels/h323/ast_h323.cpp	29 Apr 2005 04:22:28 -0000	1.72
+++ channels/h323/ast_h323.cpp	29 Apr 2005 14:08:43 -0000
@@ -48,12 +48,15 @@
 #include "chan_h323.h"
 #include "ast_h323.h"
 
+#define OPENH323_VER ((OPENH323_MAJOR << 16) | (OPENH323_MINOR << 8) | (OPENH323_BUILD))
+
 /* PWlib Required Components  */
 #define MAJOR_VERSION 1
 #define MINOR_VERSION 0
 #define BUILD_TYPE    ReleaseCode
 #define BUILD_NUMBER  0
 
+
 /** Counter for the number of connections */
 int channelsOpen;
 
@@ -91,7 +94,7 @@
 	friend class Buffer;
 };
 
-static PAsteriskLog *logstream = NULL;
+static PAsteriskLog *logStream = NULL;
 
 int PAsteriskLog::Buffer::overflow(int c)
 {
@@ -116,20 +119,20 @@
 int PAsteriskLog::Buffer::sync()
 {
 	char *str = strdup(string);
-	char *s, *s1;
+	char *str_beg, *str_next;
 	char c;
 
 	/* Pass each line with different ast_verbose() call */
-	for (s = str; s && *s; s = s1) {
-		s1 = strchr(s, '\n');
-		if (!s1)
-			s1 = s + strlen(s);
+	for (str_beg = str; str_beg && *str_beg; str_beg = str_next) {
+		str_next = strchr(str_beg, '\n');
+		if (!str_next)
+			str_next = str_beg + strlen(str_beg);
 		else
-			s1++;
-		c = *s1;
-		*s1 = '\0';
-		ast_verbose(s);
-		*s1 = c;
+			str_next++;
+		c = *str_next;
+		*str_next = '\0';
+		ast_verbose("%s", str_beg);
+		*str_next = c;
 	}
 	free(str);
 
@@ -139,11 +142,13 @@
 	return 0;
 }
 
-#define cout (*logstream)
+#define cout (*logStream)
 
 MyProcess::MyProcess(): PProcess("The NuFone Network's", "H.323 Channel Driver for Asterisk",
              MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER)
 {
+	/* Fix missed one in PWLib */
+	PX_firstTimeStart = FALSE;
 	Resume();
 }
 
@@ -152,7 +157,15 @@
 	cout << "  == Creating H.323 Endpoint" << endl;
 	endPoint = new MyH323EndPoint();
 	PTrace::Initialise(0, NULL, PTrace::Timestamp | PTrace::Thread | PTrace::FileAndLine);
-	PTrace::SetStream(logstream);
+	PTrace::SetStream(logStream);
+}
+
+void PAssertFunc(const char * msg)
+{
+	ast_log(LOG_ERROR, "%s\n", msg);
+#ifdef DO_CRASH
+	CRASH;
+#endif
 }
 
 H323_REGISTER_CAPABILITY(H323_G7231Capability, OPAL_G7231);
@@ -273,6 +286,13 @@
   	return NULL;
 }
 
+MyH323EndPoint::MyH323EndPoint()
+	: H323EndPoint()
+{
+	// Capabilities will be negotiated on per-connection basis
+	capabilities.RemoveAll();
+}
+
 /** MyH323EndPoint 
   * The fullAddress parameter is used directly in the MakeCall method so
   * the General form for the fullAddress argument is :
@@ -318,7 +338,7 @@
 
 	if (h323debug) {
 		cout << "\t-- " << GetLocalUserName() << " is calling host " << fullAddress << endl;
-		cout << "\t--" << "Call token is " << (const char *)token << endl;
+		cout << "\t-- Call token is " << (const char *)token << endl;
 		cout << "\t-- Call reference is " << *callReference << endl;
 		cout << "\t-- DTMF Payload is " << connection->dtmfCodec << endl;
 	}
@@ -351,11 +371,6 @@
 	terminalType = e_GatewayOnly;
 }
 
-H323Capabilities MyH323EndPoint::GetCapabilities(void)
-{
-	return capabilities;
-}
-
 BOOL MyH323EndPoint::ClearCall(const PString & token, H323Connection::CallEndReason reason)
 {
 	if (h323debug) {
@@ -412,183 +427,174 @@
 	return H323EndPoint::ForwardConnection(connection, forwardParty, pdu);
 }
 
-void MyH323EndPoint::OnConnectionEstablished(H323Connection & connection, const PString & estCallToken)
+H323Connection * MyH323EndPoint::CreateConnection(unsigned callReference, void *o)
 {
+	unsigned options = 0;
+	call_options_t *opts = (call_options_t *)o;
+
+	if (opts && opts->noFastStart) {
+		options |= H323Connection::FastStartOptionDisable;
+	} else {
+		options |= H323Connection::FastStartOptionEnable;
+	}
+	if (opts && opts->noH245Tunneling) {
+		options |= H323Connection::H245TunnelingOptionDisable;
+	} else {
+		options |= H323Connection::H245TunnelingOptionEnable;
+	}
+/* Disable until I can figure out the proper way to deal with this */
+#if 0
+	if (opts->noSilenceSuppression) {
+		options |= H323Connection::SilenceSuppresionOptionDisable;
+	} else {
+		options |= H323Connection::SilenceSUppressionOptionEnable;
+	}
+#endif
+	return new MyH323Connection(*this, callReference, options);
+}
+
+/* MyH323Connection Implementation */    
+MyH323Connection::MyH323Connection(MyH323EndPoint & ep, unsigned callReference,
+							unsigned options)
+	: H323Connection(ep, callReference, options)
+{
+	cause = -1;
 	if (h323debug) {
-		cout << "\t=-= In OnConnectionEstablished for call " << connection.GetCallReference() << endl;
-		cout << "\t\t-- Connection Established with \"" << connection.GetRemotePartyName() << "\"" << endl;
+		cout << "	== New H.323 Connection created." << endl;
 	}
-	on_connection_established(connection.GetCallReference(), (const char *)connection.GetCallToken());
+	return;
 }
 
-/** OnConnectionCleared callback function is called upon the dropping of an established
+MyH323Connection::~MyH323Connection()
+{
+	if (h323debug) {
+		cout << "	== H.323 Connection deleted." << endl;
+	}
+	return;
+}
+
+void MyH323Connection::OnEstablished()
+{
+	if (h323debug) {
+		cout << "\t=-= In OnConnectionEstablished for call " << callToken << endl;
+		cout << "\t\t-- Connection Established with \"" << GetRemotePartyName() << "\"" << endl;
+	}
+	if (connectionState != ShuttingDownConnection)
+		on_connection_established(GetCallReference(), (const char *)callToken);
+	else
+		cout << "\t\t-- Connection is in shutdown state" <<endl;
+	endpoint.OnConnectionEstablished(*this, callToken);
+}
+
+/** OnCleared callback function is called upon the dropping of an established
   * H323 connection. 
   */
-void MyH323EndPoint::OnConnectionCleared(H323Connection & connection, const PString & clearedCallToken)
+void MyH323Connection::OnCleared()
 {
 	PString remoteName;
-	call_details_t cd;
-        PIPSocket::Address Ip;
-	WORD sourcePort;
 
-	remoteName = connection.GetRemotePartyName();
-	cd.call_reference = connection.GetCallReference();
-	cd.call_token = strdup((const char *)clearedCallToken);
-	cd.call_source_aliases = strdup((const char *)connection.GetRemotePartyName());
-  	connection.GetSignallingChannel()->GetRemoteAddress().GetIpAndPort(Ip, sourcePort);
-	cd.sourceIp = strdup((const char *)Ip.AsString());
-	
-	/* Convert complex strings */
-	char *s;
-	if ((s = strchr(cd.call_source_aliases, ' ')) != NULL) {
-		*s = '\0';
-	}
-	switch (connection.GetCallEndReason()) {
-		case H323Connection::EndedByCallForwarded:
+	remoteName = GetRemotePartyName();
+
+	switch (GetCallEndReason()) {
+		case EndedByCallForwarded:
 			if (h323debug) {
 				cout << "-- " << remoteName << " has forwarded the call" << endl;
 			}
 			break;
-		case H323Connection::EndedByRemoteUser:
+		case EndedByRemoteUser:
 			if (h323debug) {
 				cout << "-- " << remoteName << " has cleared the call" << endl;
 			}
 			break;
-		case H323Connection::EndedByCallerAbort:
+		case EndedByCallerAbort:
 			if (h323debug) {
 				cout << "-- " << remoteName << " has stopped calling" << endl;
 			}
 			break;
-		case H323Connection::EndedByRefusal:
+		case EndedByRefusal:
 			if (h323debug) {
 				cout << "-- " << remoteName << " did not accept your call" << endl;
 			}
 			break;
-		case H323Connection::EndedByRemoteBusy:
+		case EndedByRemoteBusy:
 			if (h323debug) {
 				cout << "-- " << remoteName << " was busy" << endl;
 			}
 			break;
-		case H323Connection::EndedByRemoteCongestion:
+		case EndedByRemoteCongestion:
 			if (h323debug) {
 				cout << "-- Congested link to " << remoteName << endl;
 			}
 			break;
-		case H323Connection::EndedByNoAnswer:
+		case EndedByNoAnswer:
 			if (h323debug) {
 				cout << "-- " << remoteName << " did not answer your call" << endl;
 			}
 			break;
-		case H323Connection::EndedByTransportFail:
+		case EndedByTransportFail:
 			if (h323debug) {
 				cout << "-- Call with " << remoteName << " ended abnormally" << endl;
 			}
 			break;
-		case H323Connection::EndedByCapabilityExchange:
+		case EndedByCapabilityExchange:
 			if (h323debug) {
 				cout << "-- Could not find common codec with " << remoteName << endl;
 			}
 			break;
-		case H323Connection::EndedByNoAccept:
+		case EndedByNoAccept:
 			if (h323debug) {
 				cout << "-- Did not accept incoming call from " << remoteName << endl;
 			}
 			break;
-		case H323Connection::EndedByAnswerDenied:
+		case EndedByAnswerDenied:
 			if (h323debug) {
 				cout << "-- Refused incoming call from " << remoteName << endl;
 			}
 			break;
-		case H323Connection::EndedByNoUser:
+		case EndedByNoUser:
 			if (h323debug) {
 				cout << "-- Remote endpoint could not find user: " << remoteName << endl;
 			}
 			break;
-		case H323Connection::EndedByNoBandwidth:
+		case EndedByNoBandwidth:
 			if (h323debug) {
 				cout << "-- Call to " << remoteName << " aborted, insufficient bandwidth." << endl;
 			}
 			break;
-		case H323Connection::EndedByUnreachable:
+		case EndedByUnreachable:
 			if (h323debug) {
 				cout << "-- " << remoteName << " could not be reached." << endl;
 			}
 			break;
-		case H323Connection::EndedByHostOffline:
+		case EndedByHostOffline:
 			if (h323debug) {
 				cout << "-- " << remoteName << " is not online." << endl;
 			}
 			break;
-		case H323Connection::EndedByNoEndPoint:
+		case EndedByNoEndPoint:
 			if (h323debug) {
 				cout << "-- No phone running for " << remoteName << endl;
 			}
 			break;
-		case H323Connection::EndedByConnectFail:
+		case EndedByConnectFail:
 			if (h323debug) {
 				cout << "-- Transport error calling " << remoteName << endl;
 			}
 			break;
 		default:
 			if (h323debug)
-				cout << " -- Call with " << remoteName << " completed (" << connection.GetCallEndReason() << ")" << endl;
+				cout << " -- Call with " << remoteName << " completed (" << GetCallEndReason() << ")" << endl;
 
 	}
 
-	if (connection.IsEstablished()) {
+	if (IsEstablished()) {
 		if (h323debug) {
-			cout << "\t-- Call duration " << setprecision(0) << setw(5) << (PTime() - connection.GetConnectionStartTime()) << endl;
+			cout << "\t-- Call duration " << setprecision(0) << setw(5) << (PTime() - GetConnectionStartTime()) << endl;
 		}
 	}	
 	/* Invoke the PBX application registered callback */
-	on_connection_cleared(cd);
-	return;
-}
-
-H323Connection * MyH323EndPoint::CreateConnection(unsigned callReference, void *o)
-{
-	unsigned options = 0;
-	call_options_t *opts = (call_options_t *)o;
-
-	if (opts && opts->noFastStart) {
-		options |= H323Connection::FastStartOptionDisable;
-	} else {
-		options |= H323Connection::FastStartOptionEnable;
-	}
-	if (opts && opts->noH245Tunneling) {
-		options |= H323Connection::H245TunnelingOptionDisable;
-	} else {
-		options |= H323Connection::H245TunnelingOptionEnable;
-	}
-/* Disable until I can figure out the proper way to deal with this */
-#if 0
-	if (opts->noSilenceSuppression) {
-		options |= H323Connection::SilenceSuppresionOptionDisable;
-	} else {
-		options |= H323Connection::SilenceSUppressionOptionEnable;
-	}
-#endif
-	return new MyH323Connection(*this, callReference, options);
-}
-
-/* MyH323Connection Implementation */    
-MyH323Connection::MyH323Connection(MyH323EndPoint & ep, unsigned callReference,
-							unsigned options)
-	: H323Connection(ep, callReference, options)
-{
-	cause = -1;
-	if (h323debug) {
-		cout << "	== New H.323 Connection created." << endl;
-	}
-	return;
-}
-
-MyH323Connection::~MyH323Connection()
-{
-	if (h323debug) {
-		cout << "	== H.323 Connection deleted." << endl;
-	}
-	return;
+	on_connection_cleared(GetCallReference(), (const char *)callToken);
+	endpoint.OnConnectionCleared(*this, callToken);
 }
 
 BOOL MyH323Connection::OnReceivedProgress(const H323SignalPDU &pdu)
@@ -736,9 +742,7 @@
 	}
 
 	cd.call_reference = GetCallReference();
-	Lock();
 	cd.call_token = strdup((const char *)GetCallToken());
-	Unlock();
 	cd.call_source_aliases = strdup((const char *)sourceAliases);
 	cd.call_dest_alias = strdup((const char *)destAliases);
 	cd.call_source_e164 = strdup((const char *)sourceE164);
@@ -749,7 +753,7 @@
  	cd.sourceIp = strdup((const char *)Ip.AsString());
 
 	/* Notify Asterisk of the request */
-	call_options_t *res = on_incoming_call(cd); 
+	call_options_t *res = on_incoming_call(&cd); 
 
 	if (!res) {
 		if (h323debug) {
@@ -923,6 +927,12 @@
 	}
 }
 
+void MyH323Connection::OnSetLocalCapabilities()
+{
+	if (on_setcapabilities)
+		on_setcapabilities(GetCallReference(), (const char *)callToken);
+}
+
 BOOL MyH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCaps,
 					       const H245_MultiplexCapability * muxCap,
 					       H245_TerminalCapabilitySetReject & reject)
@@ -948,7 +958,22 @@
 		 					           const H245_H2250LogicalChannelParameters * /*param*/,
 								   RTP_QOS * /*param*/ )
 {
-	return new MyH323_ExternalRTPChannel(*this, capability, dir, sessionID);
+	/* Determine the Local (A side) IP Address and port */
+	struct rtp_info *info = on_external_rtp_create(GetCallReference(), (const char *)callToken);
+	if (!info) {
+		cout << "\tERROR: on_external_rtp_create failure" << endl;
+		return NULL;
+	}
+	externalIpAddr = info->rtp_addr.sin_addr;
+	externalPort = ntohs(info->rtp_addr.sin_port);
+	free(info);
+	if (externalIpAddr == INADDR_ANY) {
+		/* no vaild IP address, determite it by OpenH323 */
+		if (!GetControlChannel().GetLocalAddress().GetIpAddress(externalIpAddr))
+			return NULL;
+	}
+
+	return new MyH323_ExternalRTPChannel(*this, capability, dir, sessionID, externalIpAddr, externalPort);
 }
 
 /** This callback function is invoked once upon creation of each
@@ -956,44 +981,100 @@
   */
 BOOL MyH323Connection::OnStartLogicalChannel(H323Channel & channel)
 {    
+	/* Increase the count of channels we have open */
+	channelsOpen++;
+
 	if (h323debug) {
 		cout << "\t-- Started logical channel: ";	
 		cout << ((channel.GetDirection()==H323Channel::IsTransmitter)?"sending ":((channel.GetDirection()==H323Channel::IsReceiver)?"receiving ":" ")); 
 		cout << (const char *)(channel.GetCapability()).GetFormatName() << endl;
+		cout <<  "\t\t-- channelsOpen = " << channelsOpen << endl;
 	}
+	return connectionState != ShuttingDownConnection;
+}
 
-	/* Increase the count of channels we have open */
-	channelsOpen++;
+BOOL MyH323Connection::ClearCall(CallEndReason reason)
+{
+	SetCallEndReason(reason);
+	return endPoint->ClearCallSynchronous(callToken, reason, NULL);
+}
+
+void MyH323Connection::SetCapabilities(int cap, int dtmfMode)
+{
+	int g711Frames = 20;
+//	int gsmFrames  = 4;
+	PINDEX lastcap = -1; /* last common capability index */
+
+#if 0
+	if (cap & AST_FORMAT_SPEEX) {
+		/* Not real sure if Asterisk acutally supports all
+		   of the various different bit rates so add them 
+		   all and figure it out later*/
+
+		localCapabilities.SetCapability(0, 0, new SpeexNarrow2AudioCapability());
+		localCapabilities.SetCapability(0, 0, new SpeexNarrow3AudioCapability());
+		localCapabilities.SetCapability(0, 0, new SpeexNarrow4AudioCapability());
+		localCapabilities.SetCapability(0, 0, new SpeexNarrow5AudioCapability());
+		localCapabilities.SetCapability(0, 0, new SpeexNarrow6AudioCapability());
+	}
+#endif 
+	if (cap & AST_FORMAT_G729A) {
+		AST_G729ACapability *g729aCap;
+		AST_G729Capability *g729Cap;
+		lastcap = localCapabilities.SetCapability(0, 0, g729aCap = new AST_G729ACapability);
+		lastcap = localCapabilities.SetCapability(0, 0, g729Cap = new AST_G729Capability);
+	}
+	
+	if (cap & AST_FORMAT_G723_1) {
+		H323_G7231Capability *g7231Cap;
+		lastcap = localCapabilities.SetCapability(0, 0, g7231Cap = new H323_G7231Capability);
+	} 
+#if 0
+	if (cap & AST_FORMAT_GSM) {
+		H323_GSM0610Capability *gsmCap;
+	    	lastcap = localCapabilities.SetCapability(0, 0, gsmCap = new H323_GSM0610Capability);
+	    	gsmCap->SetTxFramesInPacket(gsmFrames);
+	} 
+#endif
+	if (cap & AST_FORMAT_ULAW) {
+		H323_G711Capability *g711uCap;
+	    	lastcap = localCapabilities.SetCapability(0, 0, g711uCap = new H323_G711Capability(H323_G711Capability::muLaw));
+		g711uCap->SetTxFramesInPacket(g711Frames);
+	} 
+
+	if (cap & AST_FORMAT_ALAW) {
+		H323_G711Capability *g711aCap;
+		lastcap = localCapabilities.SetCapability(0, 0, g711aCap = new H323_G711Capability(H323_G711Capability::ALaw));
+		g711aCap->SetTxFramesInPacket(g711Frames);
+	}
+
+	lastcap++;
+	lastcap = localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::HookFlashH245));
+
+	lastcap++;
+	mode = dtmfMode;
+	if (dtmfMode == H323_DTMF_INBAND) {
+		localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245));
+		sendUserInputMode = SendUserInputAsTone;
+	} else {
+		localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneRFC2833));
+		sendUserInputMode = SendUserInputAsInlineRFC2833;
+	}
 
 	if (h323debug) {
-		cout <<  "\t\t-- channelsOpen = " << channelsOpen << endl;
+		cout <<  "Allowed Codecs:\n\t" << setprecision(2) << localCapabilities << endl;
 	}
-	return connectionState != ShuttingDownConnection;
 }
 
 /* MyH323_ExternalRTPChannel */
 MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel(MyH323Connection & connection,
 						     const H323Capability & capability,
                                                      Directions direction,
-                                                     unsigned id)
- : H323_ExternalRTPChannel::H323_ExternalRTPChannel(connection, capability, direction, id)
+                                                     unsigned id,
+                                                     const PIPSocket::Address & ip,
+                                                     WORD dataPort)
+ : H323_ExternalRTPChannel::H323_ExternalRTPChannel(connection, capability, direction, id, ip, dataPort)
 {   
-	struct rtp_info *info;
-
-	/* Determine the Local (A side) IP Address and port */
-	info = on_external_rtp_create(connection.GetCallReference(), (const char *)connection.GetCallToken()); 
-	if (!info) {
-		cout << "\tERROR: on_external_rtp_create failure" << endl;
-		return;
-	} else {
-		localIpAddr = info->addr;
-		localPort = info->port;
-		/* tell the H.323 stack  */ 
-		SetExternalAddress(H323TransportAddress(localIpAddr, localPort), H323TransportAddress(localIpAddr, localPort + 1));
-		/* clean up allocated memory */
-		free(info);
-	}
-
 	/* Get the payload code	*/
 	OpalMediaFormat format(capability.GetFormatName(), FALSE);
 	payloadCode = format.GetPayloadType();
@@ -1012,45 +1093,29 @@
 	if (!H323_ExternalRTPChannel::Start()) {
 		return FALSE;
 	}
+	
+	if (GetDirection() == IsTransmitter) {
+		PIPSocket::Address remoteIpAddr;
+		WORD remotePort;
+		if (GetRemoteAddress(remoteIpAddr, remotePort)) {
+			if (h323debug) {
+				PIPSocket::Address localIpAddr;
+				WORD localPort;
+				externalMediaAddress.GetIpAndPort(localIpAddr, localPort);
+				cout << "\t\tExternal RTP SessionStarting\n"
+				     << "\t\tRTP channel id " << sessionID << " parameters:\n"
+				     << "\t\t-- remoteIpAddress: " << remoteIpAddr << endl
+				     << "\t\t-- remotePort: " << remotePort << "\n"
+				     << "\t\t-- ExternalIpAddress: " << localIpAddr << "\n"
+				     << "\t\t-- ExternalPort: " << localPort << endl;
+			}
 
-	/* Collect the remote information */
-	H323_ExternalRTPChannel::GetRemoteAddress(remoteIpAddr, remotePort);
-
-        if (h323debug) {
-        	cout << "\t\tExternal RTP Session Starting" << endl;
-        	cout << "\t\tRTP channel id " << sessionID << " parameters:" << endl;
-                cout << "\t\t-- remoteIpAddress: " << remoteIpAddr << endl;
-                cout << "\t\t-- remotePort: " << remotePort << endl;
-                cout << "\t\t-- ExternalIpAddress: " <<  localIpAddr << endl;
-                cout << "\t\t-- ExternalPort: " << localPort << endl;
-	}
-
-	/* Notify Asterisk of remote RTP information */
-	on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddr.AsString(), remotePort, 
-		(const char *)connection.GetCallToken(), (int)payloadCode);
-	return TRUE;
-}
-
-BOOL MyH323_ExternalRTPChannel::OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param)
-{
-	PIPSocket::Address remoteIpAddress;
-	WORD remotePort;
-
-	if (h323debug) {
-		cout << "	MyH323_ExternalRTPChannel::OnReceivedAckPDU" << endl;
-	}
-
-	if (H323_ExternalRTPChannel::OnReceivedAckPDU(param)) {
-		GetRemoteAddress(remoteIpAddress, remotePort);
-		if (h323debug) {
-			cout << "		-- remoteIpAddress: " << remoteIpAddress << endl;
-			cout << "		-- remotePort: " << remotePort << endl;
+			/* Notify Asterisk of remote RTP information */
+			on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddr.AsString(), remotePort, 
+				(const char *)connection.GetCallToken(), (int)payloadCode);
 		}
-		on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddress.AsString(),
-				remotePort, (const char *)connection.GetCallToken(), (int)payloadCode);
-		return TRUE;
 	}
-	return FALSE;
+	return TRUE;
 }
 
 /** IMPLEMENTATION OF C FUNCTIONS */
@@ -1073,7 +1138,7 @@
 void h323_end_point_create(void)
 {
 	channelsOpen = 0;
-	logstream = new PAsteriskLog();
+	logStream = new PAsteriskLog();
 	localProcess = new MyProcess();	
 	localProcess->Main();
 }
@@ -1087,17 +1152,6 @@
 	endPoint->RemoveGatekeeper();
 }
 
-void h323_end_process(void)
-{
-	endPoint->ClearAllCalls();
-	endPoint->RemoveListener(NULL);
-	delete endPoint;
-	endPoint = NULL;
-	PTrace::SetLevel(0);
-	delete localProcess;
-	delete logstream;
-}
-
 void h323_debug(int flag, unsigned level)
 {
 	if (flag) {
@@ -1119,7 +1173,8 @@
  			    answer_call_cb	acfunc,
 			    progress_cb		pgfunc,
 			    rfc2833_cb		dtmffunc,
-			    hangup_cb		hangupfunc)
+			    hangup_cb		hangupfunc,
+			    setcapabilities_cb	capabilityfunc)
 {
 	on_incoming_call = ifunc;
 	on_outgoing_call = sfunc;
@@ -1133,90 +1188,32 @@
 	on_progress = pgfunc;
 	on_set_rfc2833_payload = dtmffunc;
 	on_hangup = hangupfunc;
+	on_setcapabilities = capabilityfunc;
 }
 
 /**
  * Add capability to the capability table of the end point. 
  */
-int h323_set_capability(int cap, int dtmfMode)
+int h323_set_capability(const char *token, int cap, int dtmfMode)
 {
-	H323Capabilities oldcaps;
-	PStringArray codecs;
-	int g711Frames = 20;
-//	int gsmFrames  = 4;
-	PINDEX lastcap = -1; /* last common capability index */
-
+	MyH323Connection *conn;
 	if (!h323_end_point_exist()) {
 		cout << " ERROR: [h323_set_capablity] No Endpoint, this is bad" << endl;
 		return 1;
 	}
-
-	/* clean up old capabilities list before changing */
-	oldcaps = endPoint->GetCapabilities();
-	for (PINDEX i=0; i< oldcaps.GetSize(); i++) {
-                 codecs.AppendString(oldcaps[i].GetFormatName());
-        }
-        endPoint->RemoveCapabilities(codecs);
-
-#if 0
-	if (cap & AST_FORMAT_SPEEX) {
-		/* Not real sure if Asterisk acutally supports all
-		   of the various different bit rates so add them 
-		   all and figure it out later*/
-
-		endPoint->SetCapability(0, 0, new SpeexNarrow2AudioCapability());
-		endPoint->SetCapability(0, 0, new SpeexNarrow3AudioCapability());
-		endPoint->SetCapability(0, 0, new SpeexNarrow4AudioCapability());
-		endPoint->SetCapability(0, 0, new SpeexNarrow5AudioCapability());
-		endPoint->SetCapability(0, 0, new SpeexNarrow6AudioCapability());
-	}
-#endif 
-	if (cap & AST_FORMAT_G729A) {
-		AST_G729ACapability *g729aCap;
-		AST_G729Capability *g729Cap;
-		lastcap = endPoint->SetCapability(0, 0, g729aCap = new AST_G729ACapability);
-		lastcap = endPoint->SetCapability(0, 0, g729Cap = new AST_G729Capability);
-	}
-	
-	if (cap & AST_FORMAT_G723_1) {
-		H323_G7231Capability *g7231Cap;
-		lastcap = endPoint->SetCapability(0, 0, g7231Cap = new H323_G7231Capability);
-	} 
-#if 0
-	if (cap & AST_FORMAT_GSM) {
-		H323_GSM0610Capability *gsmCap;
-	    	lastcap = endPoint->SetCapability(0, 0, gsmCap = new H323_GSM0610Capability);
-	    	gsmCap->SetTxFramesInPacket(gsmFrames);
-	} 
-#endif
-	if (cap & AST_FORMAT_ULAW) {
-		H323_G711Capability *g711uCap;
-	    	lastcap = endPoint->SetCapability(0, 0, g711uCap = new H323_G711Capability(H323_G711Capability::muLaw));
-		g711uCap->SetTxFramesInPacket(g711Frames);
-	} 
-
-	if (cap & AST_FORMAT_ALAW) {
-		H323_G711Capability *g711aCap;
-		lastcap = endPoint->SetCapability(0, 0, g711aCap = new H323_G711Capability(H323_G711Capability::ALaw));
-		g711aCap->SetTxFramesInPacket(g711Frames);
+	if (!token || !*token) {
+		cout << " ERROR: [h323_set_capability] Invalid call token specified." << endl;
+		return 1;
 	}
-
-	lastcap++;
-	lastcap = endPoint->SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::HookFlashH245));
-
-	lastcap++;
-	mode = dtmfMode;
-	if (dtmfMode == H323_DTMF_INBAND) {
-		endPoint->SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245));
-		endPoint->SetSendUserInputMode(H323Connection::SendUserInputAsTone);
-	} else {
-		endPoint->SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneRFC2833));
-		endPoint->SetSendUserInputMode(H323Connection::SendUserInputAsInlineRFC2833);
+	PString myToken = PString(token);
+	conn = (MyH323Connection *)endPoint->FindConnectionWithLock(myToken);
+	if (!conn) {
+		cout << " ERROR: [h323_set_capability] Unable to find connection " << token << endl;
+		return 1;
 	}
+	conn->SetCapabilities(cap, dtmfMode);
+	conn->Unlock();
 
-	if (h323debug) {
-		cout <<  "Allowed Codecs:\n\t" << setprecision(2) << endPoint->GetCapabilities() << endl;
-	}
 	return 0;
 }
 
@@ -1250,8 +1247,9 @@
 {
 	char *p;
 	char *num;
-	PString h323id(alias->name);
-	PString e164(alias->e164);
+	PString h323id = PString(alias->name);
+	PString e164 = PString(alias->e164);
+	char *prefix;
 	
 	if (!h323_end_point_exist()) {
 		cout << "ERROR: [h323_set_alias] No Endpoint, this is bad!" << endl;
@@ -1267,14 +1265,13 @@
 		endPoint->AddAliasName(e164);
 	}
 	if (strlen(alias->prefix)) {
-		p = alias->prefix;
-		num = strsep(&p, ",");
-		while(num) {
-	        cout << "== Adding Prefix \"" << num << "\" to endpoint" << endl;
-		endPoint->SupportedPrefixes += PString(num);
-		endPoint->SetGateway();
-	        num = strsep(&p, ",");		
+		p = prefix = strdup(alias->prefix);
+		while((num = strsep(&p, ",")) != (char *)NULL) {
+		        cout << "== Adding Prefix \"" << num << "\" to endpoint" << endl;
+			endPoint->SupportedPrefixes += PString(num);
+			endPoint->SetGateway();
 		}
+		free(prefix);
 	}
 	return 0;
 }
@@ -1390,9 +1387,10 @@
 	connection = (MyH323Connection *)endPoint->FindConnectionWithLock(currentToken);
 	if (connection) {
 		connection->SetCause(cause);
+		connection->SetCallEndReason(r);
 		connection->Unlock();
 	}
-	endPoint->ClearCall(currentToken, r);
+	endPoint->ClearCallSynchronous(currentToken, r, NULL);
 	return 0;
 };
 
@@ -1495,6 +1493,25 @@
 	connection->Unlock();
 	return;
 
+}
+
+#undef cout
+void h323_end_process(void)
+{
+	if (endPoint) {
+		delete endPoint;
+		endPoint = NULL;
+	}
+	if (localProcess) {
+		delete localProcess;
+		localProcess = NULL;
+	}
+	PTrace::SetLevel(0);
+	PTrace::SetStream(&cout);
+	if (logStream) {
+		delete logStream;
+		logStream = NULL;
+	}
 }
 
 } /* extern "C" */
Index: channels/h323/ast_h323.h
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/h323/ast_h323.h,v
retrieving revision 1.32
diff -u -r1.32 ast_h323.h
--- channels/h323/ast_h323.h	4 Apr 2005 07:06:26 -0000	1.32
+++ channels/h323/ast_h323.h	29 Apr 2005 14:08:43 -0000
@@ -128,16 +128,14 @@
 	PCLASSINFO(MyH323EndPoint, H323EndPoint);
 
 	public:
+	MyH323EndPoint();
 	int MakeCall(const PString &, PString &, unsigned int *, call_options_t *opts);
 	BOOL ClearCall(const PString &, H323Connection::CallEndReason reason);
 	BOOL ClearCall(const PString &);
 
 	void OnClosedLogicalChannel(H323Connection &, const H323Channel &);
-	void OnConnectionEstablished(H323Connection &, const PString &);
-	void OnConnectionCleared(H323Connection &, const PString &);
 	H323Connection * CreateConnection(unsigned, void *);
 	void SendUserTone(const PString &, char);
-	H323Capabilities GetCapabilities(void);
 	BOOL OnConnectionForwarded(H323Connection &, const PString &, const H323SignalPDU &);
 	BOOL ForwardConnection(H323Connection &, const PString &, const H323SignalPDU &);
     	void SetEndpointTypeInfo( H225_EndpointType & info ) const;
@@ -152,6 +150,8 @@
 	public:
 	MyH323Connection(MyH323EndPoint &, unsigned, unsigned);
 	~MyH323Connection();
+	void OnEstablished();
+	void OnCleared();
 	H323Channel * CreateRealTimeLogicalChannel(const H323Capability &, 
 						   H323Channel::Directions, 
 					 	   unsigned, 
@@ -173,9 +173,12 @@
 	void OnUserInputString(const PString &value);
 	BOOL OnReceivedProgress(const H323SignalPDU &);
 	void OnSendCapabilitySet(H245_TerminalCapabilitySet &);
+	void OnSetLocalCapabilities();
+	void SetCapabilities(int, int);
 	BOOL OnReceivedCapabilitySet(const H323Capabilities &, const H245_MultiplexCapability *,
 				     H245_TerminalCapabilitySetReject &);
 	void SetCause(int _cause) { cause = _cause; };
+	BOOL ClearCall(CallEndReason reason = EndedByLocalUser);
 
 	PString sourceAliases;
 	PString destAliases;
@@ -193,6 +196,10 @@
 
 	PString ast_cid_num;
 	PString ast_cid_name;
+
+private:
+	PIPSocket::Address externalIpAddr;
+	WORD externalPort;
 };
 
 class MyH323_ExternalRTPChannel : public H323_ExternalRTPChannel {
@@ -204,21 +211,17 @@
 		MyH323Connection & connection,
       		const H323Capability & capability, 
       		Directions direction,              
-      		unsigned sessionID);
+      		unsigned sessionID,
+      		const PIPSocket::Address & ip,
+      		WORD dataPort);
 
 	~MyH323_ExternalRTPChannel();
 
 	/* Overrides */
 	BOOL Start(void);
-	BOOL OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param);
 
 	protected:
 	BYTE payloadCode;
-
-	PIPSocket::Address localIpAddr;
-	PIPSocket::Address remoteIpAddr;
-        WORD localPort;
-        WORD remotePort;
 }; 
 
 /**
Index: channels/h323/chan_h323.h
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/h323/chan_h323.h,v
retrieving revision 1.38
diff -u -r1.38 chan_h323.h
--- channels/h323/chan_h323.h	4 Apr 2005 07:06:26 -0000	1.38
+++ channels/h323/chan_h323.h	29 Apr 2005 14:08:43 -0000
@@ -105,8 +105,7 @@
 } call_details_t;
 
 typedef struct rtp_info {
-	const char *addr;
-	unsigned int port;
+	struct sockaddr_in rtp_addr;
 } rtp_info_t;
 
 /* This is a callback prototype function, called pass
@@ -131,7 +130,7 @@
 
 /* This is a callback prototype function, called upon
    an incoming call happens. */
-typedef call_options_t *(*setup_incoming_cb)(call_details_t);
+typedef call_options_t *(*setup_incoming_cb)(call_details_t *);
 extern setup_incoming_cb on_incoming_call;
 
 /* This is a callback prototype function, called upon
@@ -151,7 +150,7 @@
 
 /* This is a callback prototype function, called when
    OnConnectionCleared callback is invoked */
-typedef void (*clear_con_cb)(call_details_t);
+typedef void (*clear_con_cb)(unsigned, const char *);
 extern clear_con_cb on_connection_cleared;
 
 /* This is a callback prototype function, called when
@@ -168,6 +167,9 @@
 typedef void (*hangup_cb)(unsigned, const char *, int);
 extern hangup_cb on_hangup;
 
+typedef void (*setcapabilities_cb)(unsigned, const char *);
+extern setcapabilities_cb on_setcapabilities;
+
 /* debug flag */
 extern int h323debug;
 
@@ -201,8 +203,9 @@
  				    answer_call_cb,
 				    progress_cb,
 				    rfc2833_cb,
-				    hangup_cb);
-	int h323_set_capability(int, int);
+				    hangup_cb,
+				    setcapabilities_cb);
+	int h323_set_capability(const char *, int, int);
 	int h323_set_alias(struct oh323_alias *);
 	int h323_set_gk(int, char *, char *);
 	void h323_set_id(char *);
