manager: Add state list commands
authorKinsey Moore <kmoore@digium.com>
Wed, 30 Jul 2014 18:32:25 +0000 (18:32 +0000)
committerKinsey Moore <kmoore@digium.com>
Wed, 30 Jul 2014 18:32:25 +0000 (18:32 +0000)
This patch adds three new AMI commands:
 * ExtensionStateList (pbx.c) - list all known extension state hints
   and their current statuses. Events emitted by the list action are
   equivalent to the ExtensionStatus events.
 * PresenceStateList (res_manager_presencestate) - list all known
   presence state values. Events emitted are generated by the stasis
   message type, and hence are PresenceStateChange events.
 * DeviceStateList (res_manager_devicestate) - list all known device
   state values. Events emitted are generated by the stasis message
   type, and hence are DeviceStateChange events.

Patch-by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/3799/

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419806 65c4cc65-6c06-0410-ace0-fbb531ad65f3

main/manager.c
main/pbx.c
res/res_manager_devicestate.c
res/res_manager_presencestate.c

index 0a10d8c..50f74db 100644 (file)
@@ -1063,6 +1063,31 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <ref type="manager">Redirect</ref>
                </see-also>
        </manager>
+       <managerEvent name="ExtensionStatus" language="en_US">
+               <managerEventInstance class="EVENT_FLAG_CALL">
+                       <synopsis>Raised when a hint changes due to a device state change.</synopsis>
+                       <syntax>
+                               <parameter name="Exten" />
+                               <parameter name="Context" />
+                               <parameter name="Hint" />
+                               <parameter name="Status" />
+                               <parameter name="StatusText" />
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
+       <managerEvent name="PresenceStatus" language="en_US">
+               <managerEventInstance class="EVENT_FLAG_CALL">
+                       <synopsis>Raised when a hint changes due to a presence state change.</synopsis>
+                       <syntax>
+                               <parameter name="Exten" />
+                               <parameter name="Context" />
+                               <parameter name="Hint" />
+                               <parameter name="Status" />
+                               <parameter name="Subtype" />
+                               <parameter name="Message" />
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
  ***/
 
 /*! \addtogroup Group_AMI AMI functions
@@ -6244,11 +6269,6 @@ static int manager_state_cb(char *context, char *exten, struct ast_state_cb_info
 
        switch(info->reason) {
        case AST_HINT_UPDATE_DEVICE:
-               /*** DOCUMENTATION
-                       <managerEventInstance>
-                               <synopsis>Raised when an extension state has changed.</synopsis>
-                       </managerEventInstance>
-               ***/
                manager_event(EVENT_FLAG_CALL, "ExtensionStatus",
                        "Exten: %s\r\n"
                        "Context: %s\r\n"
@@ -6262,11 +6282,6 @@ static int manager_state_cb(char *context, char *exten, struct ast_state_cb_info
                        ast_extension_state2str(info->exten_state));
                break;
        case AST_HINT_UPDATE_PRESENCE:
-               /*** DOCUMENTATION
-                       <managerEventInstance>
-                               <synopsis>Raised when a presence state has changed.</synopsis>
-                       </managerEventInstance>
-               ***/
                manager_event(EVENT_FLAG_CALL, "PresenceStatus",
                        "Exten: %s\r\n"
                        "Context: %s\r\n"
index 48fd119..4004e14 100644 (file)
@@ -800,6 +800,45 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        may take a lot of capacity.</para>
                </description>
        </manager>
+       <manager name="ExtensionStateList" language="en_US">
+               <synopsis>
+                       List the current known extension states.
+               </synopsis>
+               <syntax>
+                       <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+               </syntax>
+               <description>
+                       <para>This will list out all known extension states in a
+                       sequence of <replaceable>ExtensionStatus</replaceable> events.
+                       When finished, a <replaceable>ExtensionStateListComplete</replaceable> event
+                       will be emitted.</para>
+               </description>
+               <see-also>
+                       <ref type="manager">ExtensionState</ref>
+                       <ref type="function">HINT</ref>
+                       <ref type="function">EXTENSION_STATE</ref>
+               </see-also>
+               <responses>
+                       <list-elements>
+                               <xi:include xpointer="xpointer(/docs/managerEvent[@name='ExtensionStatus'])" />
+                       </list-elements>
+                       <managerEvent name="ExtensionStateListComplete" language="en_US">
+                               <managerEventInstance class="EVENT_FLAG_COMMAND">
+                                       <synopsis>
+                                               Indicates the end of the list the current known extension states.
+                                       </synopsis>
+                                       <syntax>
+                                               <parameter name="EventList">
+                                                       <para>Conveys the status of the event list.</para>
+                                               </parameter>
+                                               <parameter name="ListItems">
+                                                       <para>Conveys the number of statuses reported.</para>
+                                               </parameter>
+                                       </syntax>
+                               </managerEventInstance>
+                       </managerEvent>
+               </responses>
+       </manager>
  ***/
 
 #ifdef LOW_MEMORY
@@ -11931,6 +11970,55 @@ static const struct ast_data_entry pbx_data_providers[] = {
        AST_DATA_ENTRY("asterisk/core/hints", &hints_data_provider),
 };
 
+static int action_extensionstatelist(struct mansession *s, const struct message *m)
+{
+       const char *action_id = astman_get_header(m, "ActionID");
+       struct ast_hint *hint;
+       struct ao2_iterator it_hints;
+
+       if (!hints) {
+               astman_send_error(s, m, "No dialplan hints are available");
+               return 0;
+       }
+
+       astman_send_listack(s, m, "Extension Statuses will follow", "start");
+
+       ao2_lock(hints);
+       it_hints = ao2_iterator_init(hints, 0);
+       for (; (hint = ao2_iterator_next(&it_hints)); ao2_ref(hint, -1)) {
+
+               ao2_lock(hint);
+               astman_append(s, "Event: ExtensionStatus\r\n");
+               if (!ast_strlen_zero(action_id)) {
+                       astman_append(s, "ActionID: %s\r\n", action_id);
+               }
+               astman_append(s,
+                  "Exten: %s\r\n"
+                  "Context: %s\r\n"
+                  "Hint: %s\r\n"
+                  "Status: %d\r\n"
+                  "StatusText: %s\r\n\r\n",
+                  hint->exten->exten,
+                  hint->exten->parent->name,
+                  hint->exten->app,
+                  hint->laststate,
+                  ast_extension_state2str(hint->laststate));
+               ao2_unlock(hint);
+       }
+       astman_append(s, "Event: ExtensionStateListComplete\r\n");
+       if (!ast_strlen_zero(action_id)) {
+               astman_append(s, "ActionID: %s\r\n", action_id);
+       }
+       astman_append(s, "EventList: Complete\r\n"
+               "ListItems: %d\r\n\r\n", ao2_container_count(hints));
+
+       ao2_iterator_destroy(&it_hints);
+       ao2_unlock(hints);
+
+       return 0;
+}
+
+
 /*!
  * \internal
  * \brief Clean up resources on Asterisk shutdown.
@@ -11949,6 +12037,7 @@ static void unload_pbx(void)
                ast_unregister_application(builtins[x].name);
        }
        ast_manager_unregister("ShowDialPlan");
+       ast_manager_unregister("ExtensionStateList");
        ast_cli_unregister_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
        ast_custom_function_unregister(&exception_function);
        ast_custom_function_unregister(&testtime_function);
@@ -11957,6 +12046,7 @@ static void unload_pbx(void)
 
 int load_pbx(void)
 {
+       int res = 0;
        int x;
 
        ast_register_atexit(unload_pbx);
@@ -11979,7 +12069,12 @@ int load_pbx(void)
        }
 
        /* Register manager application */
-       ast_manager_register_xml_core("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan);
+       res |= ast_manager_register_xml_core("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan);
+       res |= ast_manager_register_xml_core("ExtensionStateList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstatelist);
+
+       if (res) {
+               return -1;
+       }
 
        if (!(device_state_sub = stasis_subscribe(ast_device_state_topic_all(), device_state_cb, NULL))) {
                return -1;
index bbb4537..25eae87 100644 (file)
        <support_level>core</support_level>
  ***/
 
+/*** DOCUMENTATION
+       <manager name="DeviceStateList" language="en_US">
+               <synopsis>
+                       List the current known device states.
+               </synopsis>
+               <syntax>
+                       <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+               </syntax>
+               <description>
+                       <para>This will list out all known device states in a
+                       sequence of <replaceable>DeviceStateChange</replaceable> events.
+                       When finished, a <replaceable>DeviceStateListComplete</replaceable> event
+                       will be emitted.</para>
+               </description>
+               <see-also>
+                       <ref type="managerEvent">DeviceStateChange</ref>
+                       <ref type="function">DEVICE_STATE</ref>
+               </see-also>
+               <responses>
+                       <list-elements>
+                               <xi:include xpointer="xpointer(/docs/managerEvent[@name='DeviceStateChange'])" />
+                       </list-elements>
+                       <managerEvent name="DeviceStateListComplete" language="en_US">
+                               <managerEventInstance class="EVENT_FLAG_COMMAND">
+                                       <synopsis>
+                                               Indicates the end of the list the current known extension states.
+                                       </synopsis>
+                                       <syntax>
+                                               <parameter name="EventList">
+                                                       <para>Conveys the status of the event list.</para>
+                                               </parameter>
+                                               <parameter name="ListItems">
+                                                       <para>Conveys the number of statuses reported.</para>
+                                               </parameter>
+                                       </syntax>
+                               </managerEventInstance>
+                       </managerEvent>
+               </responses>
+       </manager>
+ ***/
+
+
 #include "asterisk.h"
 #include "asterisk/module.h"
+#include "asterisk/manager.h"
 #include "asterisk/stasis.h"
 #include "asterisk/devicestate.h"
 
 static struct stasis_forward *topic_forwarder;
 
+static int action_devicestatelist(struct mansession *s, const struct message *m)
+{
+       RAII_VAR(struct ao2_container *, device_states, NULL, ao2_cleanup);
+       const char *action_id = astman_get_header(m, "ActionID");
+       struct stasis_message *msg;
+       struct ao2_iterator it_states;
+       int count = 0;
+
+       device_states = stasis_cache_dump_by_eid(ast_device_state_cache(),
+               ast_device_state_message_type(), NULL);
+       if (!device_states) {
+               astman_send_error(s, m, "Memory Allocation Failure");
+               return 0;
+       }
+
+       astman_send_listack(s, m, "Device State Changes will follow", "start");
+
+       it_states = ao2_iterator_init(device_states, 0);
+       for (; (msg = ao2_iterator_next(&it_states)); ao2_ref(msg, -1)) {
+               struct ast_manager_event_blob *blob = stasis_message_to_ami(msg);
+
+               if (!blob) {
+                       continue;
+               }
+
+               count++;
+
+               astman_append(s, "Event: %s\r\n", blob->manager_event);
+               if (!ast_strlen_zero(action_id)) {
+                       astman_append(s, "ActionID: %s\r\n", action_id);
+               }
+               astman_append(s, "%s\r\n", blob->extra_fields);
+               ao2_ref(blob, -1);
+       }
+       ao2_iterator_destroy(&it_states);
+
+       astman_append(s, "Event: DeviceStateListComplete\r\n");
+       if (!ast_strlen_zero(action_id)) {
+               astman_append(s, "ActionID: %s\r\n", action_id);
+       }
+       astman_append(s, "EventList: Complete\r\n"
+               "ListItems: %d\r\n\r\n", count);
+
+       return 0;
+}
+
 static int unload_module(void)
 {
        topic_forwarder = stasis_forward_cancel(topic_forwarder);
+       ast_manager_unregister("DeviceStateList");
+
        return 0;
 }
 
@@ -41,8 +132,16 @@ static int load_module(void)
        if (!manager_topic) {
                return AST_MODULE_LOAD_DECLINE;
        }
-
        topic_forwarder = stasis_forward_all(ast_device_state_topic_all(), manager_topic);
+       if (!topic_forwarder) {
+               return AST_MODULE_LOAD_DECLINE;
+       }
+
+       if (ast_manager_register_xml("DeviceStateList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING,
+                                        action_devicestatelist)) {
+               topic_forwarder = stasis_forward_cancel(topic_forwarder);
+               return AST_MODULE_LOAD_DECLINE;
+       }
 
        return AST_MODULE_LOAD_SUCCESS;
 }
index ef22307..e2cfca5 100644 (file)
        <support_level>core</support_level>
  ***/
 
+/*** DOCUMENTATION
+       <manager name="PresenceStateList" language="en_US">
+               <synopsis>
+                       List the current known presence states.
+               </synopsis>
+               <syntax>
+                       <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+               </syntax>
+               <description>
+                       <para>This will list out all known presence states in a
+                       sequence of <replaceable>PresenceStateChange</replaceable> events.
+                       When finished, a <replaceable>PresenceStateListComplete</replaceable> event
+                       will be emitted.</para>
+               </description>
+               <see-also>
+                       <ref type="manager">PresenceState</ref>
+                       <ref type="managerEvent">PresenceStatus</ref>
+                       <ref type="function">PRESENCE_STATE</ref>
+               </see-also>
+               <responses>
+                       <list-elements>
+                               <xi:include xpointer="xpointer(/docs/managerEvent[@name='PresenceStateChange'])" />
+                       </list-elements>
+                       <managerEvent name="PresenceStateListComplete" language="en_US">
+                               <managerEventInstance class="EVENT_FLAG_COMMAND">
+                                       <synopsis>
+                                               Indicates the end of the list the current known extension states.
+                                       </synopsis>
+                                       <syntax>
+                                               <parameter name="EventList">
+                                                       <para>Conveys the status of the event list.</para>
+                                               </parameter>
+                                               <parameter name="ListItems">
+                                                       <para>Conveys the number of statuses reported.</para>
+                                               </parameter>
+                                       </syntax>
+                               </managerEventInstance>
+                       </managerEvent>
+               </responses>
+       </manager>
+ ***/
+
 #include "asterisk.h"
 #include "asterisk/module.h"
+#include "asterisk/manager.h"
 #include "asterisk/stasis.h"
 #include "asterisk/presencestate.h"
 
 static struct stasis_forward *topic_forwarder;
 
+static int action_presencestatelist(struct mansession *s, const struct message *m)
+{
+       RAII_VAR(struct ao2_container *, presence_states, NULL, ao2_cleanup);
+       const char *action_id = astman_get_header(m, "ActionID");
+       struct stasis_message *msg;
+       struct ao2_iterator it_states;
+       int count = 0;
+
+       presence_states = stasis_cache_dump(ast_presence_state_cache(),
+               ast_presence_state_message_type());
+       if (!presence_states) {
+               astman_send_error(s, m, "Memory Allocation Failure");
+               return 0;
+       }
+
+       astman_send_listack(s, m, "Presence State Changes will follow", "start");
+
+       it_states = ao2_iterator_init(presence_states, 0);
+       for (; (msg = ao2_iterator_next(&it_states)); ao2_ref(msg, -1)) {
+               struct ast_manager_event_blob *blob = stasis_message_to_ami(msg);
+
+               if (!blob) {
+                       continue;
+               }
+
+               count++;
+
+               astman_append(s, "Event: %s\r\n", blob->manager_event);
+               if (!ast_strlen_zero(action_id)) {
+                       astman_append(s, "ActionID: %s\r\n", action_id);
+               }
+               astman_append(s, "%s\r\n", blob->extra_fields);
+               ao2_ref(blob, -1);
+       }
+       ao2_iterator_destroy(&it_states);
+
+       astman_append(s, "Event: PresenceStateListComplete\r\n");
+       if (!ast_strlen_zero(action_id)) {
+               astman_append(s, "ActionID: %s\r\n", action_id);
+       }
+       astman_append(s, "EventList: Complete\r\n"
+               "ListItems: %d\r\n\r\n", count);
+
+       return 0;
+}
+
 static int unload_module(void)
 {
+       ast_manager_unregister("PresenceStateList");
        topic_forwarder = stasis_forward_cancel(topic_forwarder);
        return 0;
 }
@@ -41,8 +131,16 @@ static int load_module(void)
        if (!manager_topic) {
                return AST_MODULE_LOAD_DECLINE;
        }
-
        topic_forwarder = stasis_forward_all(ast_presence_state_topic_all(), manager_topic);
+       if (!topic_forwarder) {
+               return AST_MODULE_LOAD_DECLINE;
+       }
+
+       if (ast_manager_register_xml("PresenceStateList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING,
+                                        action_presencestatelist)) {
+               topic_forwarder = stasis_forward_cancel(topic_forwarder);
+               return AST_MODULE_LOAD_DECLINE;
+       }
 
        return AST_MODULE_LOAD_SUCCESS;
 }