aboutsummaryrefslogtreecommitdiffstats
path: root/patches
diff options
context:
space:
mode:
authorkpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b>2005-04-27 05:22:36 +0000
committerkpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b>2005-04-27 05:22:36 +0000
commit8e1296be7e342d81550ef10a021828e1691ab81b (patch)
treed03b8819e1e936064819c7717b88a65038626a2f /patches
parent53b8d9c9c04ecbecdf919120e98edd9284f5e7c7 (diff)
add patch from bug #3710 so it can get wider testing
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@5516 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'patches')
-rwxr-xr-xpatches/bug_3710_sip_refer.patch780
1 files changed, 780 insertions, 0 deletions
diff --git a/patches/bug_3710_sip_refer.patch b/patches/bug_3710_sip_refer.patch
new file mode 100755
index 000000000..d7e4da863
--- /dev/null
+++ b/patches/bug_3710_sip_refer.patch
@@ -0,0 +1,780 @@
+Index: channels/chan_sip.c
+===================================================================
+RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v
+retrieving revision 1.703
+diff -u -r1.703 chan_sip.c
+--- channels/chan_sip.c 6 Apr 2005 21:12:32 -0000 1.703
++++ channels/chan_sip.c 9 Apr 2005 00:13:25 -0000
+@@ -71,6 +71,7 @@
+
+ /* #define VOCAL_DATA_HACK */
+
++#define SIP_RETVAL_IGNORE 42 /* shrug */
+ #define SIPDUMPER
+ #define DEFAULT_DEFAULT_EXPIRY 120
+ #define DEFAULT_MAX_EXPIRY 3600
+@@ -668,6 +669,7 @@
+ static struct sip_user *build_user(const char *name, struct ast_variable *v, int realtime);
+ static int sip_do_reload(void);
+ static int expire_register(void *data);
++static int sip_addheader(struct ast_channel *chan, void *data);
+ static int callevents = 0;
+
+ static struct ast_channel *sip_request(const char *type, int format, void *data, int *cause);
+@@ -1237,7 +1239,7 @@
+ /* Delete it, it needs to disappear */
+ if (peer->call)
+ sip_destroy(peer->call);
+- if(peer->chanvars) {
++ if (peer->chanvars) {
+ ast_variables_destroy(peer->chanvars);
+ peer->chanvars = NULL;
+ }
+@@ -1302,7 +1304,7 @@
+ !strcasecmp(tmp->value, "user")) {
+ ast_variables_destroy(var);
+ return NULL;
+- } else if(!newpeername && !strcasecmp(tmp->name, "name")) {
++ } else if (!newpeername && !strcasecmp(tmp->name, "name")) {
+ newpeername = tmp->value;
+ }
+ tmp = tmp->next;
+@@ -1312,9 +1314,9 @@
+ peer = build_peer(newpeername, var, ast_test_flag((&global_flags_page2), SIP_PAGE2_RTCACHEFRIENDS) ? 0 : 1);
+
+ if (peer) {
+- if(ast_test_flag((&global_flags_page2), SIP_PAGE2_RTCACHEFRIENDS)) {
++ if (ast_test_flag((&global_flags_page2), SIP_PAGE2_RTCACHEFRIENDS)) {
+ 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 (ast_test_flag((&global_flags_page2), SIP_PAGE2_RTAUTOCLEAR)) {
+ if (peer->expire > -1) {
+ ast_sched_del(sched, peer->expire);
+ }
+@@ -1364,7 +1366,7 @@
+ static void sip_destroy_user(struct sip_user *user)
+ {
+ ast_free_ha(user->ha);
+- if(user->chanvars) {
++ if (user->chanvars) {
+ ast_variables_destroy(user->chanvars);
+ user->chanvars = NULL;
+ }
+@@ -1405,7 +1407,7 @@
+
+ if (user) {
+ /* Add some finishing touches, addresses, etc */
+- if(ast_test_flag((&global_flags_page2), SIP_PAGE2_RTCACHEFRIENDS)) {
++ if (ast_test_flag((&global_flags_page2), SIP_PAGE2_RTCACHEFRIENDS)) {
+ suserobjs++;
+
+ ASTOBJ_CONTAINER_LINK(&userl,user);
+@@ -1515,6 +1517,8 @@
+ }
+ }
+ if (!p && !found) {
++ char *ptr, *hostp;
++
+ hostn = peer;
+ if (port)
+ portno = atoi(port);
+@@ -1531,7 +1535,15 @@
+ portno = tportno;
+ }
+ }
+- hp = ast_gethostbyname(hostn, &ahp);
++ if ((hostp = ast_strdupa(hostn))) {
++ if ((ptr = strchr(hostp, '?'))) {
++ *ptr = '\0';
++ }
++ } else {
++ hostp = peer;
++ }
++
++ hp = ast_gethostbyname(hostp, &ahp);
+ if (hp) {
+ strncpy(r->tohost, peer, sizeof(r->tohost) - 1);
+ memcpy(&r->sa.sin_addr, hp->h_addr, sizeof(r->sa.sin_addr));
+@@ -1731,7 +1743,7 @@
+ free(cp);
+ }
+ ast_mutex_destroy(&p->lock);
+- if(p->chanvars) {
++ if (p->chanvars) {
+ ast_variables_destroy(p->chanvars);
+ p->chanvars = NULL;
+ }
+@@ -2520,7 +2532,7 @@
+ if (!p->rtp) {
+ ast_log(LOG_WARNING, "Unable to create RTP session: %s\n", strerror(errno));
+ ast_mutex_destroy(&p->lock);
+- if(p->chanvars) {
++ if (p->chanvars) {
+ ast_variables_destroy(p->chanvars);
+ p->chanvars = NULL;
+ }
+@@ -3086,7 +3098,7 @@
+ if (!strcasecmp(aliases[x].fullname, var))
+ shortname = aliases[x].shortname;
+ }
+- if(!ast_strlen_zero(shortname)) {
++ if (!ast_strlen_zero(shortname)) {
+ snprintf(req->header[req->headers], sizeof(req->data) - req->len - 4, "%s: %s\r\n", shortname, value);
+ } else {
+ snprintf(req->header[req->headers], sizeof(req->data) - req->len - 4, "%s: %s\r\n", var, value);
+@@ -3703,7 +3715,7 @@
+ }
+ /* Start by sending our preferred codecs */
+ for (x = 0 ; x < 32 ; x++) {
+- if(!(pref_codec = ast_codec_pref_index(&p->prefs,x)))
++ if (!(pref_codec = ast_codec_pref_index(&p->prefs,x)))
+ break;
+ if ((capability & pref_codec) && !(alreadysent & pref_codec)) {
+ if (debug)
+@@ -3850,7 +3862,7 @@
+ while( *e && ( *e < 33 ) ) {
+ e++;
+ }
+- if( !*e ) {
++ if ( !*e ) {
+ return -1;
+ }
+
+@@ -3858,7 +3870,7 @@
+ /* We have a response */
+ req->rlPart2 = e;
+ len = strlen( req->rlPart2 );
+- if( len < 2 ) {
++ if ( len < 2 ) {
+ return -1;
+ }
+ e+= len - 1;
+@@ -3868,18 +3880,18 @@
+ *(++e)= '\0';
+ } else {
+ /* We have a request */
+- if( *e == '<' ) {
++ if ( *e == '<' ) {
+ e++;
+- if( !*e ) {
++ if ( !*e ) {
+ return -1;
+ }
+ }
+ req->rlPart2 = e; /* URI */
+- if( ( e= strrchr( req->rlPart2, 'S' ) ) == NULL ) {
++ if ( ( e= strrchr( req->rlPart2, 'S' ) ) == NULL ) {
+ return -1;
+ }
+ while( isspace( *(--e) ) ) {}
+- if( *e == '>' ) {
++ if ( *e == '>' ) {
+ *e = '\0';
+ } else {
+ *(++e)= '\0';
+@@ -4984,7 +4996,7 @@
+
+ /* Save User agent */
+ useragent = get_header(req, "User-Agent");
+- if(useragent && strcasecmp(useragent, p->useragent)) {
++ if (useragent && strcasecmp(useragent, p->useragent)) {
+ strncpy(p->useragent, useragent, sizeof(p->useragent) - 1);
+ if (option_verbose > 3) {
+ ast_verbose(VERBOSE_PREFIX_3 "Saved useragent \"%s\" for peer %s\n",p->useragent,p->name);
+@@ -5212,12 +5224,12 @@
+ c+= strlen("response=");
+ if ((*c == '\"')) {
+ response=++c;
+- if((c = strchr(c,'\"')))
++ if ((c = strchr(c,'\"')))
+ *c = '\0';
+
+ } else {
+ response=c;
+- if((c = strchr(c,',')))
++ if ((c = strchr(c,',')))
+ *c = '\0';
+ }
+
+@@ -5225,11 +5237,11 @@
+ c+= strlen("uri=");
+ if ((*c == '\"')) {
+ resp_uri=++c;
+- if((c = strchr(c,'\"')))
++ if ((c = strchr(c,'\"')))
+ *c = '\0';
+ } else {
+ resp_uri=c;
+- if((c = strchr(c,',')))
++ if ((c = strchr(c,',')))
+ *c = '\0';
+ }
+
+@@ -5239,7 +5251,7 @@
+ c++;
+ }
+ snprintf(a1, sizeof(a1), "%s:%s:%s", username, global_realm, secret);
+- if(!ast_strlen_zero(resp_uri))
++ if (!ast_strlen_zero(resp_uri))
+ snprintf(a2, sizeof(a2), "%s:%s", sip_methods[sipmethod].text, resp_uri);
+ else
+ snprintf(a2, sizeof(a2), "%s:%s", sip_methods[sipmethod].text, uri);
+@@ -5473,8 +5485,23 @@
+ return 0;
+ }
+
++static int sip_extract_tag(char **in)
++{
++ char *tag;
++
++ if ((tag = ast_strcasestr(*in, "tag="))) {
++ char *ptr;
++ tag += 4;
++ if ((ptr = strchr(tag, ';'))) {
++ *ptr = '\0';
++ }
++ return 0;
++ }
++ return -1;
++}
++
+ /*--- get_sip_pvt_byid_locked: Lock interface lock and find matching pvt lock ---*/
+-static struct sip_pvt *get_sip_pvt_byid_locked(char *callid)
++static struct sip_pvt *get_sip_pvt_byid_locked(char *callid, struct sip_request *req, char *totag, char *fromtag)
+ {
+ struct sip_pvt *sip_pvt_ptr = NULL;
+
+@@ -5483,8 +5510,38 @@
+ sip_pvt_ptr = iflist;
+ while(sip_pvt_ptr) {
+ if (!strcmp(sip_pvt_ptr->callid, callid)) {
++ char *real_totag = NULL, *real_fromtag = NULL;
++ int match = 1;
++
+ /* Go ahead and lock it (and its owner) before returning */
+ ast_mutex_lock(&sip_pvt_ptr->lock);
++
++ if (req && pedanticsipchecking) {
++ if (totag) {
++ real_totag = ast_strdupa(get_header(req, "To"));
++ if (sip_extract_tag(&real_totag)) {
++ real_totag = NULL;
++ }
++ if (strcmp(real_totag, totag)) {
++ match = 0;
++ }
++ }
++ if (match && fromtag) {
++ real_fromtag = ast_strdupa(get_header(req, "From"));
++ if (sip_extract_tag(&real_fromtag)) {
++ real_fromtag = NULL;
++ }
++ if (strcmp(real_fromtag, fromtag)) {
++ match = 0;
++ }
++ }
++ }
++
++ if (!match) {
++ ast_mutex_unlock(&sip_pvt_ptr->lock);
++ break;
++ }
++
+ if (sip_pvt_ptr->owner) {
+ while(ast_mutex_trylock(&sip_pvt_ptr->owner->lock)) {
+ ast_mutex_unlock(&sip_pvt_ptr->lock);
+@@ -5521,14 +5578,12 @@
+ return replaced;
+ }
+
+-
+-
+ /*--- get_refer_info: Call transfer support (new standard) ---*/
+ static int get_refer_info(struct sip_pvt *sip_pvt, struct sip_request *outgoing_req)
+ {
+
+ char *p_refer_to = NULL, *p_referred_by = NULL, *h_refer_to = NULL, *h_referred_by = NULL, *h_contact = NULL;
+- char *replace_callid = "", *refer_to = NULL, *referred_by = NULL, *ptr = NULL;
++ char *replace_callid = "", *refer_to = NULL, *referred_by = NULL, *ptr = NULL, *replaces_header=NULL, *refer_uri;
+ struct sip_request *req = NULL;
+ struct sip_pvt *sip_pvt_ptr = NULL;
+ struct ast_channel *chan = NULL, *peer = NULL;
+@@ -5539,14 +5594,14 @@
+ req = &sip_pvt->initreq;
+ }
+
+- if(!( (p_refer_to = get_header(req, "Refer-To")) && (h_refer_to = ast_strdupa(p_refer_to)) )) {
++ if (!( (p_refer_to = get_header(req, "Refer-To")) && (h_refer_to = ast_strdupa(p_refer_to)) )) {
+ ast_log(LOG_WARNING, "No Refer-To Header That's illegal\n");
+ return -1;
+ }
+
+ refer_to = ditch_braces(h_refer_to);
+
+- if(!( (p_referred_by = get_header(req, "Referred-By")) && (h_referred_by = ast_strdupa(p_referred_by)) )) {
++ if (!( (p_referred_by = get_header(req, "Referred-By")) && (h_referred_by = ast_strdupa(p_referred_by)) )) {
+ ast_log(LOG_WARNING, "No Refer-To Header That's illegal\n");
+ return -1;
+ }
+@@ -5559,9 +5614,11 @@
+ ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", referred_by);
+ return -1;
+ }
++
++
+ refer_to += 4;
+ referred_by += 4;
+-
++ refer_uri = ast_strdupa(refer_to);
+
+ if ((ptr = strchr(refer_to, '?'))) {
+ /* Search for arguemnts */
+@@ -5569,10 +5626,7 @@
+ ptr++;
+ if (!strncasecmp(ptr, "REPLACES=", 9)) {
+ replace_callid = ast_strdupa(ptr + 9);
+- /* someday soon to support invite/replaces properly!
+- replaces_header = ast_strdupa(replace_callid);
+- -anthm
+- */
++ replaces_header = ast_strdupa(replace_callid);
+ sip_unescape_uri(replace_callid);
+ if ((ptr = strchr(replace_callid, '%')))
+ *ptr = '\0';
+@@ -5606,19 +5660,50 @@
+ strncpy(sip_pvt->referred_by, "", sizeof(sip_pvt->referred_by) - 1);
+ strncpy(sip_pvt->refer_contact, "", sizeof(sip_pvt->refer_contact) - 1);
+ sip_pvt->refer_call = NULL;
+- if ((sip_pvt_ptr = get_sip_pvt_byid_locked(replace_callid))) {
++ if ((sip_pvt_ptr = get_sip_pvt_byid_locked(replace_callid, req, NULL, NULL))) {
+ sip_pvt->refer_call = sip_pvt_ptr;
+ if (sip_pvt->refer_call == sip_pvt) {
+ ast_log(LOG_NOTICE, "Supervised transfer attempted to transfer into same call id (%s == %s)!\n", replace_callid, sip_pvt->callid);
+ sip_pvt->refer_call = NULL;
+- } else
+- return 0;
++ }
++ return 0;
+ } else {
+- ast_log(LOG_NOTICE, "Supervised transfer requested, but unable to find callid '%s'. Both legs must reside on Asterisk box to transfer at this time.\n", replace_callid);
+- /* XXX The refer_to could contain a call on an entirely different machine, requiring an
+- INVITE with a replaces header -anthm XXX */
++ /* Don't ask me =0 ?, SIP made do it! */
++ int cause = 0, res = -1;
++ struct ast_channel *ichan = NULL;
+
+-
++ transmit_notify_with_sipfrag(sip_pvt, sip_pvt->ocseq);
++ if ((ptr = strchr(refer_uri, ';'))) {
++ *ptr = '\0';
++ }
++
++ if ((ichan = sip_request("SIP", sip_pvt->owner ? sip_pvt->owner->readformat : AST_FORMAT_ULAW, refer_uri, &cause))) {
++ struct ast_frame *f;
++ char *rbuf;
++ ast_log(LOG_DEBUG, "Going hunting for a remote INVITE/Replaces at [%s] Wish me luck!\n", refer_uri);
++ if ((rbuf = alloca(strlen(replaces_header) + 10))) {
++ sprintf(rbuf, "Replaces: %s", replaces_header);
++ sip_addheader(ichan, rbuf);
++ sip_call(ichan, refer_uri, 20000);
++ ast_channel_masquerade(sip_pvt->owner, ichan);
++ if ((f = ast_read(ichan))) {
++ ast_log(LOG_DEBUG, "WooHoo! The INVITE/Replaces Worked!\n");
++ ast_frfree(f);
++ transmit_response(sip_pvt, "202 Accepted", req);
++ res = SIP_RETVAL_IGNORE; /* means do nothing more */
++ } else {
++ res = -1;
++ }
++ } else {
++ ast_log(LOG_ERROR,"Memory Error!\n");
++ res = -1;
++ }
++
++ ast_hangup(ichan);
++ } else {
++ res = -1;
++ }
++ return res;
+ }
+ } else if (ast_exists_extension(NULL, sip_pvt->context, refer_to, 1, NULL) || !strcmp(refer_to, ast_parking_ext())) {
+ /* This is an unsupervised transfer */
+@@ -5632,7 +5717,7 @@
+ strncpy(sip_pvt->refer_contact, h_contact, sizeof(sip_pvt->refer_contact) - 1);
+ }
+ sip_pvt->refer_call = NULL;
+- if((chan = sip_pvt->owner) && (peer = ast_bridged_channel(sip_pvt->owner))) {
++ if ((chan = sip_pvt->owner) && (peer = ast_bridged_channel(sip_pvt->owner))) {
+ pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
+ pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
+ }
+@@ -5807,7 +5892,7 @@
+ *end = '\0';
+ else
+ output[0] = '\0';
+- if(strstr(input,"privacy=full") || strstr(input,"privacy=uri"))
++ if (strstr(input,"privacy=full") || strstr(input,"privacy=uri"))
+ return AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
+
+ return 0;
+@@ -5840,7 +5925,7 @@
+
+ rpid = get_header(req, "Remote-Party-ID");
+ memset(rpid_num,0,sizeof(rpid_num));
+- if(!ast_strlen_zero(rpid))
++ if (!ast_strlen_zero(rpid))
+ p->callingpres = get_rpid_num(rpid,rpid_num, sizeof(rpid_num));
+
+ of = ditch_braces(from);
+@@ -5876,14 +5961,14 @@
+ ast_copy_flags(p, user, SIP_TRUSTRPID | SIP_USECLIENTCODE | SIP_NAT | SIP_PROG_INBAND | SIP_OSPAUTH);
+ /* copy channel vars */
+ for (v = user->chanvars ; v ; v = v->next) {
+- if((tmpvar = ast_variable_new(v->name, v->value))) {
++ if ((tmpvar = ast_variable_new(v->name, v->value))) {
+ tmpvar->next = p->chanvars;
+ p->chanvars = tmpvar;
+ }
+ }
+ p->prefs = user->prefs;
+ /* replace callerid if rpid found, and not restricted */
+- if(!ast_strlen_zero(rpid_num) && ast_test_flag(p, SIP_TRUSTRPID)) {
++ if (!ast_strlen_zero(rpid_num) && ast_test_flag(p, SIP_TRUSTRPID)) {
+ if (*calleridname)
+ strncpy(p->cid_name, calleridname, sizeof(p->cid_name) - 1);
+ strncpy(p->cid_num, rpid_num, sizeof(p->cid_num) - 1);
+@@ -5955,7 +6040,7 @@
+ /* Take the peer */
+ ast_copy_flags(p, peer, SIP_TRUSTRPID | SIP_USECLIENTCODE | SIP_NAT | SIP_PROG_INBAND | SIP_OSPAUTH);
+ /* replace callerid if rpid found, and not restricted */
+- if(!ast_strlen_zero(rpid_num) && ast_test_flag(p, SIP_TRUSTRPID)) {
++ if (!ast_strlen_zero(rpid_num) && ast_test_flag(p, SIP_TRUSTRPID)) {
+ if (*calleridname)
+ strncpy(p->cid_name, calleridname, sizeof(p->cid_name) - 1);
+ strncpy(p->cid_num, rpid_num, sizeof(p->cid_num) - 1);
+@@ -5988,7 +6073,7 @@
+ strncpy(p->authname, peer->name, sizeof(p->authname) - 1);
+ /* copy channel vars */
+ for (v = peer->chanvars ; v ; v = v->next) {
+- if((tmpvar = ast_variable_new(v->name, v->value))) {
++ if ((tmpvar = ast_variable_new(v->name, v->value))) {
+ tmpvar->next = p->chanvars;
+ p->chanvars = tmpvar;
+ }
+@@ -6466,7 +6551,7 @@
+ sip_do_reload();
+ ast_cli(fd, "OK. Cache is flushed.\n");
+ } else if ((peer = find_peer(argv[3], NULL, 0))) {
+- if(ast_test_flag((&peer->flags_page2), SIP_PAGE2_RTCACHEFRIENDS)) {
++ if (ast_test_flag((&peer->flags_page2), SIP_PAGE2_RTCACHEFRIENDS)) {
+ ast_set_flag((&peer->flags_page2), SIP_PAGE2_RTAUTOCLEAR);
+ expire_register(peer);
+ ast_cli(fd, "OK. Peer %s was removed from the cache.\n", argv[3]);
+@@ -6606,10 +6691,10 @@
+ pref = &peer->prefs;
+ for(x = 0; x < 32 ; x++) {
+ codec = ast_codec_pref_index(pref,x);
+- if(!codec)
++ if (!codec)
+ break;
+ ast_cli(fd, "%s", ast_getformatname(codec));
+- if(x < 31 && ast_codec_pref_index(pref,x+1))
++ if (x < 31 && ast_codec_pref_index(pref,x+1))
+ ast_cli(fd, "|");
+ }
+
+@@ -6689,10 +6774,10 @@
+ pref = &peer->prefs;
+ for(x = 0; x < 32 ; x++) {
+ codec = ast_codec_pref_index(pref,x);
+- if(!codec)
++ if (!codec)
+ break;
+ ast_cli(fd, "%s", ast_getformatname(codec));
+- if(x < 31 && ast_codec_pref_index(pref,x+1))
++ if (x < 31 && ast_codec_pref_index(pref,x+1))
+ ast_cli(fd, ",");
+ }
+
+@@ -6765,10 +6850,10 @@
+ pref = &user->prefs;
+ for(x = 0; x < 32 ; x++) {
+ codec = ast_codec_pref_index(pref,x);
+- if(!codec)
++ if (!codec)
+ break;
+ ast_cli(fd, "%s", ast_getformatname(codec));
+- if(x < 31 && ast_codec_pref_index(pref,x+1))
++ if (x < 31 && ast_codec_pref_index(pref,x+1))
+ ast_cli(fd, "|");
+ }
+
+@@ -7816,12 +7901,12 @@
+ }
+ switch(resp) {
+ case 100: /* 100 Trying */
+- if(sipmethod == SIP_INVITE) {
++ if (sipmethod == SIP_INVITE) {
+ sip_cancel_destroy(p);
+ }
+ break;
+ case 183: /* 183 Session Progress */
+- if(sipmethod == SIP_INVITE) {
++ if (sipmethod == SIP_INVITE) {
+ sip_cancel_destroy(p);
+ if (!ast_strlen_zero(get_header(req, "Content-Type")))
+ process_sdp(p, req);
+@@ -7832,7 +7917,7 @@
+ }
+ break;
+ case 180: /* 180 Ringing */
+- if(sipmethod == SIP_INVITE) {
++ if (sipmethod == SIP_INVITE) {
+ sip_cancel_destroy(p);
+ if (p->owner) {
+ ast_queue_control(p->owner, AST_CONTROL_RINGING);
+@@ -7911,8 +7996,8 @@
+ for(;;) {
+ contact = __get_header(req, "Contact", &start);
+ /* this loop ensures we get a contact header about our register request */
+- if(!ast_strlen_zero(contact)) {
+- if( (tmptmp=strstr(contact, p->our_contact))) {
++ if (!ast_strlen_zero(contact)) {
++ if ( (tmptmp=strstr(contact, p->our_contact))) {
+ contact=tmptmp;
+ break;
+ }
+@@ -7986,7 +8071,7 @@
+ transmit_request(p, SIP_ACK, seqno, 0, 0);
+ /* Then we AUTH */
+ /* But only if the packet wasn't marked as ignore in handle_request */
+- if(!ignore){
++ if (!ignore){
+ p->theirtag[0]='\0'; /* forget their old tag, so we don't match tags when getting response */
+ if ((p->authtries > 1) || do_proxy_auth(p, req, "Proxy-Authenticate", "Proxy-Authorization", SIP_INVITE, 1)) {
+ ast_log(LOG_NOTICE, "Failed to authenticate on INVITE to '%s'\n", get_header(&p->initreq, "From"));
+@@ -8259,18 +8344,19 @@
+
+ if (peera->cdr && peerb->cdr) {
+ peerb->cdr = ast_cdr_append(peerb->cdr, peera->cdr);
+- } else if(peera->cdr) {
++ } else if (peera->cdr) {
+ peerb->cdr = peera->cdr;
+ }
+ peera->cdr = NULL;
+
+ if (peerb->cdr && peerc->cdr) {
+ peerb->cdr = ast_cdr_append(peerb->cdr, peerc->cdr);
+- } else if(peerc->cdr) {
++ } else if (peerc->cdr) {
+ peerb->cdr = peerc->cdr;
+ }
+ peerc->cdr = NULL;
+
++ ast_log(LOG_DEBUG, "XXXX Trying to masquerade %s and %s\n", peerb->name, peerc->name);
+ if (ast_channel_masquerade(peerb, peerc)) {
+ ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", peerb->name, peerc->name);
+ res = -1;
+@@ -8318,7 +8404,24 @@
+ struct ast_channel *c=NULL;
+ int gotdest;
+ struct ast_frame af = { AST_FRAME_NULL, };
++ char *p_replaces, *replace_id = NULL;
+
++ if ((p_replaces = get_header(req, "Replaces"))) {
++ if (ast_strlen_zero(p_replaces)) {
++ p_replaces = NULL;
++ } else {
++ char *ptr;
++ ast_log(LOG_DEBUG, "I SEE a Replaces [%s]\n", p_replaces);
++ replace_id = ast_strdupa(p_replaces);
++ if (strchr(replace_id, '%')) {
++ sip_unescape_uri(replace_id);
++ }
++ if ((ptr = strchr(replace_id, ';'))) {
++ *ptr = '\0';
++ }
++ }
++ }
++
+ if (ast_test_flag(p, SIP_OUTGOING) && p->owner && (p->owner->_state != AST_STATE_UP)) {
+ /* This is a call to ourself. Send ourselves an error code and stop
+ processing immediately, as SIP really has no good mechanism for
+@@ -8327,6 +8430,7 @@
+ /* We do NOT destroy p here, so that our response will be accepted */
+ return 0;
+ }
++
+ if (!ignore) {
+ /* Use this as the basis */
+ if (debug)
+@@ -8351,8 +8455,10 @@
+ ast_log(LOG_DEBUG, "Hm.... No sdp for the moment\n");
+ }
+ }
+- } else if (debug)
++ } else if (debug) {
+ ast_verbose("Ignoring this request\n");
++ }
++
+ if (!p->lastinvite && !ignore && !p->owner) {
+ /* Handle authentication if this is our first invite */
+ res = check_user(p, req, SIP_INVITE, e, 1, sin, ignore);
+@@ -8403,22 +8509,22 @@
+ get_rdnis(p, NULL);
+ extract_uri(p, req);
+ build_contact(p);
+-
+- if (gotdest) {
++
++ if (!replace_id && gotdest) {
+ if (gotdest < 0) {
+ if (ignore)
+ transmit_response(p, "404 Not Found", req);
+ else
+ transmit_response_reliable(p, "404 Not Found", req, 1);
+ update_user_counter(p,DEC_IN_USE);
+- } else {
+- if (ignore)
+- transmit_response(p, "484 Address Incomplete", req);
+- else
+- transmit_response_reliable(p, "484 Address Incomplete", req, 1);
+- update_user_counter(p,DEC_IN_USE);
+- }
+- ast_set_flag(p, SIP_NEEDDESTROY);
++ } else {
++ if (ignore)
++ transmit_response(p, "484 Address Incomplete", req);
++ else
++ transmit_response_reliable(p, "484 Address Incomplete", req, 1);
++ update_user_counter(p,DEC_IN_USE);
++ }
++ ast_set_flag(p, SIP_NEEDDESTROY);
+ } else {
+ /* If no extension was specified, use the s one */
+ if (ast_strlen_zero(p->exten))
+@@ -8431,16 +8537,41 @@
+ /* Save Record-Route for any later requests we make on this dialogue */
+ build_route(p, req, 0);
+ if (c) {
++ if (replace_id) {
++ struct sip_pvt *refer_pvt;
++ struct ast_frame *f;
++
++ if ((refer_pvt = get_sip_pvt_byid_locked(replace_id, req, NULL, p->theirtag))) {
++ ast_log(LOG_DEBUG, "XXXXXXXX I PARSED a Replaces [%s]\n", p_replaces);
++ transmit_response(p, "100 Trying", req);
++ ast_mutex_unlock(&refer_pvt->owner->lock);
++ ast_mutex_unlock(&refer_pvt->lock);
++ ast_channel_masquerade(refer_pvt->owner, c );
++ ast_hangup(c);
++ c = refer_pvt->owner;
++ if ((f = ast_read(c))) {
++ ast_log(LOG_DEBUG, "XXXXXXXX I DID a Replaces [%s]\n", p_replaces);
++ ast_frfree(f);
++ ast_setstate(c, AST_STATE_UP);
++ }
++ } else {
++ transmit_response_with_allow(p, "481 Call/Transaction Does Not Exist", req, 0);
++ return 0;
++ }
++ }
+ /* Pre-lock the call */
+ ast_mutex_lock(&c->lock);
+ }
+ }
+-
+- } else
++ } else {
+ c = p->owner;
+- if (!ignore && p)
++ }
++
++ if (!ignore && p) {
+ p->lastinvite = seqno;
++ }
+ if (c) {
++
+ switch(c->_state) {
+ case AST_STATE_DOWN:
+ transmit_response(p, "100 Trying", req);
+@@ -8528,11 +8659,13 @@
+ if (ast_strlen_zero(p->context))
+ strncpy(p->context, default_context, sizeof(p->context) - 1);
+ res = get_refer_info(p, req);
+- if (res < 0)
++ if (res == SIP_RETVAL_IGNORE) {
++ ignore = 1;
++ } else if (res < 0) {
+ transmit_response_with_allow(p, "404 Not Found", req, 1);
+- else if (res > 0)
++ } else if (res > 0) {
+ transmit_response_with_allow(p, "484 Address Incomplete", req, 1);
+- else {
++ } else {
+ int nobye = 0;
+ if (!ignore) {
+ if (p->refer_call) {
+@@ -8856,7 +8989,7 @@
+ cseq += len;
+
+ /* Determine the request URI for sip, sips or tel URIs */
+- if( determine_firstline_parts( req ) < 0 ) {
++ if ( determine_firstline_parts( req ) < 0 ) {
+ return -1;
+ }
+ cmd = req->rlPart1;
+@@ -9548,7 +9681,7 @@
+ ast_set_flag(flags, SIP_PROG_INBAND_YES);
+ } else if (!strcasecmp(v->name, "allowguest")) {
+ #ifdef OSP_SUPPORT
+- if(!strcasecmp(v->value, "osp"))
++ if (!strcasecmp(v->value, "osp"))
+ global_allowguest = 2;
+ else
+ #endif
+@@ -9716,7 +9849,7 @@
+ if (varname && (varval = strchr(varname,'='))) {
+ *varval = '\0';
+ varval++;
+- if((tmpvar = ast_variable_new(varname, varval))) {
++ if ((tmpvar = ast_variable_new(varname, varval))) {
+ tmpvar->next = user->chanvars;
+ user->chanvars = tmpvar;
+ }
+@@ -9857,7 +9990,7 @@
+ peer->expiry = expiry;
+ }
+ /* If we have channel variables, remove them (reload) */
+- if(peer->chanvars) {
++ if (peer->chanvars) {
+ ast_variables_destroy(peer->chanvars);
+ peer->chanvars = NULL;
+ }
+@@ -10027,7 +10160,7 @@
+ if (varname && (varval = strchr(varname,'='))) {
+ *varval = '\0';
+ varval++;
+- if((tmpvar = ast_variable_new(varname, varval))) {
++ if ((tmpvar = ast_variable_new(varname, varval))) {
+ tmpvar->next = peer->chanvars;
+ peer->chanvars = tmpvar;
+ }
+@@ -10164,7 +10297,7 @@
+ ast_set2_flag((&global_flags_page2), ast_true(v->value), SIP_PAGE2_RTNOUPDATE);
+ } else if (!strcasecmp(v->name, "rtautoclear")) {
+ int i = atoi(v->value);
+- if(i > 0)
++ if (i > 0)
+ global_rtautoclear = i;
+ else
+ i = 0;
+@@ -10937,7 +11070,7 @@
+ p = p->next;
+ /* Free associated memory */
+ ast_mutex_destroy(&pl->lock);
+- if(pl->chanvars) {
++ if (pl->chanvars) {
+ ast_variables_destroy(pl->chanvars);
+ pl->chanvars = NULL;
+ }