Index: channels/chan_sip.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v
retrieving revision 1.797
diff -u -u -r1.797 chan_sip.c
--- channels/chan_sip.c	28 Jul 2005 18:24:04 -0000	1.797
+++ channels/chan_sip.c	29 Jul 2005 21:26:49 -0000
@@ -485,7 +485,7 @@
 #define SIP_PAGE2_RTNOUPDATE 		(1 << 1)
 #define SIP_PAGE2_RTAUTOCLEAR 		(1 << 2)
 #define SIP_PAGE2_RTIGNOREREGEXPIRE       (1 << 3)
-
+#define SIP_PAGE2_FROMREALTIME		(1 << 4)
 static int global_rtautoclear = 120;
 
 /* sip_pvt: PVT structures are used for each SIP conversation, ie. a call  */
@@ -515,6 +515,7 @@
 	int sessionid;				/* SDP Session ID */
 	int sessionversion;			/* SDP Session Version */
 	struct sockaddr_in sa;			/* Our peer */
+	struct sockaddr_in defaddr;			/* Our peer */
 	struct sockaddr_in redirip;		/* Where our RTP should be going if not to us */
 	struct sockaddr_in vredirip;		/* Where our Video RTP should be going if not to us */
 	int redircodecs;			/* Redirect codecs */
@@ -820,6 +821,7 @@
 static void append_date(struct sip_request *req);	/* Append date to SIP packet */
 static int determine_firstline_parts(struct sip_request *req);
 
+
 /* Definition of this channel for channel registration */
 static const struct ast_channel_tech sip_tech = {
 	.type = channeltype,
@@ -934,12 +936,21 @@
 	int res;
 	char iabuf[INET_ADDRSTRLEN];
 
-	if (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)
+	if (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE) {
+		if (!ntohs(p->recv.sin_port)) {
+			p->recv.sin_port = p->defaddr.sin_port;
+		}
 		res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->recv, sizeof(struct sockaddr_in));
-	else
+	} else {
+		if (!ntohs(p->sa.sin_port)) {
+			p->sa.sin_port = p->defaddr.sin_port;
+		}
 		res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->sa, sizeof(struct sockaddr_in));
+	}
+
 	if (res != len) {
-		ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s returned %d: %s\n", data, len, ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), res, strerror(errno));
+		
+		ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s:%d returned %d: %s\n", data, len, ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), res, ntohs(p->sa.sin_port), strerror(errno));
 	}
 	return res;
 }
@@ -1328,23 +1339,6 @@
 	return res;
 }
 
-/*--- url_decode: Decode SIP URL (overwrite the string)  ---*/
-static void url_decode(char *s) 
-{
-	char *o;
-	unsigned int tmp;
-
-	for (o = s; *s; s++, o++) {
-		if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) {
-			/* have '%', two chars and correct parsing */
-			*o = tmp;
-			s += 2;	/* Will be incremented once more when we break out */
-		} else /* all other cases, just copy */
-			*o = *s;
-	}
-	*o = '\0';
-}
-
 /*--- get_in_brackets: Pick out text in brackets from character string ---*/
 /* returns pointer to terminated stripped string. modifies input string. */
 static char *get_in_brackets(char *tmp)
@@ -1489,6 +1483,7 @@
 	struct ast_variable *var;
 	struct ast_variable *tmp;
 	char *newpeername = (char *) peername;
+	char *fullcontact = NULL;
 	char iabuf[80] = "";
 
 	/* First check on peer name */
@@ -1513,6 +1508,10 @@
 		} else if (!newpeername && !strcasecmp(tmp->name, "name")) {
 			newpeername = tmp->value;
 		}
+		if (!strcasecmp(tmp->name, "fullcontact")) {
+			fullcontact = ast_strdupa(tmp->value);
+			url_decode(fullcontact);
+		}
 		tmp = tmp->next;
 	}
 	
@@ -1521,17 +1520,23 @@
 		ast_variables_destroy(var);
 		return (struct sip_peer *) NULL;
 	}
-		
 	/* Peer found in realtime, now build it in memory */
