Index: channels/chan_sip.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v
retrieving revision 1.637
diff -u -r1.637 chan_sip.c
--- channels/chan_sip.c	21 Jan 2005 07:06:24 -0000	1.637
+++ channels/chan_sip.c	24 Jan 2005 22:35:51 -0000
@@ -380,6 +380,7 @@
 	struct sip_request initreq;		/* Initial request */
 	
 	int maxtime;				/* Max time for first response */
+	int maxforwards;			/* keep the max-forwards info */
 	int initid;				/* Auto-congest ID if appropriate */
 	int autokillid;				/* Auto-kill ID */
 	time_t lastrtprx;			/* Last RTP received */
@@ -3137,6 +3138,11 @@
 	} else {
 		add_header(resp, "Contact", p->our_contact);
 	}
+	if (p->maxforwards) {
+		char tmp[256];
+		snprintf(tmp, sizeof(tmp), "%d", p->maxforwards);
+		add_header(resp, "Max-Forwards", tmp);
+	}
 	return 0;
 }
 
@@ -9394,6 +9400,15 @@
 "Skips to priority+101 if header does not exist\n"
 "Otherwise returns 0\n";
 
+static char *synopsis_sipredirect = "Sends a SIP 302 message to caller with custom content";
+static char *descrip_sipredirect = 
+"SIPRedirect(extension[@host[:port]])\n"
+"   extension := string which contains new extension (mandatory)\n"
+"   host := hostname or IP address of SIP destination.  If left blank,\n"
+"this host's IP address will be used.\n"
+"   port := integer.  If left unset, no port will be specified.\n";
+static char *app_sipredirect = "SIPRedirect";
+
 
 /*--- sip_dtmfmode: change the DTMFmode for a SIP call (application) ---*/
 static int sip_dtmfmode(struct ast_channel *chan, void *data)
@@ -9531,6 +9546,129 @@
 	return 0;
 }
 
