<p>B. Martin has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/8801">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">chan_mobile: support handling of caller-id names ("cnam").<br><br>ASTERISK-27726<br>-<br>Add support to handle caller-ID names ("cnam") in addition to caller-ID<br>numbers.  The prior code ignored the caller-ID name altogether, and<br>used the local name for the cell phone (e.g. "my-iphone") in its place.<br>-<br>Note: as of this writing, at least some Android phones don't pass cnam to<br>us. This can be seen by issuing "core set debug 2" in the CLI and watching<br>the "CLIP" record when a call comes in.  If cnam isn't in the CLIP record,<br>there's nothing we can do to provide one.  We'll provide a null cnam field,<br>so later Asterisk processes know to try other sources (e.g. cidname database,<br>OpenCNAM, etc.).<br><br>Reported by: Brian Martin<br>Tested by: Brian Martin<br><br>Change-Id: I89490d85fa406c36261879c50ae5e65595538ba5<br>---<br>M addons/chan_mobile.c<br>1 file changed, 109 insertions(+), 36 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/01/8801/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/addons/chan_mobile.c b/addons/chan_mobile.c<br>index 04d4047..af59a2d 100644<br>--- a/addons/chan_mobile.c<br>+++ b/addons/chan_mobile.c<br>@@ -58,6 +58,7 @@<br> <br> #include "asterisk/compat.h"<br> #include "asterisk/lock.h"<br>+#include "asterisk/callerid.h"<br> #include "asterisk/channel.h"<br> #include "asterisk/config.h"<br> #include "asterisk/logger.h"<br>@@ -162,6 +163,10 @@<br> <br>       AST_LIST_ENTRY(mbl_pvt) entry;<br> };<br>+struct cidinfo {                  /* Structure used by hfp_parse_clip to return two items */<br>+   char *cnum;<br>+  char *cnam;<br>+};<br> <br> static AST_RWLIST_HEAD_STATIC(devices, mbl_pvt);<br> <br>@@ -208,7 +213,7 @@<br> "  Dest - destination\n"<br> "  Message - text of the message\n";<br> <br>-static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num,<br>+static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, struct cidinfo *cidinfo,<br>             const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor);<br> static struct ast_channel *mbl_request(const char *type, struct ast_format_cap *cap,<br>              const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);<br>@@ -364,7 +369,8 @@<br> <br> <br> static int hfp_parse_ciev(struct hfp_pvt *hfp, char *buf, int *value);<br>-static char *hfp_parse_clip(struct hfp_pvt *hfp, char *buf);<br>+static struct cidinfo hfp_parse_clip(struct hfp_pvt *hfp, char *buf);<br>+static int parse_next_token(char string[], const int start, const char delim);<br> static int hfp_parse_cmti(struct hfp_pvt *hfp, char *buf);<br> static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, char **text);<br> static int hfp_parse_brsf(struct hfp_pvt *hfp, const char *buf);<br>@@ -699,6 +705,7 @@<br>        return CLI_SUCCESS;<br> }<br> <br>+   <br> /*<br> <br>      Dialplan applications implementation<br>@@ -837,10 +844,11 @@<br> <br> */<br> <br>-static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num,<br>+static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, struct cidinfo *cidinfo,<br>              const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)<br> {<br>  struct ast_channel *chn;<br>+     struct cidinfo localcid;<br> <br>   pvt->answered = 0;<br>         pvt->alignment_count = 0;<br>@@ -853,7 +861,19 @@<br>    ast_smoother_reset(pvt->smoother, DEVICE_FRAME_SIZE);<br>      ast_dsp_digitreset(pvt->dsp);<br> <br>-  chn = ast_channel_alloc(1, state, cid_num, pvt->id, 0, 0, pvt->context,<br>+        if (cidinfo == NULL) {<br>+               /* Null pointer.  Dummy up CID info.  */<br>+             localcid.cnam = '\0';<br>+                localcid.cnum = '\0';<br>+        }<br>+    else<br>+ {<br>+            /* Valid CID info */<br>+         localcid.cnum = cidinfo->cnum;<br>+            localcid.cnam = cidinfo->cnam;<br>+    }<br>+<br>+ chn = ast_channel_alloc(1, state, localcid.cnum, localcid.cnam, 0, 0, pvt->context,<br>                        assignedids, requestor, 0,<br>                    "Mobile/%s-%04lx", pvt->id, ast_random() & 0xffff);<br>  if (!chn) {<br>@@ -2203,45 +2223,97 @@<br>  * \param hfp an hfp_pvt struct<br>  * \param buf the buffer to parse (null terminated)<br>  * \note buf will be modified when the CID string is parsed<br>- * \return NULL on error (parse error) or a pointer to the caller id<br>- * information in buf<br>+ * \return a cidinfo structure pointing to the cnam and cnum<br>+ * \data in buf.  On parse errors, either or both pointers <br>+ * \will point to null strings<br>  */<br>-static char *hfp_parse_clip(struct hfp_pvt *hfp, char *buf)<br>+static struct cidinfo hfp_parse_clip(struct hfp_pvt *hfp, char *buf)<br> {<br>-       int i, state;<br>-        char *clip = NULL;<br>-   size_t s;<br>+    int i;<br>+       int tokens[6];<br>+       char *cnamtmp;<br>+       char delim = ' ';       /* First token terminates with space */<br>+      int invalid = 0;        /* Number of invalid chars in cnam */<br>+        struct cidinfo cidinfo = {NULL,NULL};<br> <br>      /* parse clip info in the following format:<br>    * +CLIP: "123456789",128,...<br>        */<br>-  state = 0;<br>-   s = strlen(buf);<br>-     for (i = 0; i < s && state != 3; i++) {<br>-           switch (state) {<br>-             case 0: /* search for start of the number (") */<br>-                        if (buf[i] == '"') {<br>-                            state++;<br>-                     }<br>-                    break;<br>-               case 1: /* mark the number */<br>-                        clip = &buf[i];<br>-                  state++;<br>-                     /* fall through */<br>-           case 2: /* search for the end of the number (") */<br>-                      if (buf[i] == '"') {<br>-                            buf[i] = '\0';<br>-                               state++;<br>-                     }<br>-                    break;<br>+       ast_debug(3, "[%s] hfp_parse_clip is processing \"%s\"\n", hfp->owner->id, buf);<br>+   tokens[0]=0;            /* First token starts in position 0 */<br>+       for (i = 1; i < 6; i++) {<br>+         tokens[i] = parse_next_token(buf,tokens[i-1],delim);<br>+         delim = ',';    /* Subsequent tokens terminate with comma */<br>+ }<br>+    ast_debug(3, "[%s] hfp_parse_clip found tokens: 0=%s, 1=%s, 2=%s, 3=%s, 4=%s, 5=%s\n",<br>+             hfp->owner->id, &buf[tokens[0]], &buf[tokens[1]], &buf[tokens[2]], &buf[tokens[3]],<br>+            &buf[tokens[4]], &buf[tokens[5]]);<br>+<br>+        /* Clean up cnum, and make sure it is legitimate since it is untrusted. */<br>+   cidinfo.cnum = &buf[tokens[1]];<br>+  ast_strip_quoted(cidinfo.cnum, "\"", "\"");<br>+    if (*cidinfo.cnum == '"') {cidinfo.cnum++;};       /* ast_strip_quoted leaves leading quote symbol */<br>+   if (!(ast_isphonenumber(cidinfo.cnum))) {<br>+            ast_debug(1, "[%s] hfp_parse_clip invalid cidinfo.cnum data \"%s\" - deleting\n", hfp->owner->id, cidinfo.cnum);<br>+           cidinfo.cnum="";<br>+   }<br>+<br>+ /* Some docs say tokens 2 and 3 including the commas are optional.  If absent, that would move CNAM <br>+ back to token 3. */<br>+  cidinfo.cnam = &buf[tokens[5]];     /* Assume it's in token 5 */<br>+     if (buf[tokens[5]] == '\0' && buf[tokens[4]] == '\0') {<br>+              /* Tokens 4 and 5 are empty.  See if token 3 looks like CNAM (starts with ") */<br>+         i = tokens[3];<br>+               while (buf[i] == ' ') {i++;};   /* Find the first non-blank */<br>+               if (buf[i] == '"') {<br>+                    /* Starts with quote.  Use this for CNAM. */<br>+                 cidinfo.cnam = &buf[i];<br>           }<br>     }<br> <br>- if (state != 3) {<br>-            return NULL;<br>+ /* Clean up CNAM. */<br>+ ast_strip_quoted(cidinfo.cnam, "\"", "\"");<br>+    if (*cidinfo.cnam == '"') {cidinfo.cnam++;};       /* ast_strip_quoted leaves leading quote symbol */<br>+   for (cnamtmp = cidinfo.cnam; *cnamtmp != '\0'; cnamtmp++) {<br>+                if (!strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789-,abcdefghijklmnopqrstuvwxyz_", *cnamtmp)) {<br>+                       *cnamtmp = '_'; /* Invalid.  Replace with underscore. */<br>+                     invalid++;<br>+           }<br>     }<br>+    if (invalid) {<br>+               ast_debug(2, "[%s] hfp_parse_clip replaced %d invalid byte(s) in cnam data\n", hfp->owner->id, invalid);<br>+     }<br>+    ast_debug(2, "[%s] hfp_parse_clip returns cnum=%s and cnam=%s\n", hfp->owner->id, cidinfo.cnum, cidinfo.cnam);<br> <br>-    return clip;<br>+ return cidinfo;<br>+}<br>+<br>+/*!<br>+ * \brief Terminate current token and return an index to start of the next token.<br>+ * \param string - the null-terminated string being parsed (will be altered!)<br>+ * \param start - where the current token starts<br>+ * \delip - the token termination delimiter.  \0 is also considered a terminator.<br>+ * \retval index of the next token.  May be the same as this token if the string is exhausted.<br>+ */<br>+static int parse_next_token(char string[], const int start, const char delim)<br>+{<br>+   int index;<br>+   int quoting = 0;<br>+     for (index=start; string[index] != 0; index++) {<br>+             if ((string[index] == delim) && !quoting ) {<br>+                 /* Found the delimiter, outside of quotes.  This is the end of the token. */<br>+                 string[index]='\0';     /* Terminate this token. */<br>+                  index++;                /* Point the index to the start of the next token. */<br>+                        break;                  /* We're done. */<br>+                } else if (string[index] == '"' && !quoting) {<br>+                  /* Found a beginning quote mark.  Remember it. */<br>+                    quoting = 1;<br>+         } else if (string[index] == '"' ) {<br>+                     /* Found the end quote mark. */<br>+                      quoting = 0;<br>+         }<br>+    }<br>+    return index;<br> }<br> <br> /*!<br>@@ -3578,19 +3650,20 @@<br>  */<br> static int handle_response_clip(struct mbl_pvt *pvt, char *buf)<br> {<br>-      char *clip;<br>   struct msg_queue_entry *msg;<br>  struct ast_channel *chan;<br>+    struct cidinfo cidinfo;<br> <br>    if ((msg = msg_queue_head(pvt)) && msg->expected == AT_CLIP) {<br>             msg_queue_free_and_pop(pvt);<br> <br>               pvt->needcallerid = 0;<br>-            if (!(clip = hfp_parse_clip(pvt->hfp, buf))) {<br>+            cidinfo = hfp_parse_clip(pvt->hfp, buf);<br>+          if (!cidinfo.cnum) {<br>                  ast_debug(1, "[%s] error parsing CLIP: %s\n", pvt->id, buf);<br>             }<br> <br>-         if (!(chan = mbl_new(AST_STATE_RING, pvt, clip, NULL, NULL))) {<br>+              if (!(chan = mbl_new(AST_STATE_RING, pvt, &cidinfo, NULL, NULL))) {<br>                       ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);<br>                      hfp_send_chup(pvt->hfp);<br>                   msg_queue_push(pvt, AT_OK, AT_CHUP);<br>@@ -3859,7 +3932,7 @@<br>                   break;<br>                }<br> <br>-         ast_debug(1, "[%s] %s\n", pvt->id, buf);<br>+                ast_debug(1, "[%s] read %s\n", pvt->id, buf);<br> <br>                 switch (at_msg) {<br>             case AT_BRSF:<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/8801">change 8801</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/8801"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 13 </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I89490d85fa406c36261879c50ae5e65595538ba5 </div>
<div style="display:none"> Gerrit-Change-Number: 8801 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: B. Martin <asterisk-forum@silverflash.net> </div>