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

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_pjsip: Add AMI action 'PJSIPShowContacts'<br><br>Add an AMI action which provides information on all<br>configured Contacts.<br><br>ASTERISK-27581<br><br>Change-Id: I2eed42c74bbc725fad26b8b33b1a5b3161950c73<br>---<br>M res/res_pjsip.c<br>M res/res_pjsip/pjsip_options.c<br>2 files changed, 186 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/res/res_pjsip.c b/res/res_pjsip.c<br>index 0311dfd..1f65832 100644<br>--- a/res/res_pjsip.c<br>+++ b/res/res_pjsip.c<br>@@ -2362,6 +2362,77 @@<br>                  </syntax><br>               </managerEventInstance><br>         </managerEvent><br>+        <managerEvent language="en_US" name="ContactList"><br>+         <managerEventInstance class="EVENT_FLAG_COMMAND"><br>+                    <synopsis>Provide details about a contact section.</synopsis><br>+                    <syntax><br>+                               <parameter name="ObjectType"><br>+                                        <para>The object's type. This will always be 'contact'.</para><br>+                               </parameter><br>+                           <parameter name="ObjectName"><br>+                                        <para>The name of this object.</para><br>+                            </parameter><br>+                           <parameter name="ViaAddr"><br>+                                   <para>IP address of the last Via header in REGISTER request.<br>+                                   Will only appear in the event if available.</para><br>+                             </parameter><br>+                           <parameter name="ViaPort"><br>+                                   <para>Port number of the last Via header in REGISTER request.<br>+                                  Will only appear in the event if available.</para><br>+                             </parameter><br>+                           <parameter name="QualifyTimeout"><br>+                                    <para>The elapsed time in decimal seconds after which an OPTIONS<br>+                                       message is sent before the contact is considered unavailable.</para><br>+                           </parameter><br>+                           <parameter name="CallId"><br>+                                    <para>Content of the Call-ID header in REGISTER request.<br>+                                       Will only appear in the event if available.</para><br>+                             </parameter><br>+                           <parameter name="RegServer"><br>+                                 <para>Asterisk Server name.</para><br>+                               </parameter><br>+                           <parameter name="PruneOnBoot"><br>+                                       <para>If true delete the contact on Asterisk restart/boot.</para><br>+                                </parameter><br>+                           <parameter name="Path"><br>+                                      <para>The Path header received on the REGISTER.</para><br>+                           </parameter><br>+                           <parameter name="Endpoint"><br>+                                  <para>The name of the endpoint associated with this information.</para><br>+                          </parameter><br>+                           <parameter name="AuthenticateQualify"><br>+                                       <para>A boolean indicating whether a qualify should be authenticated.</para><br>+                             </parameter><br>+                           <parameter name="Uri"><br>+                                       <para>This contact's URI.</para><br>+                             </parameter><br>+                           <parameter name="QualifyFrequency"><br>+                                  <para>The interval in seconds at which the contact will be qualified.</para><br>+                             </parameter><br>+                           <parameter name="UserAgent"><br>+                                 <para>Content of the User-Agent header in REGISTER request</para><br>+                                </parameter><br>+                           <parameter name="ExpirationTime"><br>+                                    <para>Absolute time that this contact is no longer valid after</para><br>+                            </parameter><br>+                           <parameter name="OutboundProxy"><br>+                                     <para>The contact's outbound proxy.</para><br>+                           </parameter><br>+                           <parameter name="Status"><br>+                                    <para>This contact's status.</para><br>+                                  <enumlist><br>+                                             <enum name="Reachable"/><br>+                                             <enum name="Unreachable"/><br>+                                           <enum name="NonQualified"/><br>+                                          <enum name="Unknown"/><br>+                                       </enumlist><br>+                            </parameter><br>+                           <parameter name="RoundtripUsec"><br>+                                     <para>The round trip time in microseconds.</para><br>+                                </parameter><br>+                   </syntax><br>+              </managerEventInstance><br>+        </managerEvent><br>         <managerEvent language="en_US" name="ContactStatusDetail"><br>          <managerEventInstance class="EVENT_FLAG_COMMAND"><br>                     <synopsis>Provide details about a contact's status.</synopsis><br>@@ -2378,6 +2449,7 @@<br>                                                 <enum name="Reachable"/><br>                                              <enum name="Unreachable"/><br>                                            <enum name="NonQualified"/><br>+                                          <enum name="Unknown"/><br>                                        </enumlist><br>                             </parameter><br>                            <parameter name="RoundtripUsec"><br>@@ -2574,6 +2646,33 @@<br>                      </managerEvent><br>                 </responses><br>    </manager><br>+     <manager name="PJSIPShowContacts" language="en_US"><br>+                <synopsis><br>+                     Lists PJSIP Contacts.<br>+                </synopsis><br>+            <syntax /><br>+             <description><br>+                  <para>Provides a listing of all Contacts. For each Contact a <literal>ContactList</literal><br>+                        event is raised that contains relevant attributes and status information.<br>+                    Once all contacts have been listed a <literal>ContactListComplete</literal> event<br>+                        is issued.<br>+                   </para><br>+                </description><br>+         <responses><br>+                    <list-elements><br>+                                <xi:include xpointer="xpointer(/docs/managerEvent[@name='ContactList'])" /><br>+                  </list-elements><br>+                       <managerEvent language="en_US" name="ContactListComplete"><br>+                         <managerEventInstance class="EVENT_FLAG_COMMAND"><br>+                                    <synopsis>Provide final information about a contact list.</synopsis><br>+                                     <syntax><br>+                                               <parameter name="EventList"/><br>+                                                <parameter name="ListItems"/><br>+                                        </syntax><br>+                              </managerEventInstance><br>+                        </managerEvent><br>+                </responses><br>+   </manager><br> <br>  ***/<br> <br>diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c<br>index 9d7402b..3465eae 100644<br>--- a/res/res_pjsip/pjsip_options.c<br>+++ b/res/res_pjsip/pjsip_options.c<br>@@ -929,6 +929,91 @@<br>     return 0;<br> }<br> <br>+static struct ao2_container *get_all_contacts(void)<br>+{<br>+   struct ao2_container *contacts;<br>+<br>+   contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "contact",<br>+                        AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);<br>+<br>+        return contacts;<br>+}<br>+<br>+static int sip_contact_to_ami(const struct ast_sip_contact *contact,<br>+                          struct ast_str **buf)<br>+{<br>+ return ast_sip_sorcery_object_to_ami(contact, buf);<br>+}<br>+<br>+static int format_ami_contactlist_handler(void *obj, void *arg, int flags)<br>+{<br>+  struct ast_sip_contact *contact = obj;<br>+       struct ast_sip_ami *ami = arg;<br>+       struct ast_str *buf;<br>+ struct ast_sip_contact_status *status;<br>+<br>+    buf = ast_sip_create_ami_event("ContactList", ami);<br>+<br>+     if (!buf) {<br>+          return CMP_STOP;<br>+     }<br>+<br>+ if (sip_contact_to_ami(contact, &buf)) {<br>+         ast_free(buf);<br>+               return CMP_STOP;<br>+     }<br>+<br>+ /* Add extra info */<br>+ status = ast_sorcery_retrieve_by_id(<br>+         ast_sip_get_sorcery(), CONTACT_STATUS,<br>+               ast_sorcery_object_get_id(contact));<br>+ ast_str_append(&buf, 0, "Status: %s\r\n",<br>+                      ast_sip_get_contact_status_label(status ? status->status : UNKNOWN));<br>+     if (!status || status->status == UNKNOWN) {<br>+               ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");<br>+     } else {<br>+             ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);<br>+   }<br>+<br>+ astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));<br>+<br>+        ami->count++;<br>+<br>+  ast_free(buf);<br>+<br>+    return 0;<br>+}<br>+<br>+static int ami_show_contacts(struct mansession *s, const struct message *m)<br>+{<br>+   struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };<br>+       struct ao2_container *contacts;<br>+<br>+   contacts = get_all_contacts();<br>+       if (!contacts) {<br>+             astman_send_error(s, m, "Could not get Contacts\n");<br>+               return 0;<br>+    }<br>+<br>+ if (!ao2_container_count(contacts)) {<br>+                astman_send_error(s, m, "No Contacts found\n");<br>+            ao2_ref(contacts, -1);<br>+               return 0;<br>+    }<br>+<br>+ astman_send_listack(s, m, "A listing of Contacts follows, presented as ContactList events",<br>+                        "start");<br>+<br>+       ao2_callback(contacts, OBJ_NODATA, format_ami_contactlist_handler, &ami);<br>+<br>+     astman_send_list_complete_start(s, m, "ContactListComplete", ami.count);<br>+   astman_send_list_complete_end(s);<br>+<br>+ ao2_ref(contacts, -1);<br>+<br>+    return 0;<br>+}<br>+<br> static int ami_sip_qualify(struct mansession *s, const struct message *m)<br> {<br>      const char *endpoint_name = astman_get_header(m, "Endpoint");<br>@@ -1479,6 +1564,7 @@<br> <br>     internal_sip_register_endpoint_formatter(&contact_status_formatter);<br>      ast_manager_register_xml("PJSIPQualify", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_sip_qualify);<br>+       ast_manager_register_xml("PJSIPShowContacts", EVENT_FLAG_SYSTEM, ami_show_contacts);<br>        ast_cli_register_multiple(cli_options, ARRAY_LEN(cli_options));<br> <br>    update_all_unqualified_endpoints();<br>@@ -1491,6 +1577,7 @@<br> {<br>        ast_cli_unregister_multiple(cli_options, ARRAY_LEN(cli_options));<br>     ast_manager_unregister("PJSIPQualify");<br>+    ast_manager_unregister("PJSIPShowContacts");<br>        internal_sip_unregister_endpoint_formatter(&contact_status_formatter);<br> <br>         ast_sorcery_observer_remove(ast_sip_get_sorcery(), "aor", &observer_callbacks_options);<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/7960">change 7960</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/7960"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I2eed42c74bbc725fad26b8b33b1a5b3161950c73 </div>
<div style="display:none"> Gerrit-Change-Number: 7960 </div>
<div style="display:none"> Gerrit-PatchSet: 5 </div>
<div style="display:none"> Gerrit-Owner: sungtae kim <pchero21@gmail.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </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>
<div style="display:none"> Gerrit-Reviewer: sungtae kim <pchero21@gmail.com> </div>