From 54832880489bf55b8998e70b3f704306d8b06d54 Mon Sep 17 00:00:00 2001 From: Olle Johansson <oej@edvina.net> Date: Thu, 6 Apr 2006 20:36:25 +0000 Subject: [PATCH] - Implement handle_request_notify to handle incoming NOTIFY requests and respond properly to them. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@18024 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/chan_sip.c | 145 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 140 insertions(+), 5 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 6d91fbec90..58dcb4f6da 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -10553,6 +10553,145 @@ static char *gettag(struct sip_request *req, char *header, char *tagbuf, int tag return thetag; } +/*! \brief Handle incoming notifications */ +static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, struct sockaddr_in *sin, int seqno, char *e) +{ + /* This is mostly a skeleton for future improvements */ + /* Mostly created to return proper answers on notifications on outbound REFER's */ + int res = 0; + char *event = get_header(req, "Event"); + char *eventid = NULL; + char *sep; + + if( (sep = strchr(event, ';')) ) { + *sep = '\0'; + eventid = ++sep; + } + + if (option_debug > 1 && sipdebug) + ast_log(LOG_DEBUG, "Got NOTIFY Event: %s\n", event); + + if (strcmp(event, "refer")) { + /* We don't understand this event. */ + /* Here's room to implement incoming voicemail notifications :-) */ + transmit_response(p, "489 Bad event", req); + if (!p->lastinvite) + ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); + return -1; + } else { + /* Handle REFER notifications */ + + char buf[1024]; + char *cmd, *code; + int respcode; + int success = TRUE; + + /* EventID for each transfer... EventID is basically the REFER cseq + + We are getting notifications on a call that we transfered + We should hangup when we are getting a 200 OK in a sipfrag + Check if we have an owner of this event */ + + /* Check the content type */ + if (strncasecmp(get_header(req, "Content-Type"), "message/sipfrag", strlen("message/sipfrag"))) { + /* We need a sipfrag */ + transmit_response(p, "400 Bad request", req); + ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); + return -1; + } + + /* Get the text of the attachment */ + if (get_msg_text(buf, sizeof(buf), req)) { + ast_log(LOG_WARNING, "Unable to retrieve attachment from NOTIFY %s\n", p->callid); + transmit_response(p, "400 Bad request", req); + ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); + return -1; + } + + /* + From the RFC... + A minimal, but complete, implementation can respond with a single + NOTIFY containing either the body: + SIP/2.0 100 Trying + + if the subscription is pending, the body: + SIP/2.0 200 OK + if the reference was successful, the body: + SIP/2.0 503 Service Unavailable + if the reference failed, or the body: + SIP/2.0 603 Declined + + if the REFER request was accepted before approval to follow the + reference could be obtained and that approval was subsequently denied + (see Section 2.4.7). + + If there are several REFERs in the same dialog, we need to + match the ID of the event header... + */ + if (option_debug > 2) + ast_log(LOG_DEBUG, "* SIP Transfer NOTIFY Attachment: \n---%s\n---\n", buf); + cmd = buf; + while(*cmd && (*cmd < 33)) { /* Skip white space */ + cmd++; + } + code = cmd; + /* We are at SIP/2.0 */ + while(*code && (*code > 32)) { /* Search white space */ + code++; + } + *code = '\0'; + code++; + while(*code && (*code < 33)) { /* Skip white space */ + code++; + } + sep = code; + sep++; + while(*sep && (*sep > 32)) { /* Search white space */ + sep++; + } + *sep = '\0'; + sep++; /* Response string */ + respcode = atoi(code); + switch (respcode) { + case 100: /* Trying: */ + /* Don't do anything yet */ + break; + case 183: /* Ringing: */ + /* Don't do anything yet */ + break; + case 200: /* OK: The new call is up, hangup this call */ + /* Hangup the call that we are replacing */ + break; + case 301: /* Moved permenantly */ + case 302: /* Moved temporarily */ + /* Do we get the header in the packet in this case? */ + success = FALSE; + break; + case 503: /* Service Unavailable: The new call failed */ + /* Cancel transfer, continue the call */ + success = FALSE; + break; + case 603: /* Declined: Not accepted */ + /* Cancel transfer, continue the current call */ + success = FALSE; + break; + } + if (!success) { + ast_log(LOG_NOTICE, "Transfer failed. Sorry. Nothing further to do with this call\n"); + } + + /* Confirm that we received this packet */ + transmit_response(p, "200 OK", req); + return res; + }; + + /* THis could be voicemail notification */ + transmit_response(p, "200 OK", req); + if (!p->lastinvite) + ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); + return res; +} + /*! \brief Handle incoming OPTIONS request */ static int handle_request_options(struct sip_pvt *p, struct sip_request *req, int debug) { @@ -11428,11 +11567,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc } break; case SIP_NOTIFY: - /* XXX we get NOTIFY's from some servers. WHY?? Maybe we should - look into this someday XXX */ - transmit_response(p, "200 OK", req); - if (!p->lastinvite) - ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); + res = handle_request_notify(p, req, debug, ignore, sin, seqno, e); break; case SIP_ACK: /* Make sure we don't ignore this */ -- GitLab