--- chan_sip.c.2009-07-07 2009-07-07 16:06:48.000000000 -0600 +++ chan_sip.c 2009-07-07 17:37:47.000000000 -0600 @@ -2472,6 +2472,7 @@ static void ast_quiet_chan(struct ast_channel *chan); static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target); static int do_magic_pickup(struct ast_channel *channel, const char *extension, const char *context); +static int get_mwi_parameters(struct sip_request *req, int* messages_waiting, int* new_voicemail_messages, int* old_voicemail_messages, int* new_urgent_voicemail_messages, int* old_urgent_voicemail_messages); /*! * \brief generic function for determining if a correct transport is being @@ -7381,10 +7382,6 @@ if (intended_method == SIP_REFER) { /* We do support REFER, but not outside of a dialog yet */ transmit_response_using_temp(callid, sin, 1, intended_method, req, "603 Declined (no dialog)"); - } else if (intended_method == SIP_NOTIFY) { - /* We do not support out-of-dialog NOTIFY either, - like voicemail notification, so cancel that early */ - transmit_response_using_temp(callid, sin, 1, intended_method, req, "489 Bad event"); } else { /* Ok, time to create a new SIP dialog object, a pvt */ if ((p = sip_alloc(callid, sin, 1, intended_method, req))) { @@ -19247,6 +19244,69 @@ return NULL; } +/*! \brief Parse the NOTIFY SIP request body to extract MWI related parameters */ +static int get_mwi_parameters(struct sip_request *req, int* messages_waiting, int* new_voicemail_messages, int* old_voicemail_messages, int* new_urgent_voicemail_messages, int* old_urgent_voicemail_messages) +{ + int response_code = 400; /* Bad request*/ + char *c; + + /*Example: Messages-Waiting: yes [no] */ + c = ast_strdupa(get_body(req, "Messages-Waiting", ':')); + + if (!ast_strlen_zero(c)) { + if (ast_true(c)) { + *messages_waiting = 1; + *new_voicemail_messages = 1; + response_code = 200; + } else if (ast_false(c)) { + *messages_waiting = 0; + response_code = 200; + } + + if (sipdebug) + ast_debug(2, "messages_waiting=%d, new_voicemail_messages=%d, response_code=%d\n", + *messages_waiting, *new_voicemail_messages, response_code); + } + + + /*Example: Voice-Message: 1/3 */ + /*Example (with urgent messages): Voice-Message: 1/3 (0/1)*/ + c = ast_strdupa(get_body(req, "Voice-Message", ':')); + + if (!ast_strlen_zero(c)) { + char* delimiter; + if( (delimiter = strchr(c, '/')) ) { + char new_voice_messages[10]=""; + strncpy(new_voice_messages, c, (delimiter - c) - 1); + *new_voicemail_messages = atoi(new_voice_messages); + *messages_waiting = (new_voicemail_messages) ? 1 : 0; + response_code = 200; + + char* delimiter2; + if( (delimiter2 = strchr(delimiter, '(')) ) { + char old_voice_messages[10]=""; + strncpy(old_voice_messages, delimiter, (delimiter2 - delimiter) - 1); + *old_voicemail_messages = atoi(old_voice_messages); + + char* delimiter3; + if( (delimiter3 = strchr(delimiter2, '/')) ) { + char new_urgent_voice_messages[10]=""; + strncpy(new_urgent_voice_messages, delimiter2, (delimiter3 - delimiter2) - 1); + *new_urgent_voicemail_messages = atoi(new_urgent_voice_messages); + + char* delimiter4; + if( (delimiter4 = strchr(delimiter3, ')')) ) { + char old_urgent_voice_messages[10]=""; + strncpy(old_urgent_voice_messages, delimiter3, (delimiter4 - delimiter3) - 1); + *old_urgent_voicemail_messages = atoi(old_urgent_voice_messages); + } + } + } + } + } + return response_code; +} + /*! \brief Handle incoming notifications */ static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, const char *e) { @@ -19369,25 +19429,148 @@ } /* Confirm that we received this packet */ transmit_response(p, "200 OK", req); - } else if (p->mwi && !strcmp(event, "message-summary")) { - char *c = ast_strdupa(get_body(req, "Voice-Message", ':')); - if (!ast_strlen_zero(c)) { - char *old = strsep(&c, " "); - char *new = strsep(&old, "/"); - struct ast_event *event; - - if ((event = ast_event_new(AST_EVENT_MWI, - AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, p->mwi->mailbox, - AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, "SIP_Remote", - AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, atoi(new), - AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, atoi(old), - AST_EVENT_IE_END))) { - ast_event_queue_and_cache(event); + } else if (!strcmp(event, "message-summary")) { + if (p->mwi) { + char *c = ast_strdupa(get_body(req, "Voice-Message", ':')); + + if (!ast_strlen_zero(c)) { + char *old = strsep(&c, " "); + char *new = strsep(&old, "/"); + struct ast_event *event; + + if ((event = ast_event_new(AST_EVENT_MWI, + AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, p->mwi->mailbox, + AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, "SIP_Remote", + AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, atoi(new), + AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, atoi(old), + AST_EVENT_IE_END))) { + ast_event_queue_and_cache(event); + } + } + + transmit_response(p, "200 OK", req); + + } else { + + int response_code = 489; /* Bad event*/ + int messages_waiting = 0; + int new_voicemail_messages = 0; + int old_voicemail_messages = 0; + int new_urgent_voicemail_messages = 0; + int old_urgent_voicemail_messages = 0; + + const char *Content_Type; + Content_Type = get_header(req, "Content-Type"); + if (!strcasecmp(Content_Type, "application/simple-message-summary")) { + response_code = get_mwi_parameters(req, &messages_waiting, &new_voicemail_messages, &old_voicemail_messages, &new_urgent_voicemail_messages, &old_urgent_voicemail_messages); + } + + if (sipdebug) + ast_debug(2, "Processing : %s, Content-Type: %s, messages_waiting=%d, new_voicemail_messages=%d, old_voicemail_messages=%d\n", + event,Content_Type,messages_waiting,new_voicemail_messages,old_voicemail_messages); + + if (sipdebug) + ast_debug(2, "Processing : %s, response_code=%d\n", event,response_code); + + if(response_code == 200) { + struct sip_peer *peer; + struct sip_pvt *pvt = NULL; + + char* header_value; + char to[256]; + char peername[50]; + ast_copy_string(to, get_header(req, "To"), sizeof(to)); + + if(!ast_strlen_zero(to)) { + header_value = to+3; + memset(peername, 0, sizeof(peername)); + get_calleridname(to, peername, sizeof(peername)); + + if(!strlen(peername)) { + char* peer_start; + if( (peer_start = strstr(to,"sips:")) ) { + peer_start += 5; + } else if( (peer_start = strstr(to,"sip:")) ) { + peer_start += 4; + } + + if(peer_start) { + char* peer_end; + if( (peer_end = strstr(peer_start,"@")) ) { + strncpy(peername,peer_start,(peer_end-peer_start)); + } + } + } + } + + if (sipdebug) + ast_debug(2, "Finding peer for : %s\n", peername); + + peer = find_peer(peername, NULL, TRUE, FINDALLDEVICES, FALSE); + /* Found the peer and it does not have an active suncription */ + if (peer && !peer->mwipvt) { + res = -1; + response_code = 500; + /* Build temporary dialog for this message*/ + if ((pvt = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL))) { + if (!create_addr_from_peer(pvt, peer)) { + /* Recalculate our side, and recalculate Call ID*/ + ast_sip_ouraddrfor(&pvt->sa.sin_addr, &pvt->ourip, pvt); + build_via(pvt); + build_callid_pvt(pvt); + /* Destroy this session after 32 secs*/ + sip_scheddestroy(pvt, DEFAULT_TRANS_TIMEOUT); + + res = 0; + response_code = 200; + } + else { + /* Maybe they're not registered, etc.*/ + sip_destroy(pvt); + } + } + } + + if(response_code == 200) { + /* Send MWI NOTIFY*/ + ast_set_flag(&pvt->flags[0], SIP_OUTGOING); + transmit_notify_with_mwi(pvt, new_voicemail_messages, old_voicemail_messages, peer->vmexten); + } else { + if (sipdebug) + ast_debug(2, "NOTIFY not sent, response_code=%d\n", response_code); + } + } + + char response_str[255]; + switch(response_code) { + case 400: + ast_copy_string(response_str,"400 Bad Request Asterisk",255); + break; + case 404: + ast_copy_string(response_str,"404 Not Found",255); + break; + case 500: + ast_copy_string(response_str,"500 Internal Server Error",255); + break; + case 200: + ast_copy_string(response_str,"200 OK",255); + break; + case 489: + default: + ast_copy_string(response_str,"489 Bad Event",255); + break; + } + + if (sipdebug) + ast_debug(2, "Responding to incoming NOTIFY with %d\n",response_code); + + transmit_response(p, (const char*)response_str, req); + if(res == 0) { + res = (response_code != 200) ? -1 : 0; } } - transmit_response(p, "200 OK", req); } else { /* We don't understand this event. */ transmit_response(p, "489 Bad event", req);