<p>Friendly Automation <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/14513">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Benjamin Keith Ford: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved
  Friendly Automation: Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">manager - Add Content-Type parameter to the SendText action<br><br>This patch allows a user of AMI to now specify the type of message<br>content contained within by setting the 'Content-Type' parameter.<br><br>Note, the AMI version has been bumped for this change.<br><br>ASTERISK-28945 #close<br><br>Change-Id: Ibb5315702532c6b954e1498beddc8855fabdf4bb<br>---<br>A doc/CHANGES-staging/ami_sendtext_content_type.txt<br>M include/asterisk/frame.h<br>M include/asterisk/manager.h<br>M include/asterisk/message.h<br>M main/channel.c<br>M main/manager.c<br>M main/message.c<br>7 files changed, 158 insertions(+), 21 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/doc/CHANGES-staging/ami_sendtext_content_type.txt b/doc/CHANGES-staging/ami_sendtext_content_type.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..45037ff</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/ami_sendtext_content_type.txt</span><br><span>@@ -0,0 +1,4 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: AMI</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+You can now specify an optional 'Content-Type' as an argument for the Asterisk</span><br><span style="color: hsl(120, 100%, 40%);">+SendText manager action.</span><br><span>diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h</span><br><span>index dd59c6b..116ff99 100644</span><br><span>--- a/include/asterisk/frame.h</span><br><span>+++ b/include/asterisk/frame.h</span><br><span>@@ -335,9 +335,16 @@</span><br><span>         AST_CONTROL_RECORD_MUTE = 1103, /*!< Indicated to a channel in record to mute/unmute (i.e. write silence) recording */</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Actions to indicate to, and be handled on channel read</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * The subtype to specify for an AST_CONTROL_READ_ACTION frame. These</span><br><span style="color: hsl(120, 100%, 40%);">+ * frames are then to be enacted on within a channel's read thread.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span> enum ast_frame_read_action {</span><br><span>  AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO,</span><br><span>  AST_FRAME_READ_ACTION_SEND_TEXT,</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_FRAME_READ_ACTION_SEND_TEXT_DATA,</span><br><span> };</span><br><span> </span><br><span> struct ast_control_read_action_payload {</span><br><span>diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h</span><br><span>index 72a667d..910eb5d 100644</span><br><span>--- a/include/asterisk/manager.h</span><br><span>+++ b/include/asterisk/manager.h</span><br><span>@@ -54,7 +54,7 @@</span><br><span> - \ref manager.c Main manager code file</span><br><span>  */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#define AMI_VERSION                     "5.0.1"</span><br><span style="color: hsl(120, 100%, 40%);">+#define AMI_VERSION                     "5.0.2"</span><br><span> #define DEFAULT_MANAGER_PORT 5038     /* Default port for Asterisk management via TCP */</span><br><span> #define DEFAULT_MANAGER_TLS_PORT 5039     /* Default port for Asterisk management via TCP */</span><br><span> </span><br><span>diff --git a/include/asterisk/message.h b/include/asterisk/message.h</span><br><span>index 826fa0a..72ccd96 100644</span><br><span>--- a/include/asterisk/message.h</span><br><span>+++ b/include/asterisk/message.h</span><br><span>@@ -467,6 +467,24 @@</span><br><span>   struct ast_msg_data_attribute attributes[], size_t count);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Allocates an ast_msg_data structure.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.35.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.12.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 17.6.0</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param source The source type of the message</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param to Where the message is sent to</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param from Where the message is sent from</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param content_type Content type of the body</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param body The message body</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return Pointer to msg structure or NULL on allocation failure.</span><br><span style="color: hsl(120, 100%, 40%);">+ *         Caller must call ast_free when done.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_msg_data *ast_msg_data_alloc2(enum ast_msg_data_source_type source_type,</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *to, const char *from, const char *content_type, const char *body);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Clone an ast_msg_data structure</span><br><span>  * \since 13.22.0</span><br><span>  * \since 15.5.0</span><br><span>diff --git a/main/channel.c b/main/channel.c</span><br><span>index 3390917..92b6b06 100644</span><br><span>--- a/main/channel.c</span><br><span>+++ b/main/channel.c</span><br><span>@@ -3847,7 +3847,12 @@</span><br><span>                                    break;</span><br><span>                               case AST_FRAME_READ_ACTION_SEND_TEXT:</span><br><span>                                        ast_channel_unlock(chan);</span><br><span style="color: hsl(0, 100%, 40%);">-                                       ast_sendtext(chan, (const char *) read_action_payload->payload);</span><br><span style="color: hsl(120, 100%, 40%);">+                                   ast_sendtext(chan, (const char *)read_action_payload->payload);</span><br><span style="color: hsl(120, 100%, 40%);">+                                    ast_channel_lock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+                                       break;</span><br><span style="color: hsl(120, 100%, 40%);">+                                case AST_FRAME_READ_ACTION_SEND_TEXT_DATA:</span><br><span style="color: hsl(120, 100%, 40%);">+                                    ast_channel_unlock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+                                     ast_sendtext_data(chan, (struct ast_msg_data *)read_action_payload->payload);</span><br><span>                                     ast_channel_lock(chan);</span><br><span>                                      break;</span><br><span>                               }</span><br><span>diff --git a/main/manager.c b/main/manager.c</span><br><span>index 1963151..7f8dc0f 100644</span><br><span>--- a/main/manager.c</span><br><span>+++ b/main/manager.c</span><br><span>@@ -100,6 +100,7 @@</span><br><span> #include "asterisk/format_cache.h"</span><br><span> #include "asterisk/translate.h"</span><br><span> #include "asterisk/taskprocessor.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/message.h"</span><br><span> </span><br><span> /*** DOCUMENTATION</span><br><span>        <manager name="Ping" language="en_US"></span><br><span>@@ -873,7 +874,8 @@</span><br><span>       </manager></span><br><span>     <manager name="SendText" language="en_US"></span><br><span>                 <synopsis></span><br><span style="color: hsl(0, 100%, 40%);">-                        Send text message to channel.</span><br><span style="color: hsl(120, 100%, 40%);">+                 Sends a text message to channel. A content type can be optionally specified. If not set</span><br><span style="color: hsl(120, 100%, 40%);">+                       it is set to an empty string allowing a custom handler to default it as it sees fit.</span><br><span>                 </synopsis></span><br><span>            <syntax></span><br><span>                       <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" /></span><br><span>@@ -883,10 +885,16 @@</span><br><span>                  <parameter name="Message" required="true"></span><br><span>                                 <para>Message to send.</para></span><br><span>                    </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+                    <parameter name="Content-Type" required="false" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+                               <para>The type of content in the message</para></span><br><span style="color: hsl(120, 100%, 40%);">+                   </parameter></span><br><span>           </syntax></span><br><span>              <description></span><br><span>                  <para>Sends A Text Message to a channel while in a call.</para></span><br><span>          </description></span><br><span style="color: hsl(120, 100%, 40%);">+          <see-also></span><br><span style="color: hsl(120, 100%, 40%);">+                      <ref type="application">SendText</ref></span><br><span style="color: hsl(120, 100%, 40%);">+          </see-also></span><br><span>    </manager></span><br><span>     <manager name="UserEvent" language="en_US"></span><br><span>                <synopsis></span><br><span>@@ -4836,14 +4844,92 @@</span><br><span>   return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Queue a given read action containing a payload onto a channel</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This queues a READ_ACTION control frame that contains a given "payload", or</span><br><span style="color: hsl(120, 100%, 40%);">+ * data to be triggered and handled on the channel's read side. This ensures</span><br><span style="color: hsl(120, 100%, 40%);">+ * the "action" is handled by the channel's media reading thread.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param chan The channel to queue the action on</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param payload The read action's payload</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param payload_size The size of the given payload</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param action The type of read action to queue</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return -1 on error, 0 on success</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int queue_read_action_payload(struct ast_channel *chan, const unsigned char *payload,</span><br><span style="color: hsl(120, 100%, 40%);">+       size_t payload_size, enum ast_frame_read_action action)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_control_read_action_payload *obj;</span><br><span style="color: hsl(120, 100%, 40%);">+  size_t obj_size;</span><br><span style="color: hsl(120, 100%, 40%);">+      int res;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    obj_size = payload_size + sizeof(*obj);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     obj = ast_malloc(obj_size);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!obj) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   obj->action = action;</span><br><span style="color: hsl(120, 100%, 40%);">+      obj->payload_size = payload_size;</span><br><span style="color: hsl(120, 100%, 40%);">+  memcpy(obj->payload, payload, payload_size);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     res = ast_queue_control_data(chan, AST_CONTROL_READ_ACTION, obj, obj_size);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(obj);</span><br><span style="color: hsl(120, 100%, 40%);">+        return res;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Queue a read action to send a text message</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param chan The channel to queue the action on</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param body The body of the message</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return -1 on error, 0 on success</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int queue_sendtext(struct ast_channel *chan, const char *body)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return queue_read_action_payload(chan, (const unsigned char *)body,</span><br><span style="color: hsl(120, 100%, 40%);">+           strlen(body) + 1, AST_FRAME_READ_ACTION_SEND_TEXT);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Queue a read action to send a text data message</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param chan The channel to queue the action on</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param body The body of the message</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param content_type The message's content type</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return -1 on error, 0 on success</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int queue_sendtext_data(struct ast_channel *chan, const char *body,</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *content_type)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  int res;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_msg_data *obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   obj = ast_msg_data_alloc2(AST_MSG_DATA_SOURCE_TYPE_UNKNOWN,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   NULL, NULL, content_type, body);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!obj) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   res = queue_read_action_payload(chan, (const unsigned char *)obj,</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_msg_data_get_length(obj), AST_FRAME_READ_ACTION_SEND_TEXT_DATA);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_free(obj);</span><br><span style="color: hsl(120, 100%, 40%);">+        return res;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int action_sendtext(struct mansession *s, const struct message *m)</span><br><span> {</span><br><span>   struct ast_channel *c;</span><br><span>       const char *name = astman_get_header(m, "Channel");</span><br><span>        const char *textmsg = astman_get_header(m, "Message");</span><br><span style="color: hsl(0, 100%, 40%);">-        struct ast_control_read_action_payload *frame_payload;</span><br><span style="color: hsl(0, 100%, 40%);">-  int payload_size;</span><br><span style="color: hsl(0, 100%, 40%);">-       int frame_size;</span><br><span style="color: hsl(120, 100%, 40%);">+       const char *content_type = astman_get_header(m, "Content-Type");</span><br><span>   int res;</span><br><span> </span><br><span>         if (ast_strlen_zero(name)) {</span><br><span>@@ -4862,22 +4948,13 @@</span><br><span>               return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   payload_size = strlen(textmsg) + 1;</span><br><span style="color: hsl(0, 100%, 40%);">-     frame_size = payload_size + sizeof(*frame_payload);</span><br><span style="color: hsl(120, 100%, 40%);">+   /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * If the "extra" data is not available, then send using "string" only.</span><br><span style="color: hsl(120, 100%, 40%);">+    * Doing such maintains backward compatibilities.</span><br><span style="color: hsl(120, 100%, 40%);">+      */</span><br><span style="color: hsl(120, 100%, 40%);">+   res = ast_strlen_zero(content_type) ? queue_sendtext(c, textmsg) :</span><br><span style="color: hsl(120, 100%, 40%);">+            queue_sendtext_data(c, textmsg, content_type);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      frame_payload = ast_malloc(frame_size);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!frame_payload) {</span><br><span style="color: hsl(0, 100%, 40%);">-           ast_channel_unref(c);</span><br><span style="color: hsl(0, 100%, 40%);">-           astman_send_error(s, m, "Failure");</span><br><span style="color: hsl(0, 100%, 40%);">-           return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       frame_payload->action = AST_FRAME_READ_ACTION_SEND_TEXT;</span><br><span style="color: hsl(0, 100%, 40%);">-     frame_payload->payload_size = payload_size;</span><br><span style="color: hsl(0, 100%, 40%);">-  memcpy(frame_payload->payload, textmsg, payload_size);</span><br><span style="color: hsl(0, 100%, 40%);">-       res = ast_queue_control_data(c, AST_CONTROL_READ_ACTION, frame_payload, frame_size);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    ast_free(frame_payload);</span><br><span>     ast_channel_unref(c);</span><br><span> </span><br><span>    if (res >= 0) {</span><br><span>diff --git a/main/message.c b/main/message.c</span><br><span>index 26b356d..d4cbd48 100644</span><br><span>--- a/main/message.c</span><br><span>+++ b/main/message.c</span><br><span>@@ -1416,6 +1416,32 @@</span><br><span>     return msg;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_msg_data *ast_msg_data_alloc2(enum ast_msg_data_source_type source_type,</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *to, const char *from, const char *content_type, const char *body)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_msg_data_attribute attrs[] =</span><br><span style="color: hsl(120, 100%, 40%);">+       {</span><br><span style="color: hsl(120, 100%, 40%);">+             {</span><br><span style="color: hsl(120, 100%, 40%);">+                     .type = AST_MSG_DATA_ATTR_TO,</span><br><span style="color: hsl(120, 100%, 40%);">+                 .value = (char *)S_OR(to, ""),</span><br><span style="color: hsl(120, 100%, 40%);">+              },</span><br><span style="color: hsl(120, 100%, 40%);">+            {</span><br><span style="color: hsl(120, 100%, 40%);">+                     .type = AST_MSG_DATA_ATTR_FROM,</span><br><span style="color: hsl(120, 100%, 40%);">+                       .value = (char *)S_OR(from, ""),</span><br><span style="color: hsl(120, 100%, 40%);">+            },</span><br><span style="color: hsl(120, 100%, 40%);">+            {</span><br><span style="color: hsl(120, 100%, 40%);">+                     .type = AST_MSG_DATA_ATTR_CONTENT_TYPE,</span><br><span style="color: hsl(120, 100%, 40%);">+                       .value = (char *)S_OR(content_type, ""),</span><br><span style="color: hsl(120, 100%, 40%);">+            },</span><br><span style="color: hsl(120, 100%, 40%);">+            {</span><br><span style="color: hsl(120, 100%, 40%);">+                     .type = AST_MSG_DATA_ATTR_BODY,</span><br><span style="color: hsl(120, 100%, 40%);">+                       .value = (char *)S_OR(body, ""),</span><br><span style="color: hsl(120, 100%, 40%);">+            },</span><br><span style="color: hsl(120, 100%, 40%);">+    };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return ast_msg_data_alloc(source_type, attrs, ARRAY_LEN(attrs));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct ast_msg_data *ast_msg_data_dup(struct ast_msg_data *msg)</span><br><span> {</span><br><span>        struct ast_msg_data *dest;</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/14513">change 14513</a>. To unsubscribe, or for help writing mail filters, 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/c/asterisk/+/14513"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: certified/16.8 </div>
<div style="display:none"> Gerrit-Change-Id: Ibb5315702532c6b954e1498beddc8855fabdf4bb </div>
<div style="display:none"> Gerrit-Change-Number: 14513 </div>
<div style="display:none"> Gerrit-PatchSet: 6 </div>
<div style="display:none"> Gerrit-Owner: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Benjamin Keith Ford <bford@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>