+#define DEFAULT_MAX_FORWARDS	70
+#define SIPREDIRECT_DEBUG
+#undef SIPREDIRECT_DEBUG
+
+/* this is SIPRedirect application 		*/
+/* coded by Martin Pycko (m78pl@yahoo.com) 	*/
+/*          ************			*/
+/* use it to redirect SIP calls to diffrent SIP	*/
+/* servers before the call gets answered	*/
+
+static int sip_sipredirect(struct ast_channel *chan, void *data)
+{
+	struct sip_pvt *p = NULL;
+	char *cdata;
+	char *extension, *host, *port;
+	int host_allocated = 0;
+	int port_allocated = 0;
+	char tmp[80];
+	int res = 0;
+	
+	ast_mutex_lock(&chan->lock);
+	if (chan->type != channeltype) {
+		ast_log(LOG_WARNING, "%s: Call this application only on SIP incoming calls\n", app_sipredirect);
+		ast_mutex_unlock(&chan->lock);
+		return 0;
+	}
+	if (chan->_state != AST_STATE_RING) {
+		ast_log(LOG_WARNING, "%s: This app needs the call to be unanswered\n", app_sipredirect);
+		ast_mutex_unlock(&chan->lock);
+		return 0;
+	}
+	if (!data || !strlen((char *)data)) {
+		ast_log(LOG_WARNING, "%s: This application requires these arguments: SIPRedirect(extension[@host[:port]])\n", app_sipredirect);
+		ast_mutex_unlock(&chan->lock);
+		return 0;
+	}
+	cdata = strdup((char *)data);
+	if (!cdata) {
+		ast_log(LOG_ERROR, "%s: Problem allocating the memory\n", app_sipredirect);
+		ast_mutex_unlock(&chan->lock);
+		return 0;
+	}
+	extension = strsep(&cdata, "@");
+	host = strsep(&cdata, ":");
+	port = strsep(&cdata, ":");
+	if (!extension) {
+		ast_log(LOG_ERROR, "%s: Missing mandatory argument: extension\n", app_sipredirect);
+		ast_mutex_unlock(&chan->lock);
+		return 0;
+	}
+#ifdef SIPREDIRECT_DEBUG
+	ast_verbose("%s: extension: %s, host: %s, port: %s\n", app_sipredirect, extension, host ? host : "null", port ? port : "null");
+#endif
+	p = chan->pvt->pvt;
+	if (p) {
+		ast_mutex_lock(&p->lock);
+		/* we'll issue the redirect message here */
+		if (!host) {
+			char *localtmp;
+			strncpy(tmp, get_header(&p->initreq, "To"), sizeof(tmp) - 1);
+			if (!strlen(tmp)) {
+				ast_log(LOG_ERROR, "%s: Cannot retrieve the 'To' header from the original SIP request!\n", app_sipredirect);
+				ast_mutex_unlock(&p->lock);
+				ast_mutex_unlock(&chan->lock);
+				return 0;
+			}
+			if ((localtmp = strstr(tmp, "sip:")) && (localtmp = strchr(localtmp, '@'))) {
+				char lhost[80], lport[80];
+				memset(lhost, 0, sizeof(lhost));
+				memset(lport, 0, sizeof(lport));
+				localtmp++;
+				sscanf(localtmp, "%[^<>:; ]:%[^<>:; ]", lhost, lport);
+				if (!strlen(lhost)) {
+					ast_log(LOG_ERROR, "%s: Can't find the host address\n", app_sipredirect);
+					ast_mutex_unlock(&p->lock);
+					ast_mutex_unlock(&chan->lock);
+					return 0;
+				}
+				host = (char *)strdup(lhost);
+				host_allocated = 1;
+				if (strlen(lport)) {
+					port = (char *)strdup(lport);
+					port_allocated = 1;
+				}
+				if ((host_allocated && !host) || (port_allocated && !port)) {
+					ast_log(LOG_ERROR, "%s: Problem allocating the memory\n", app_sipredirect);
+					ast_mutex_unlock(&p->lock);
+					ast_mutex_unlock(&chan->lock);
+					return 0;
+				}
+			}
+		}
+
+		/* make sure the forwarding won't be forever */
+		strncpy(tmp, get_header(&p->initreq, "Max-Forwards"), sizeof(tmp) - 1);
+		if (strlen(tmp) && atoi(tmp)) {
+			/* we found Max-Forwards in the original SIP request */
+			p->maxforwards = atoi(tmp) - 1;
+		} else {
+			/* just send our 302 Moved Temporarily */
+			p->maxforwards = DEFAULT_MAX_FORWARDS - 1;
+		}
+		if (p->maxforwards > -1) {
+			snprintf(p->our_contact, sizeof(p->our_contact), "redirect <sip:%s@%s%s%s>", extension, host, port ? ":" : "", port ? port : "");
+			transmit_response_reliable(p, "302 Moved Temporarily", &p->initreq, 1);
+		} else {
+			transmit_response(p, "483 Too Many Hops", &p->initreq);
+		}
+		/* this is all that we want to send to that SIP device */
+		ast_set_flag(p, SIP_ALREADYGONE);
+		/* hangup if you happen to go this way */
+		res = -1;
+		ast_mutex_unlock(&p->lock);
+	}
+	ast_mutex_unlock(&chan->lock);
+	/* free the memory if applicable */
+	if (host_allocated && host)
+		free(host);
+	if (port_allocated && port)
+		free(port);
+	return res;
+}
+
 /*--- sip_get_codec: Return peers codec ---*/
 static int sip_get_codec(struct ast_channel *chan)
 {
@@ -9667,6 +9805,7 @@
 		ast_register_application(app_dtmfmode, sip_dtmfmode, synopsis_dtmfmode, descrip_dtmfmode);
 		ast_register_application(app_sipaddheader, sip_addheader, synopsis_sipaddheader, descrip_sipaddheader);
 		ast_register_application(app_sipgetheader, sip_getheader, synopsis_sipgetheader, descrip_sipgetheader);
+		ast_register_application(app_sipredirect, sip_sipredirect, synopsis_sipredirect, descrip_sipredirect);
 		sip_poke_all_peers();
 		sip_send_all_registers();
 		
@@ -9684,6 +9823,7 @@
 	ast_unregister_application(app_dtmfmode);
 	ast_unregister_application(app_sipaddheader);
 	ast_unregister_application(app_sipgetheader);
+	ast_unregister_application(app_sipredirect);
 	ast_cli_unregister(&cli_notify);
 	ast_cli_unregister(&cli_show_users);
 	ast_cli_unregister(&cli_show_objects);
