Fix SIP INFO DTMF handling for non-numeric codes
[asterisk/asterisk.git] / channels / chan_sip.c
index d6ffa8a..df14b22 100644 (file)
@@ -19434,7 +19434,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 */
@@ -19443,92 +19444,55 @@ 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) {
                                ast_verbose("* DTMF-relay event received: FLASH\n");
@@ -19544,9 +19508,6 @@ 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);
@@ -19556,7 +19517,6 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
                }
                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) {