[asterisk-dev] NCS PacketCable Patch

Jason Burton jburton at picriverisp.net
Fri Oct 20 10:26:36 MST 2006


Skipped content of type multipart/alternative-------------- next part --------------
--- chan_mgcp.c.orig	2005-06-21 06:54:23.000000000 +0200
+++ chan_mgcp.c	2005-06-24 18:03:40.000000000 +0200
@@ -171,6 +171,8 @@
 static int dtmfmode = 0;
 static int nat = 0;
 
+static int ncs = 0;
+
 /* Not used. Dosn't hurt for us to always send cid  */
 /* to the mgcp box. */
 /*static int use_callerid = 1;*/
@@ -195,7 +197,7 @@
 /* to the mgcp box. */
 /*static int callwaitingcallerid = 0;*/
 
-/*static int hidecallerid = 0;*/
+static int hidecallerid = 0;
 
 static int callreturn = 0;
 
@@ -392,6 +394,7 @@
 	int hidecallerid;
 	int dtmfmode;
 	int amaflags;
+	int ncs;
 	int type;
 	int slowsequence;			/* MS: Sequence the endpoint as a whole */
 	int group;
@@ -446,7 +449,7 @@
 	int delme;                 /* SC: needed for reload */
 	struct mgcp_response *responses;
 	struct mgcp_gateway *next;
-} *gateways;
+} *gateways = NULL, *gatetemplate = NULL;
 
 AST_MUTEX_DEFINE_STATIC(mgcp_reload_lock);
 static int mgcp_reloading = 0;
@@ -965,6 +968,7 @@
 {
 	struct mgcp_subchannel *sub = ast->tech_pvt;
 	struct mgcp_endpoint *p = sub->parent;
+	int unhidecallerid = 0;
 
 	if (option_debug) {
 		ast_log(LOG_DEBUG, "mgcp_hangup(%s)\n", ast->name);
@@ -1043,7 +1047,11 @@
 	/* SC: Decrement use count */
 
 	if ((p->hookstate == MGCP_ONHOOK) && (!sub->next->rtp)) {
+
+		if (p->hidecallerid) unhidecallerid = 1;
+		    
 		p->hidecallerid = 0;
+
 		if (p->hascallwaiting && !p->callwaiting) {
 			if (option_verbose > 2)
 				ast_verbose(VERBOSE_PREFIX_3 "Enabling call waiting on %s\n", ast->name);
@@ -1062,6 +1070,8 @@
 			}
 			transmit_notify_request(sub, "L/vmwi(-)");
 		}
+
+		if (unhidecallerid) p->hidecallerid = 1;
 	}
 	ast_mutex_unlock(&sub->lock);
 	return 0;
@@ -1344,14 +1354,14 @@
 #ifdef DLINK_BUGGY_FIRMWARE	
 		transmit_notify_request(sub, "rt");
 #else
-		transmit_notify_request(sub, "G/rt");
+		transmit_notify_request(sub, sub->parent->ncs ? "L/rt" : "G/rt");
 #endif		
 		break;
 	case AST_CONTROL_BUSY:
 		transmit_notify_request(sub, "L/bz");
 		break;
 	case AST_CONTROL_CONGESTION:
-		transmit_notify_request(sub, "G/cg");
+		transmit_notify_request(sub, sub->parent->ncs ? "L/cg" : "G/cg");
 		break;
 	case -1:
 		transmit_notify_request(sub, "");
@@ -1477,7 +1487,7 @@
 	return "";
 }
 
-static char *__get_header(struct mgcp_request *req, char *name, int *start)
+static char *__get_header(struct mgcp_request *req, char *name, int *start, char *def)
 {
 	int x;
 	int len = strlen(name);
@@ -1493,13 +1503,19 @@
 		}
 	}
 	/* Don't return NULL, so get_header is always a valid pointer */
-	return "";
+	return def;
 }
 
 static char *get_header(struct mgcp_request *req, char *name)
 {
 	int start = 0;
-	return __get_header(req, name, &start);
+	return __get_header(req, name, &start, "");
+}
+
+static char *get_header_default(struct mgcp_request *req, char *name, char *def)
+{
+	int start = 0;
+	return __get_header(req, name, &start, def);
 }
 
 /* SC: get comma separated value */
@@ -1524,7 +1540,50 @@
 	return s;
 }
 
