diff options
author | markster <markster@f38db490-d61c-443f-a65b-d21fe96a405b> | 2005-02-19 17:34:06 +0000 |
---|---|---|
committer | markster <markster@f38db490-d61c-443f-a65b-d21fe96a405b> | 2005-02-19 17:34:06 +0000 |
commit | b8375317121c5cd16ca4f3239fcaa4ee2e894cb1 (patch) | |
tree | 1a87d1f73644bbb9f57399fe2d4d8e8969c18f2d | |
parent | 56a6b23126220c47c1204dc74c57e402bef5c8ce (diff) |
Add sip redirect support (bug #3419i, with mods)
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@5055 f38db490-d61c-443f-a65b-d21fe96a405b
-rwxr-xr-x | apps/app_transfer.c | 13 | ||||
-rwxr-xr-x | channels/chan_sip.c | 93 |
2 files changed, 102 insertions, 4 deletions
diff --git a/apps/app_transfer.c b/apps/app_transfer.c index 212792c86..d46e34f25 100755 --- a/apps/app_transfer.c +++ b/apps/app_transfer.c @@ -29,7 +29,7 @@ static char *app = "Transfer"; static char *synopsis = "Transfer caller to remote extension"; static char *descrip = -" Transfer(exten): Requests the remote caller be transferred to\n" +" Transfer([Tech/]dest): Requests the remote caller be transferred\n" "a given extension. Returns -1 on hangup, or 0 on completion\n" "regardless of whether the transfer was successful. If the transfer\n" "was *not* supported or successful and there exists a priority n + 101,\n" @@ -42,14 +42,21 @@ LOCAL_USER_DECL; static int transfer_exec(struct ast_channel *chan, void *data) { int res=0; + int len; struct localuser *u; + char *slash; if (!data || !strlen(data)) { - ast_log(LOG_WARNING, "Transfer requires an argument (destination)\n"); + ast_log(LOG_WARNING, "Transfer requires an argument ([Tech/]destination)\n"); res = 1; } + if ((slash = strchr((char *)data, '/')) && (len = (slash - (char *)data))) { + /* Allow execution only if the Tech/destination agrees with the type of the channel */ + if (strncasecmp(chan->type, (char *)data, len)) + return 0; + } LOCAL_USER_ADD(u); if (!res) { - res = ast_transfer(chan, data); + res = ast_transfer(chan, data + strlen(chan->type) + 1); } if (!res) { /* Look for a "busy" place */ diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 9a8ad83c9..5e8827fef 100755 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -389,6 +389,7 @@ static struct sip_pvt { 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 */ @@ -598,6 +599,7 @@ static int transmit_reinvite_with_sdp(struct sip_pvt *p); static int transmit_info_with_digit(struct sip_pvt *p, char digit); static int transmit_message_with_text(struct sip_pvt *p, char *text); static int transmit_refer(struct sip_pvt *p, char *dest); +static int sip_sipredirect(struct sip_pvt *p, char *dest); static struct sip_peer *temp_peer(char *name); static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader, char *msg, int init); static void free_old_route(struct sip_route *route); @@ -1968,6 +1970,10 @@ static int sip_transfer(struct ast_channel *ast, char *dest) int res; ast_mutex_lock(&p->lock); + if (ast->_state == AST_STATE_RING) + res = sip_sipredirect(p, dest); + else + res = transmit_refer(p, dest); res = transmit_refer(p, dest); ast_mutex_unlock(&p->lock); return res; @@ -3252,6 +3258,11 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, char *msg, stru } 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; } @@ -9786,7 +9797,6 @@ static char *descrip_sipgetheader = "" "Skips to priority+101 if header does not exist\n" "Otherwise returns 0\n"; - /*--- sip_dtmfmode: change the DTMFmode for a SIP call (application) ---*/ static int sip_dtmfmode(struct ast_channel *chan, void *data) { @@ -9923,6 +9933,87 @@ static int sip_getheader(struct ast_channel *chan, void *data) return 0; } +#define DEFAULT_MAX_FORWARDS 70 + +/* This is 302 sipredirect function coded by Martin Pycko (m78pl@yahoo.com) */ +static int sip_sipredirect(struct sip_pvt *p, char *dest) +{ + char *cdest; + char *extension, *host, *port; + char tmp[80]; + if (!dest || ast_strlen_zero(dest)) { + ast_log(LOG_WARNING, "This application requires these arguments: SIPRedirect(extension[@host[:port]])\n"); + return 0; + } + cdest = ast_strdupa(dest); + if (!cdest) { + ast_log(LOG_ERROR, "Problem allocating the memory\n"); + return 0; + } + extension = strsep(&cdest, "@"); + host = strsep(&cdest, ":"); + port = strsep(&cdest, ":"); + if (!extension) { + ast_log(LOG_ERROR, "Missing mandatory argument: extension\n"); + return 0; + } + + /* 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, "Cannot retrieve the 'To' header from the original SIP request!\n"); + 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++; + /* This is okay becuase lhost and lport are as big as tmp */ + sscanf(localtmp, "%[^<>:; ]:%[^<>:; ]", lhost, lport); + if (!strlen(lhost)) { + ast_log(LOG_ERROR, "Can't find the host address\n"); + return 0; + } + host = ast_strdupa(lhost); + if (!host) { + ast_log(LOG_ERROR, "Problem allocating the memory\n"); + return 0; + } + if (!ast_strlen_zero(lport)) { + port = ast_strdupa(lport); + if (!port) { + ast_log(LOG_ERROR, "Problem allocating the memory\n"); + 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 here */ + return -1; +} + /*--- sip_get_codec: Return peers codec ---*/ static int sip_get_codec(struct ast_channel *chan) { |