<p>Jenkins2 <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/8801">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Richard Mudgett: Looks good to me, but someone else must approve
  Kevin Harwell: Looks good to me, approved
  Jenkins2: Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">chan_mobile: support handling of caller-id names ("cnam").<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>ASTERISK-27726<br><br>Change-Id: I89490d85fa406c36261879c50ae5e65595538ba5<br>---<br>M addons/chan_mobile.c<br>1 file changed, 106 insertions(+), 40 deletions(-)<br><br></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..9d3ac79 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>@@ -163,6 +164,12 @@<br>     AST_LIST_ENTRY(mbl_pvt) entry;<br> };<br> <br>+/*! Structure used by hfp_parse_clip to return two items */<br>+struct cidinfo {<br>+      char *cnum;<br>+  char *cnam;<br>+};<br>+<br> static AST_RWLIST_HEAD_STATIC(devices, mbl_pvt);<br> <br> static int handle_response_ok(struct mbl_pvt *pvt, char *buf);<br>@@ -208,7 +215,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 +371,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>@@ -837,7 +845,7 @@<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>@@ -853,9 +861,11 @@<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>-                        assignedids, requestor, 0,<br>-                   "Mobile/%s-%04lx", pvt->id, ast_random() & 0xffff);<br>+ chn = ast_channel_alloc(1, state,<br>+            cidinfo ? cidinfo->cnum : NULL,<br>+           cidinfo ? cidinfo->cnam : NULL,<br>+           0, 0, pvt->context, assignedids, requestor, 0,<br>+            "Mobile/%s-%04lx", pvt->id, ast_random() & 0xffff);<br>  if (!chn) {<br>           goto e_return;<br>        }<br>@@ -2203,45 +2213,103 @@<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 < ARRAY_LEN(tokens); 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]],<br>+         &buf[tokens[3]], &buf[tokens[4]], &buf[tokens[5]]);<br>+<br>+   /* Clean up cnum, and make sure it is legitimate since it is untrusted. */<br>+   cidinfo.cnum = ast_strip_quoted(&buf[tokens[1]], "\"", "\"");<br>+      if (!ast_isphonenumber(cidinfo.cnum)) {<br>+              ast_debug(1, "[%s] hfp_parse_clip invalid cidinfo.cnum data \"%s\" - deleting\n",<br>+                        hfp->owner->id, cidinfo.cnum);<br>+         cidinfo.cnum = "";<br>+ }<br>+<br>+ /*<br>+    * Some docs say tokens 2 and 3 including the commas are optional.<br>+    * If absent, that would move CNAM back to token 3.<br>+   */<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] == ' ') {         /* Find the first non-blank */<br>+                       i++;<br>+         }<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>+ cidinfo.cnam = ast_strip_quoted(cidinfo.cnam, "\"", "\"");<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",<br>+                     hfp->owner->id, invalid);<br>+      }<br>+    ast_debug(2, "[%s] hfp_parse_clip returns cnum=%s and cnam=%s\n",<br>+          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>+ * \param delim the token termination delimiter.  \0 is also considered a terminator.<br>+ * \return index of the next token.  May be the same as this token if the string is<br>+ * 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>+<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 +3646,17 @@<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>-                    ast_debug(1, "[%s] error parsing CLIP: %s\n", pvt->id, buf);<br>-            }<br>+            cidinfo = hfp_parse_clip(pvt->hfp, buf);<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 +3925,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: merged </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: 3 </div>
<div style="display:none"> Gerrit-Owner: B. Martin <asterisk-forum@silverflash.net> </div>
<div style="display:none"> Gerrit-Reviewer: B. Martin <asterisk-forum@silverflash.net> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Richard Mudgett <rmudgett@digium.com> </div>