-static struct mgcp_subchannel *find_subchannel_and_lock(char *name, int msgid, struct sockaddr_in *sin)
+static struct mgcp_gateway *clone_gateway(struct mgcp_gateway *gw, char *at)
+{
+    struct mgcp_gateway *gw_new;
+    struct mgcp_endpoint *e, *e_new;
+    struct mgcp_subchannel *sub, *sub_new;
+
+    if ((gw_new = malloc(sizeof(struct mgcp_gateway)))) {
+	memcpy(gw_new, gw, sizeof (struct mgcp_gateway));
+        strncpy(gw_new->name, at, 79);
+        gw_new->endpoints = NULL;
+	gw_new->dynamic = 1;
+	for (e = gw->endpoints; e; e = e->next) {
+	    if ((e_new = malloc(sizeof(struct mgcp_endpoint)))) {
+		if (mgcpdebug)
+		    ast_verbose("Cloning endpoint %s@%s\n", e_new->name, gw_new->name);
+		    e_new->parent = gw_new;
+		    e_new->sub = NULL;
+		    e_new->next = gw_new->endpoints;
+		    gw_new->endpoints = e_new;
+		    for (sub = e->sub; sub; sub = sub->next) {
+			if ((sub_new = malloc(sizeof(struct mgcp_subchannel)))) {
+			    memcpy(sub_new, sub, sizeof(struct mgcp_subchannel));
+			    if (mgcpdebug)
+				ast_verbose("Cloning subchannel %d of endpoint %s@%s\n", sub_new->id, e_new->name, gw_new->name);
+			    sub_new->parent = e_new;
+			    sub_new->next = e_new->sub;
+			    e_new->sub = sub_new;
+			    }
+                            //fix circular reference
+			    if (sub->next == e->sub) {
+				while(sub_new->next){
+				    sub_new = sub_new->next;
+				}
+				sub_new->next = e_new->sub;
+				break;
+                           }
+                       }
+                   }
+           }
+   }
+   return gw_new;
+}
+
+static struct mgcp_subchannel *find_subchannel_and_lock(char *name, int msgid, struct sockaddr_in *sin, struct mgcp_gateway *gt)
 {
 	struct mgcp_endpoint *p = NULL;
 	struct mgcp_subchannel *sub = NULL;
@@ -1624,7 +1683,7 @@
 				p = p->next;
 			}
 			if (sub && found) {
-				ast_mutex_lock(&sub->lock);
+				 ast_mutex_lock(&sub->lock);
 				break;
 			}
 		}
@@ -1633,10 +1692,20 @@
 	ast_mutex_unlock(&gatelock);
 	if (!sub) {
 		if (name) {
-			if (g)
-				ast_log(LOG_NOTICE, "Endpoint '%s' not found on gateway '%s'\n", tmp, at);
-			else
-				ast_log(LOG_NOTICE, "Gateway '%s' (and thus its endpoint '%s') does not exist\n", at, tmp);
+			if (g) {
+			    ast_log(LOG_NOTICE, "Endpoint '%s' not found on gateway '%s'\n", tmp, at);
+			 } else {
+				if (gt && (g = clone_gateway(gt, at))) {
+				    ast_mutex_lock(&gatelock);
+				    g->next = gateways;
+				    gateways = g;
+				    ast_mutex_unlock(&gatelock);
+				    ast_log(LOG_NOTICE, "Gateway '%s' dynamically allocated\n", at);
+				    return find_subchannel_and_lock(name, msgid, sin, NULL);
+				    } else {
+					ast_log(LOG_NOTICE, "Gateway '%s' (and thus its endpoint '%s') does not exist\n", at, tmp);
+				    }
+			    }
 		} 
 	}
 	return sub;
@@ -1901,9 +1970,11 @@
 	req->header[req->headers] = req->data + req->len;
 	/* SC: check if we need brackets around the gw name */
 	if (p->parent->isnamedottedip)
-		snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@[%s] MGCP 1.0\r\n", verb, oseq, p->name, p->parent->name);
+//		snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@[%s] MGCP 1.0\r\n", verb, oseq, p->name, p->parent->name);
+		snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@[%s] MGCP 1.0%s\r\n", verb, oseq, p->name, p->parent->name, p->ncs ? " NCS 1.0" : "");
 	else
-		snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@%s MGCP 1.0\r\n", verb, oseq, p->name, p->parent->name);
+//		snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@%s MGCP 1.0\r\n", verb, oseq, p->name, p->parent->name);
+		snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@%s MGCP 1.0%s\r\n", verb, oseq, p->name, p->parent->name, p->ncs ? " NCS 1.0" : "");
 	req->len += strlen(req->header[req->headers]);
 	if (req->headers < MGCP_MAX_HEADERS)
 		req->headers++;
