From: Matthew Jordan Date: Thu, 9 Feb 2012 16:30:56 +0000 (+0000) Subject: Fix SIP INFO DTMF handling for non-numeric codes X-Git-Tag: 1.8.11.0-rc1~56 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ead2b479076aba39c538203b6aa83826c5a4366e;p=thirdparty%2Fasterisk.git Fix SIP INFO DTMF handling for non-numeric codes In ASTERISK-18924, SIP INFO DTMF handlingw as changed to account for both lowercase alphatbetic DTMF events, as well as uppercase alphabetic DTMF events. When this occurred, the comparison of the character buffer containing the event code was changed such that the buffer was first compared again '0' and '9' to determine if it was numeric. Unfortunately, since the first character in the buffer will typically be '1' in the case of non-numeric event codes (10-16), this caused those codes to be converted to a DTMF event of '1'. This patch fixes that, and cleans up handling of both application/dtmf-relay and application/dtmf content types. Review: https://reviewboard.asterisk.org/r/1722/ (closes issue ASTERISK-19290) Reported by: Ira Emus Tested by: mjordan git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@354542 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 4c7b218307..4dda9d5c0f 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -18714,7 +18714,8 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req) /* Need to check the media/type */ if (!strcasecmp(c, "application/dtmf-relay") || - !strcasecmp(c, "application/vnd.nortelnetworks.digits")) { + !strcasecmp(c, "application/vnd.nortelnetworks.digits") || + !strcasecmp(c, "application/dtmf")) { unsigned int duration = 0; if (!p->owner) { /* not a PBX call */ @@ -18723,91 +18724,59 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req) return; } - /* Try getting the "signal=" part */ - if (ast_strlen_zero(c = get_body(req, "Signal", '=')) && ast_strlen_zero(c = get_body(req, "d", '='))) { - ast_log(LOG_WARNING, "Unable to retrieve DTMF signal from INFO message from %s\n", p->callid); - transmit_response(p, "200 OK", req); /* Should return error */ - return; - } else { - ast_copy_string(buf, c, sizeof(buf)); - } + /* If dtmf-relay or vnd.nortelnetworks.digits, parse the signal and duration; otherwise use the body as the signal */ + if (strcasecmp(c, "application/dtmf")) { + const char *msg_body; - if (!ast_strlen_zero((c = get_body(req, "Duration", '=')))) - duration = atoi(c); - if (!duration) - duration = 100; /* 100 ms */ + if (ast_strlen_zero(msg_body = get_body(req, "Signal", '=')) && ast_strlen_zero(msg_body = get_body(req, "d", '='))) { + ast_log(LOG_WARNING, "Unable to retrieve DTMF signal for INFO message on call %s\n", p->callid); + transmit_response(p, "200 OK", req); + return; + } else { + ast_copy_string(buf, msg_body, sizeof(buf)); + } + if (!ast_strlen_zero((msg_body = get_body(req, "Duration", '=')))) { + sscanf(msg_body, "%30u", &duration); + } + } else { + /* Type is application/dtmf, simply use what's in the message body */ + get_msg_text(buf, sizeof(buf), req); + } + /* An empty message body requires us to send a 200 OK */ if (ast_strlen_zero(buf)) { transmit_response(p, "200 OK", req); return; } - if ('0' <= buf[0] && buf[0] <= '9') { - event = buf[0] - '0'; - } else if (buf[0] == '*') { + if (!duration) { + duration = 100; /* 100 ms */ + } + + if (buf[0] == '*') { event = 10; } else if (buf[0] == '#') { event = 11; + } else if (buf[0] == '!') { + event = 16; } else if ('A' <= buf[0] && buf[0] <= 'D') { event = 12 + buf[0] - 'A'; } else if ('a' <= buf[0] && buf[0] <= 'd') { event = 12 + buf[0] - 'a'; - } else if (buf[0] == '!') { - event = 16; - } else { - /* Unknown digit */ - event = 0; - } - if (event == 16) { - /* send a FLASH event */ - struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_FLASH, } }; - ast_queue_frame(p->owner, &f); - if (sipdebug) - ast_verbose("* DTMF-relay event received: FLASH\n"); - } else { - /* send a DTMF event */ - struct ast_frame f = { AST_FRAME_DTMF, }; - if (event < 10) { - f.subclass.integer = '0' + event; - } else if (event == 10) { - f.subclass.integer = '*'; - } else if (event == 11) { - f.subclass.integer = '#'; - } else if (event < 16) { - f.subclass.integer = 'A' + (event - 12); - } - f.len = duration; - ast_queue_frame(p->owner, &f); - if (sipdebug) - ast_verbose("* DTMF-relay event received: %c\n", (int) f.subclass.integer); - } - transmit_response(p, "200 OK", req); - return; - } else if (!strcasecmp(c, "application/dtmf")) { - /*! \todo Note: Doesn't read the duration of the DTMF. Should be fixed. */ - unsigned int duration = 0; - - if (!p->owner) { /* not a PBX call */ - transmit_response(p, "481 Call leg/transaction does not exist", req); - sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); - return; - } - - get_msg_text(buf, sizeof(buf), req); - duration = 100; /* 100 ms */ - - if (ast_strlen_zero(buf)) { + } else if ((sscanf(buf, "%30u", &event) != 1) || event > 16) { + ast_log(AST_LOG_WARNING, "Unable to convert DTMF event signal code to a valid value for INFO message on call %s\n", p->callid); transmit_response(p, "200 OK", req); return; } - event = atoi(buf); + if (event == 16) { /* send a FLASH event */ - struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_FLASH }, }; + struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_FLASH, } }; ast_queue_frame(p->owner, &f); - if (sipdebug) + if (sipdebug) { ast_verbose("* DTMF-relay event received: FLASH\n"); + } } else { /* send a DTMF event */ struct ast_frame f = { AST_FRAME_DTMF, }; @@ -18819,18 +18788,15 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req) f.subclass.integer = '#'; } else if (event < 16) { f.subclass.integer = 'A' + (event - 12); - } else { - /* Unknown digit. */ - f.subclass.integer = '0'; } f.len = duration; ast_queue_frame(p->owner, &f); - if (sipdebug) + if (sipdebug) { ast_verbose("* DTMF-relay event received: %c\n", (int) f.subclass.integer); + } } transmit_response(p, "200 OK", req); return; - } else if (!strcasecmp(c, "application/media_control+xml")) { /* Eh, we'll just assume it's a fast picture update for now */ if (p->owner)