-	peer = build_peer(newpeername, var, !ast_test_flag((&global_flags_page2), SIP_PAGE2_RTCACHEFRIENDS));
-
-	if (!peer) {
+	
+	if ((peer = build_peer(newpeername, var, !ast_test_flag((&global_flags_page2), SIP_PAGE2_RTCACHEFRIENDS)))) {
+		if (fullcontact) {
+			ast_copy_string(peer->fullcontact, fullcontact, sizeof(peer->fullcontact));
+		}
+	} else {
 		ast_variables_destroy(var);
 		return (struct sip_peer *) NULL;
 	}
+
+	ast_set_flag((&peer->flags_page2), SIP_PAGE2_FROMREALTIME);
+
 	if (ast_test_flag((&global_flags_page2), SIP_PAGE2_RTCACHEFRIENDS)) {
 		/* Cache peer */
 		ast_copy_flags((&peer->flags_page2),(&global_flags_page2), SIP_PAGE2_RTAUTOCLEAR|SIP_PAGE2_RTCACHEFRIENDS);
+
 		if (ast_test_flag((&global_flags_page2), SIP_PAGE2_RTAUTOCLEAR)) {
 			if (peer->expire > -1) {
 				ast_sched_del(sched, peer->expire);
@@ -1656,6 +1661,10 @@
 {
 	char *callhost;
 
+
+	r->defaddr.sin_addr = peer->defaddr.sin_addr;
+	r->defaddr.sin_port = peer->defaddr.sin_port;
+
 	if ((peer->addr.sin_addr.s_addr || peer->defaddr.sin_addr.s_addr) &&
 	    (!peer->maxms || ((peer->lastms >= 0)  && (peer->lastms <= peer->maxms)))) {
 		if (peer->addr.sin_addr.s_addr) {
@@ -5029,7 +5038,10 @@
 	struct sip_peer *peer = data;
 
 	memset(&peer->addr, 0, sizeof(peer->addr));
-	ast_db_del("SIP/Registry", peer->name);
+
+	if (!ast_test_flag(&(peer->flags_page2), SIP_PAGE2_FROMREALTIME)) {
+		ast_db_del("SIP/Registry", peer->name);
+	}
 	manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", peer->name);
 	register_peer_exten(peer, 0);
 	peer->expire = -1;
@@ -5062,8 +5074,11 @@
 	int port;
 	char *scan, *addr, *port_str, *expiry_str, *username, *contact;
 
-	if (ast_db_get("SIP/Registry", peer->name, data, sizeof(data)))
+	if (!ast_test_flag(&(peer->flags_page2), SIP_PAGE2_FROMREALTIME)) {
+		ast_copy_string(data, peer->fullcontact, sizeof(data));
+	} else if (ast_db_get("SIP/Registry", peer->name, data, sizeof(data))) {
 		return;
+	}
 
 	scan = data;
 	addr = strsep(&scan, ":");
@@ -5216,7 +5231,9 @@
 		if (p->expire > -1)
 			ast_sched_del(sched, p->expire);
 		p->expire = -1;
-		ast_db_del("SIP/Registry", p->name);
+		if (!ast_test_flag(&(p->flags_page2), SIP_PAGE2_FROMREALTIME)) {
+			ast_db_del("SIP/Registry", p->name);
+		}
 		register_peer_exten(p, 0);
 		p->fullcontact[0] = '\0';
 		p->useragent[0] = '\0';
@@ -5229,6 +5246,11 @@
 		return 0;
 	}
 	ast_copy_string(p->fullcontact, c, sizeof(p->fullcontact));
+	if (!ast_test_flag((&global_flags_page2), SIP_PAGE2_RTNOUPDATE)) {
+		char buf[128];
+		url_encode(c, buf, sizeof(buf));
+		ast_update_realtime("sippeers", "name", p->name, "fullcontact", buf, NULL);
+	}
 	/* For the 200 OK, we should use the received contact */
 	snprintf(pvt->our_contact, sizeof(pvt->our_contact) - 1, "<%s>", c);
 	/* Make sure it's a SIP URL */
@@ -5289,8 +5311,13 @@
 		p->expire = -1;
 	pvt->expiry = expiry;
 	snprintf(data, sizeof(data), "%s:%d:%d:%s:%s", ast_inet_ntoa(iabuf, sizeof(iabuf), p->addr.sin_addr), ntohs(p->addr.sin_port), expiry, p->username, p->fullcontact);
-	if (!(ast_test_flag(p, SIP_REALTIME) && ast_test_flag((&p->flags_page2), SIP_PAGE2_RTCACHEFRIENDS)))
+	if (!ast_test_flag((&p->flags_page2), SIP_PAGE2_FROMREALTIME)) {
 		ast_db_put("SIP/Registry", p->name, data);
+	} else {
+		char buf[128];
+		url_encode(data, buf, sizeof(buf));
+		ast_update_realtime("sippeers", "name", p->name, "fullcontact", buf, NULL);
+	}
 	manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Registered\r\n", p->name);
 	if (inaddrcmp(&p->addr, &oldsin)) {
 		sip_poke_peer(p);
@@ -10628,12 +10655,16 @@
 			continue;
 		}
 
-		if (realtime && !strcasecmp(v->name, "regseconds")) {
+		if (!strcasecmp(v->name, "regseconds")) {
 			if (sscanf(v->value, "%li", &regseconds) != 1)
 				regseconds = 0;
-		} else if (realtime && !strcasecmp(v->name, "ipaddr") && !ast_strlen_zero(v->value) ) {
+		} else if (!strcasecmp(v->name, "ipaddr") && !ast_strlen_zero(v->value) ) {
 			inet_aton(v->value, &(peer->addr.sin_addr));
-		} else if (realtime && !strcasecmp(v->name, "name"))
+			if (ast_test_flag((&global_flags_page2), SIP_PAGE2_RTIGNOREREGEXPIRE)) {
+				inet_aton(v->value, &(peer->defaddr.sin_addr));
+				found++;
+			}
+		} else if (!strcasecmp(v->name, "name"))
 			ast_copy_string(peer->name, v->value, sizeof(peer->name));
 		else if (!strcasecmp(v->name, "secret")) 
 			ast_copy_string(peer->secret, v->value, sizeof(peer->secret));
@@ -10783,18 +10814,20 @@
 		 */
 		v=v->next;
 	}
-	if (realtime && !ast_test_flag((&global_flags_page2), SIP_PAGE2_RTIGNOREREGEXPIRE) && ast_test_flag(peer, SIP_DYNAMIC)) {
+
+	if (!ast_test_flag((&global_flags_page2), SIP_PAGE2_RTIGNOREREGEXPIRE) && ast_test_flag(peer, SIP_DYNAMIC)) {
 		time_t nowtime;
 
 		time(&nowtime);
 		if ((nowtime - regseconds) > 0) {
 			memset(&peer->addr, 0, sizeof(peer->addr));
+			ast_update_realtime("sippeers", "name", peer->name, "fullcontact", "", NULL);
 			if (option_debug)
 				ast_log(LOG_DEBUG, "Bah, we're expired (%ld/%ld/%ld)!\n", nowtime - regseconds, regseconds, nowtime);
 		}
 	}
 	ast_copy_flags(peer, &peerflags, mask.flags);
-	if (!found && ast_test_flag(peer, SIP_DYNAMIC) && !ast_test_flag(peer, SIP_REALTIME))
+	if (!found && ast_test_flag(peer, SIP_DYNAMIC) && !ast_test_flag(peer, SIP_REALTIME)) 
 		reg_source_db(peer);
 	ASTOBJ_UNMARK(peer);
 	ast_free_ha(oldha);
@@ -10879,6 +10912,7 @@
 	/* Read the [general] config section of sip.conf (or from realtime config) */
 	v = ast_variable_browse(cfg, "general");
 	while(v) {
+
 		if (handle_common_options(&global_flags, &dummy, v)) {
 			v = v->next;
 			continue;
