Index: asterisk-1.2.24.dfsg+pf.0.1~svn1329/channels/chan_sip.c =================================================================== --- asterisk-1.2.24.dfsg+pf.0.1~svn1329.orig/channels/chan_sip.c 2007-08-20 17:56:17.000000000 +0200 +++ asterisk-1.2.24.dfsg+pf.0.1~svn1329/channels/chan_sip.c 2007-08-20 17:57:29.000000000 +0200 @@ -1946,9 +1946,9 @@ struct ast_hostent ahp; struct sip_peer *p; int found=0; - char *port; + char *port, *ptr, *hostp, *hostn; int portno; - char host[MAXHOSTNAMELEN], *hostn; + char host[MAXHOSTNAMELEN]; char peer[256]; ast_copy_string(peer, opeer, sizeof(peer)); @@ -1986,7 +1986,14 @@ 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) { ast_copy_string(dialog->tohost, peer, sizeof(dialog->tohost)); memcpy(&dialog->sa.sin_addr, hp->h_addr, sizeof(dialog->sa.sin_addr)); @@ -5189,6 +5196,7 @@ enum state { NOTIFY_OPEN, NOTIFY_INUSE, NOTIFY_CLOSED } local_state = NOTIFY_OPEN; char *pidfstate = "--"; char *pidfnote= "Ready"; + struct sip_pvt *np = NULL; memset(from, 0, sizeof(from)); memset(to, 0, sizeof(to)); @@ -5303,12 +5311,18 @@ ast_build_string(&t, &maxbytes, "\n", p->exten); ast_build_string(&t, &maxbytes, "
\n", mto); ast_build_string(&t, &maxbytes, "\n", (local_state == NOTIFY_OPEN) ? "open" : (local_state == NOTIFY_INUSE) ? "inuse" : "closed"); - ast_build_string(&t, &maxbytes, "\n", (local_state == NOTIFY_OPEN) ? "online" : (local_state == NOTIFY_INUSE) ? "onthephone" : "offline"); + ast_build_string(&t, &maxbytes, "\n", + (local_state == NOTIFY_OPEN) ? "online" : (local_state == NOTIFY_INUSE) ? "onthephone" : "offline"); ast_build_string(&t, &maxbytes, "
\n
\n\n"); break; case PIDF_XML: /* Eyebeam supports this format */ ast_build_string(&t, &maxbytes, "\n"); - ast_build_string(&t, &maxbytes, "\n", mfrom); + ast_build_string(&t, &maxbytes, + "\n", mfrom); ast_build_string(&t, &maxbytes, "\n"); if (pidfstate[0] != '-') ast_build_string(&t, &maxbytes, "\n", pidfstate); @@ -5319,17 +5333,53 @@ if (pidfstate[0] == 'b') /* Busy? Still open ... */ ast_build_string(&t, &maxbytes, "open\n"); else - ast_build_string(&t, &maxbytes, "%s\n", (local_state != NOTIFY_CLOSED) ? "open" : "closed"); + ast_build_string(&t, &maxbytes, "%s\n", + (local_state != NOTIFY_CLOSED) ? "open" : "closed"); ast_build_string(&t, &maxbytes, "\n\n"); break; case DIALOG_INFO_XML: /* SNOM subscribes in this format */ ast_build_string(&t, &maxbytes, "\n"); - ast_build_string(&t, &maxbytes, "\n", p->dialogver++, full ? "full":"partial", mto); - if ((state & AST_EXTENSION_RINGING) && global_notifyringing) - ast_build_string(&t, &maxbytes, "\n", p->exten); - else + ast_build_string(&t, &maxbytes, + "\n", + p->dialogver++, full ? "full":"partial", mto); + + if (!ast_strlen_zero(hint)) { + if ((state & AST_EXTENSION_RINGING)) { + struct ast_channel *chan = NULL; + int hintlen = strlen(hint); + while ((chan = ast_channel_walk_locked(chan)) != NULL) { + if (chan->_state == AST_STATE_RINGING && !strncasecmp(chan->name, "SIP", 3) && + chan->tech_pvt && !strncasecmp(chan->name, hint, hintlen)) { + char iabuf[INET_ADDRSTRLEN]; + np = chan->tech_pvt; + + ast_build_string(&t, &maxbytes, + "\n", + p->exten, np->callid, (unsigned int)np->tag, np->theirtag); + ast_build_string(&t, &maxbytes, "%s\n", statestring); + ast_build_string(&t, &maxbytes, + "%s\n", + p->exten, mto, mfrom); + ast_build_string(&t, &maxbytes, + "%s@%s\n", + np->fromname, np->fromuser, + ((!ast_strlen_zero(np->fromdomain)) ? np->fromdomain : ast_inet_ntoa(iabuf, sizeof(iabuf), np->ourip)), + mto); + + + ast_mutex_unlock(&chan->lock); + break; + + } + ast_mutex_unlock(&chan->lock); + } + } + } + + if(np == NULL) { ast_build_string(&t, &maxbytes, "\n", p->exten); - ast_build_string(&t, &maxbytes, "%s\n", statestring); + ast_build_string(&t, &maxbytes, "%s\n", statestring); + } ast_build_string(&t, &maxbytes, "\n\n"); break; case NONE: @@ -6885,10 +6935,12 @@ } /*! \brief 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; - + char real_totag[128], real_fromtag[128]; + int match = 1; + /* Search interfaces and find the match */ ast_mutex_lock(&iflock); sip_pvt_ptr = iflist; @@ -6896,6 +6948,27 @@ if (!strcmp(sip_pvt_ptr->callid, callid)) { /* Go ahead and lock it (and its owner) before returning */ ast_mutex_lock(&sip_pvt_ptr->lock); + + if (req && pedanticsipchecking) { + if (totag) { + if (!gettag(req, "To", real_totag, sizeof(real_totag))) + bzero(real_totag, sizeof(real_totag)); + if (strcmp(real_totag, totag)) + match = 0; + } + if (match && fromtag) { + if(!gettag(req, "From", real_fromtag, sizeof(real_fromtag))) + bzero(real_fromtag, sizeof(real_fromtag)); + 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); @@ -6918,7 +6991,7 @@ { 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; @@ -6963,6 +7036,8 @@ if (referred_by) referred_by += 4; + refer_uri = ast_strdupa(refer_to); + if ((ptr = strchr(refer_to, '?'))) { /* Search for arguments */ *ptr = '\0'; @@ -6970,10 +7045,7 @@ if (!strncasecmp(ptr, "REPLACES=", 9)) { char *p; 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); ast_uri_decode(replace_callid); if ((ptr = strchr(replace_callid, '%'))) *ptr = '\0'; @@ -7015,13 +7087,13 @@ ast_copy_string(sip_pvt->referred_by, "", sizeof(sip_pvt->referred_by)); ast_copy_string(sip_pvt->refer_contact, "", sizeof(sip_pvt->refer_contact)); 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 @@ -8890,8 +8962,11 @@ { char buf[1024]; unsigned int event; - char *c; + char * c = NULL; + if (sip_debug_test_pvt(p)) + ast_log(LOG_NOTICE, "Receiving INFO from %s\n", p->callid); + /* Need to check the media/type */ if (!strcasecmp(get_header(req, "Content-Type"), "application/dtmf-relay") || !strcasecmp(get_header(req, "Content-Type"), "application/vnd.nortelnetworks.digits")) { @@ -8971,7 +9046,7 @@ /* if (get_msg_text(buf, sizeof(buf), req)) { */ ast_log(LOG_WARNING, "Unable to parse INFO message from %s. Content %s\n", p->callid, buf); - transmit_response(p, "415 Unsupported media type", req); + transmit_response(p, "501 Not Implemented", req); return; } @@ -10604,13 +10679,16 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, int seqno, struct sockaddr_in *sin, int *recount, char *e) { int res = 1; - struct ast_channel *c=NULL; - int gotdest; + int gotdest = 0; + struct ast_channel *c = NULL; struct ast_frame af = { AST_FRAME_NULL, }; - char *supported; - char *required; + char *supported = NULL; + char *required = NULL; unsigned int required_profile = 0; int reinvite = 0; + char *ptr, *p_replaces = NULL, *replace_id = NULL; + struct sip_pvt *refer_pvt = NULL; + struct ast_frame *f = NULL; /* Find out what they support */ if (!p->sipoptions) { @@ -10631,6 +10709,20 @@ } } + if ((p_replaces = get_header(req, "Replaces"))) { + if (ast_strlen_zero(p_replaces)) { + p_replaces = NULL; + } else { + if (debug) + ast_log(LOG_DEBUG, "Found a Replaces header %s\n", get_header(req, "Replaces")); + replace_id = ast_strdupa(p_replaces); + if (strchr(replace_id, '%')) + ast_uri_decode(replace_id); + if ((ptr = strchr(replace_id, ';'))) + *ptr = '\0'; + } + } + /* Check if this is a loop */ /* This happens since we do not properly support SIP domain handling yet... -oej */ @@ -10723,7 +10815,7 @@ extract_uri(p, req); build_contact(p); - if (gotdest) { + if (!replace_id && gotdest) { if (gotdest < 0) transmit_response_reliable(p, "404 Not Found", req, 1); else @@ -10743,8 +10835,41 @@ /* Save Record-Route for any later requests we make on this dialogue */ build_route(p, req, 0); if (c) { - /* Pre-lock the call */ - ast_mutex_lock(&c->lock); + if (replace_id) { + if ((refer_pvt = get_sip_pvt_byid_locked(replace_id, req, NULL, p->theirtag))) { + if (refer_pvt->owner && refer_pvt->owner->_state == AST_STATE_RINGING) { + transmit_response(p, "100 Trying", req); + 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))) { + if (option_debug > 1) + ast_log(LOG_DEBUG, "SIP Call Replacement (pickup) successful for CallID: %s\n", p_replaces); + ast_frfree(f); + ast_setstate(c, AST_STATE_UP); + } else { + ast_log(LOG_WARNING, "SIP Call Replacement (pickup) not successful for CallID: %s\n", p_replaces); + transmit_response_with_allow(p, "403 Call Can Not Be Read From", req, 0); /* Don't know if this is the correct answer, but seems to work */ + ast_mutex_unlock(&refer_pvt->owner->lock); + return 0; + } + } else { + if (refer_pvt->owner) + ast_mutex_unlock(&refer_pvt->owner->lock); + ast_mutex_unlock(&refer_pvt->lock); + ast_hangup(c); + ast_log(LOG_WARNING, "SIP Call Replacement (pickup) not possible. Call already answered\n"); + transmit_response_with_allow(p, "403 Call Already Answered Or Hung Up", req, 0); /* Don't know if this is the correct answer, but seems to work */ + return 0; + } + } else { + ast_hangup(c); + transmit_response_with_allow(p, "481 Call/Transaction Does Not Exist", req, 0); + return 0; + } + } else + ast_mutex_lock(&c->lock); /* Pre-lock the call */ } } @@ -11251,7 +11376,10 @@ if (!strcmp(p_old->username, p->username)) { if (!strcmp(p_old->exten, p->exten) && !strcmp(p_old->context, p->context)) { - ast_set_flag(p_old, SIP_NEEDDESTROY); + if(strncmp(get_header(req, "User-Agent"), "THOMSON ST20", 12) == 0) { + ast_set_flag(p, SIP_NEEDDESTROY); + } else + ast_set_flag(p_old, SIP_NEEDDESTROY); ast_mutex_unlock(&p_old->lock); break; } @@ -11493,6 +11621,14 @@ if (!p->lastinvite && ast_strlen_zero(p->randdata)) ast_set_flag(p, SIP_NEEDDESTROY); break; + case SIP_PUBLISH: + transmit_response_with_allow(p, "501 Method Not Implemented", req, 0); + if (debug) + ast_log(LOG_DEBUG, "PUBLISH: from %s\n", e); + /* If this is some new method, and we don't have a call, destroy it now */ + if (!p->initreq.headers) + ast_set_flag(p, SIP_NEEDDESTROY); + break; default: transmit_response_with_allow(p, "501 Method Not Implemented", req, 0); ast_log(LOG_NOTICE, "Unknown SIP command '%s' from '%s'\n",