@@ -2065,7 +2136,7 @@
 		ast_rtp_get_peer(rtp, &sub->tmpdest);
 		return 0;
 	}
-	snprintf(local, sizeof(local), "p:20");
+	snprintf(local, sizeof(local), "p:20, s:off, e:on");
 	for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
 		if (p->capability & x) {
 			snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x));
@@ -2096,7 +2167,7 @@
 	int x;
 	struct mgcp_endpoint *p = sub->parent;
 
-	snprintf(local, sizeof(local), "p:20");
+	snprintf(local, sizeof(local), "p:20, s:off, e:on");
 	for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
 		if (p->capability & x) {
 			snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x));
@@ -2139,7 +2210,7 @@
 		add_header(&resp, "R", "L/hd(N)");
 		break;
 	case MGCP_OFFHOOK:
-		add_header(&resp, "R", (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N),L/hf(N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)");
+		add_header(&resp, "R", (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N),L/hf(N)" : (p->ncs ? "L/hu(N), L/hf(N), L/[0-9#*](N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)"));
 		break;
 	}
 	if (!ast_strlen_zero(tone)) {
@@ -2182,7 +2253,7 @@
 		add_header(&resp, "R", "L/hd(N)");
 		break;
 	case MGCP_OFFHOOK:
-		add_header(&resp, "R",  (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N),L/hf(N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)");
+		add_header(&resp, "R", (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N),L/hf(N)" : (p->ncs ? "L/hu(N), L/hf(N), L/[0-9#*](N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)"));
 		break;
 	}
 	if (!ast_strlen_zero(tone2)) {
@@ -2223,7 +2294,7 @@
 		add_header(&resp, "R", "L/hd(N)");
 		break;
 	case MGCP_OFFHOOK:
-		add_header(&resp, "R",  (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N), L/hf(N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)");
+		add_header(&resp, "R", (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N),L/hf(N)" : (p->ncs ? "L/hu(N), L/hf(N), L/[0-9#*](N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)"));
 		break;
 	}
 	/* SC: fill in new fields */
@@ -2401,6 +2472,10 @@
 			break;
 		}
 		if (sub) {
+			if (!sub->cxident[0] && (req->cmd == MGCP_CMD_CRCX)) {
+			    ast_log(LOG_NOTICE, "DLCX for all connections on %s due to error %d\n", gw->name, result);
+			    transmit_connection_del(sub);
+			}
 			if (sub->owner) {
 				ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n", 
 					result, p->name, p->parent->name, sub ? sub->id:-1);
@@ -2424,6 +2499,14 @@
 	}
 
 	if (resp) {
+               /* responseAck: */
+		if ((req->cmd == MGCP_CMD_CRCX || req->cmd == MGCP_CMD_MDCX)) {
+            	    if ((c = get_header_default(resp, "K", NULL))) {
+			if (c == '\0') {
+			    transmit_response(sub, "000", resp, "OK");
+			}
+		    }
+		}
 		if (req->cmd == MGCP_CMD_CRCX) {
 			if ((c = get_header(resp, "I"))) {
 				if (!ast_strlen_zero(c) && sub) {
@@ -2616,6 +2699,15 @@
 							if (chan->cid.cid_name)
 								free(chan->cid.cid_name);
 							chan->cid.cid_name = strdup(p->cid_name);
+						} else {
+							/* SC: free existing chan->callerid */
+							if (chan->cid.cid_num)
+								free(chan->cid.cid_num);
+							chan->cid.cid_num = NULL;
+							/* SC: free existing chan->callerid */
+							if (chan->cid.cid_name)
+								free(chan->cid.cid_name);
+							chan->cid.cid_name = "private";
 						}
 						if (chan->cid.cid_ani)
 							free(chan->cid.cid_ani);
@@ -2632,7 +2724,7 @@
 						ast_log(LOG_WARNING, "PBX exited non-zero\n");
 						/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);*/
 						/*transmit_notify_request(p, "nbz", 1);*/
-						transmit_notify_request(sub, "G/cg");
+						transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
 					}
 					return NULL;
 				}
@@ -2644,7 +2736,7 @@
 		} else if (res == 0) {
 			ast_log(LOG_DEBUG, "not enough digits (and no ambiguous match)...\n");
 			/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);*/
-			transmit_notify_request(sub, "G/cg");
+			transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
 			/*zt_wait_event(p->subs[index].zfd);*/
 			ast_hangup(chan);
 			return NULL;
@@ -2667,7 +2759,7 @@
 			if (ast_pickup_call(chan)) {
 				ast_log(LOG_WARNING, "No call pickup possible...\n");
 				/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);*/
-				transmit_notify_request(sub, "G/cg");
+				transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
 			}
 			ast_hangup(chan);
 			return NULL;
@@ -2922,12 +3014,12 @@
 #ifdef DLINK_BUGGY_FIRMWARE	
 				transmit_notify_request(sub, "rt");
 #else
-				transmit_notify_request(sub, "G/rt");
+				transmit_notify_request(sub, p->ncs ? "L/rt" : "G/rt");
 #endif		
 				c = mgcp_new(sub, AST_STATE_RING);
 				if (!c) {
 					ast_log(LOG_WARNING, "Unable to start PBX on channel %s@%s\n", p->name, p->parent->name);
-					transmit_notify_request(sub, "G/cg");
+					transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
 					ast_hangup(c);
 				}
 			} else {
@@ -2977,6 +3069,7 @@
 	struct mgcp_gateway *g = NULL;
 	char iabuf[INET_ADDRSTRLEN];
 	int res;
+	int unhidecallerid = 0;
 
 	if (mgcpdebug) {
 		ast_verbose("Handling request '%s' on %s@%s\n", req->verb, p->name, p->parent->name);
@@ -3192,6 +3285,9 @@
 				}
 			}
 			if ((p->hookstate == MGCP_ONHOOK) && (!sub->rtp) && (!sub->next->rtp)) {
+			
+				if (p->hidecallerid) unhidecallerid = 1;
+			
 				p->hidecallerid = 0;
 				if (p->hascallwaiting && !p->callwaiting) {
 					if (option_verbose > 2)
@@ -3209,6 +3305,8 @@
 					}
 					transmit_notify_request(sub, "L/vmwi(-)");
 				}
+				
+				 if (unhidecallerid) p->hidecallerid = 1;
 			}
 		} else if ((strlen(ev) == 1) && 
 				(((ev[0] >= '0') && (ev[0] <= '9')) ||
@@ -3309,8 +3407,12 @@
 	}
 
 	if (sscanf(req.verb, "%d", &result) && sscanf(req.identifier, "%d", &ident)) {
+	    if (result < 200) {
+		ast_log(LOG_DEBUG, "Ignoring provisional response on transaction %d\n", ident);
+		return 1;
+	    }
 		/* Try to find who this message is for, if it's important */
-		sub = find_subchannel_and_lock(NULL, ident, &sin);
+		sub = find_subchannel_and_lock(NULL, ident, &sin, gatetemplate);
 		if (sub) {
 			struct mgcp_gateway *gw = sub->parent->parent;
 			struct mgcp_message *cur, *prev;
@@ -3352,7 +3454,7 @@
 			return 1;
 		}
 		/* Process request, with iflock held */
-		sub = find_subchannel_and_lock(req.endpoint, 0, &sin);
+		sub = find_subchannel_and_lock(req.endpoint, 0, &sin, gatetemplate);
 		if (sub) {
 			/* look first to find a matching response in the queue */
 			if (!find_and_retrans(sub, &req))
@@ -3504,7 +3606,7 @@
 		ast_log(LOG_NOTICE, "MGCP Channels require an endpoint\n");
 		return NULL;
 	}
-	sub = find_subchannel_and_lock(tmp, 0, NULL);
+	sub = find_subchannel_and_lock(tmp, 0, NULL, gatetemplate);
 	if (!sub) {
 		ast_log(LOG_WARNING, "Unable to find MGCP endpoint '%s'\n", tmp);
 		*cause = AST_CAUSE_UNREGISTERED;
@@ -3630,6 +3732,8 @@
 					ast_log(LOG_WARNING, "'%s' is not a valid DTMF mode at line %d\n", v->value, v->lineno);
 			} else if (!strcasecmp(v->name, "nat")) {
 				nat = ast_true(v->value);
+			} else if (!strcasecmp(v->name, "ncs")) {
+				ncs = ast_true(v->value);
 			} else if (!strcasecmp(v->name, "callerid")) {
 				if (!strcasecmp(v->value, "asreceived")) {
 					cid_num[0] = '\0';
@@ -3658,6 +3762,8 @@
 				immediate = ast_true(v->value);
 			} else if (!strcasecmp(v->name, "cancallforward")) {
 				cancallforward = ast_true(v->value);
+			} else if (!strcasecmp(v->name, "hidecallerid")) {
+				hidecallerid = ast_true(v->value);
 			} else if (!strcasecmp(v->name, "singlepath")) {
 				singlepath = ast_true(v->value);
 			} else if (!strcasecmp(v->name, "canreinvite")) {
@@ -3712,6 +3818,7 @@
 					strncpy(e->cid_num, cid_num, sizeof(e->cid_num) - 1);
 					strncpy(e->cid_name, cid_name, sizeof(e->cid_name) - 1);
 					strncpy(e->language, language, sizeof(e->language) - 1);
+					strncpy(e->accountcode, accountcode, sizeof(e->accountcode) - 1);
 					strncpy(e->musicclass, musicclass, sizeof(e->musicclass) - 1);
 					strncpy(e->mailbox, mailbox, sizeof(e->mailbox) - 1);
 					snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08x", rand());
@@ -3719,6 +3826,7 @@
 					e->amaflags = amaflags;
 					e->capability = capability;
 					e->parent = gw;
+					e->hidecallerid = hidecallerid;
 					e->dtmfmode = dtmfmode;
 					if (!ep_reload && e->sub && e->sub->rtp)
 						e->dtmfmode |= MGCP_DTMF_INBAND;
@@ -3810,6 +3918,7 @@
 					strncpy(e->cid_num, cid_num, sizeof(e->cid_num) - 1);
 					strncpy(e->cid_name, cid_name, sizeof(e->cid_name) - 1);
 					strncpy(e->language, language, sizeof(e->language) - 1);
+					strncpy(e->accountcode, accountcode, sizeof(e->accountcode) - 1);
 					strncpy(e->musicclass, musicclass, sizeof(e->musicclass) - 1);
 					strncpy(e->mailbox, mailbox, sizeof(e->mailbox)-1);
 					if (!ast_strlen_zero(mailbox)) {
@@ -3823,6 +3932,7 @@
 					e->amaflags = amaflags;
 					e->capability = capability;
 					e->dtmfmode = dtmfmode;
+					e->ncs = ncs;
 					e->adsi = adsi;
 					if (!strcasecmp(v->name, "trunk"))
 						e->type = TYPE_TRUNK;
@@ -3834,6 +3944,7 @@
 					e->pickupgroup=cur_pickupgroup;
 					e->callreturn = callreturn;
 					e->cancallforward = cancallforward;
+					e->hidecallerid = hidecallerid;
 					e->canreinvite = canreinvite;
 					e->singlepath = singlepath;
 					e->callwaiting = callwaiting;
@@ -4167,20 +4278,30 @@
 	cat = ast_category_browse(cfg, NULL);
 	while(cat) {
 		if (strcasecmp(cat, "general")) {
+		    if (!(strcasecmp(cat, "template"))) {
+			ast_mutex_lock(&gatelock);
+			gatetemplate = build_gateway(cat, ast_variable_browse(cfg, cat));
+			if (gatetemplate) {
+			    if (option_verbose > 2) {
+				ast_verbose(VERBOSE_PREFIX_3 "Added template gateway\n");
+			    }
+			}
+		    ast_mutex_unlock(&gatelock);
+		    } else {
 			ast_mutex_lock(&gatelock);
 			g = build_gateway(cat, ast_variable_browse(cfg, cat));
 			if (g) {
-				if (option_verbose > 2) {
-					ast_verbose(VERBOSE_PREFIX_3 "Added gateway '%s'\n", g->name);
-				}
-				g->next = gateways;
-				gateways = g;
+			    if (option_verbose > 2) {
+				ast_verbose(VERBOSE_PREFIX_3 "Added gateway '%s'\n", g->name);
+			    }
+			    g->next = gateways;
+			    gateways = g;
 			}
 			ast_mutex_unlock(&gatelock);
-
-			/* FS: process queue and IO */
-			if (monitor_thread == pthread_self()) {
-				if (sched) ast_sched_runq(sched);
+		    }
+		/* FS: process queue and IO */
+		if (monitor_thread == pthread_self()) {
+			if (sched) ast_sched_runq(sched);
 				if (io) ast_io_wait(io, 10);
 			}
 		}


More information about the asterisk-dev mailing list