<p>Kevin Harwell <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/11463">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Kevin Harwell: Looks good to me, approved
  Friendly Automation: Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">mwi: Update the MWI core to use stasis_state API<br><br>** Note **<br><br>This patch is meant to be the minimum needed in order for the MWI core to use<br>the now underlying stasis_state module. As such it does not completely remove<br>its reliance on the stasis_cache. Doing so has allowed current consumers to<br>not have to change, and update those code paths for this patch. When time<br>allows, subsequent patches can/will be made to those consumers to take advantage<br>of some of the new MWI API included here. Thus, eventually and ultimately<br>removing MWI dependency on the stasis_cache.<br><br>** End Note **<br><br>This patch makes it so the MWI core now takes advantage of the new stasis_state<br>API. Consumers of MWI should no longer need to depend upon stasis topic pooling,<br>and the stasis cache directly. Similar functionality and implementation details<br>have now been pushed into the stasis_state module. However, all MWI state should<br>be accessed via the MWI API itself.<br><br>As such a few new methods, and constructs have been added to the MWI core that<br>facilitate consumer publishing, subscribing, and iterating over MWI state data.<br><br>* ast_mwi_subscriber *<br><br>Created via ast_mwi_add_subscriber, a subscriber subscribes to a given mailbox<br>in order to receive updates about the given mailbox. Adding a subscriber will<br>create the underlying topic, and associated state data if those do not already<br>exist for it. The topic, and last known state data is guaranteed to exist for<br>the lifetime of the subscriber.<br><br>* ast_mwi_publisher *<br><br>Before publishing to a particular topic a publisher should be created. This can<br>be achieved by using ast_mwi_add_publisher. Publishing to a mailbox should then<br>be done using one of the MWI publish functions. This ensures the message is<br>published to the appropriate topic, and the last known state is maintained.<br><br>* ast_mwi_observer *<br><br>Add an observer in order to watch for particular MWI module related events. For<br>instance if a submodule needs to know when a subscription is added to any<br>mailbox an observer can be added to watch for that.<br><br>* other *<br><br>Urgent message count is now part of the published MWI state object. Also state<br>can be iterated over using defined callbacks.<br><br>ASTERISK-28442<br><br>Change-Id: I93f935f9090cd5ddff6d4bc80ff90703c05cf776<br>---<br>M include/asterisk/mwi.h<br>M main/mwi.c<br>A tests/test_mwi.c<br>3 files changed, 965 insertions(+), 52 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/asterisk/mwi.h b/include/asterisk/mwi.h</span><br><span>index 1502224..3ce2b06 100644</span><br><span>--- a/include/asterisk/mwi.h</span><br><span>+++ b/include/asterisk/mwi.h</span><br><span>@@ -19,7 +19,77 @@</span><br><span> #ifndef _ASTERISK_MWI_H</span><br><span> #define _ASTERISK_MWI_H</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! \file</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Asterisk MWI API.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \par Intro</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This module manages, and processes all things MWI. Defined are mechanisms for subscribing</span><br><span style="color: hsl(120, 100%, 40%);">+ * and publishing to MWI topics. User modules wishing to receive MWI updates for a particular</span><br><span style="color: hsl(120, 100%, 40%);">+ * mailbox should do so by adding an MWI subscriber to that mailbox, followed by subscribing</span><br><span style="color: hsl(120, 100%, 40%);">+ * to the mailbox's topic. Likewise, user modules that want to publish MWI updates about a</span><br><span style="color: hsl(120, 100%, 40%);">+ * particular mailbox should first add a publisher for that mailbox prior to publishing.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * MWI state is managed via an underlying \ref stasis_state_manager (if interested see the</span><br><span style="color: hsl(120, 100%, 40%);">+ * stasis_state.c module for the gory details). As such all last known mailbox state can be</span><br><span style="color: hsl(120, 100%, 40%);">+ * retrieve and iterated over by using the \ref ast_mwi_callback function.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \par ast_mwi_subscriber</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Created via \ref ast_mwi_add_subscriber, a subscriber subscribes to a given mailbox in</span><br><span style="color: hsl(120, 100%, 40%);">+ * order to receive updates about the given mailbox. Adding a subscriber will create the</span><br><span style="color: hsl(120, 100%, 40%);">+ * underlying topic, and associated state data if those do not already exist for it. The</span><br><span style="color: hsl(120, 100%, 40%);">+ * topic, and last known state data is guaranteed to exist for the lifetime of the subscriber.</span><br><span style="color: hsl(120, 100%, 40%);">+ * State data can be NULL if nothing has been published to the mailbox's topic yet.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * NOTE, currently adding a subscriber here will either create, or add a reference to the</span><br><span style="color: hsl(120, 100%, 40%);">+ * underlying stasis state (and associated topic). However, it does not actually subscribe to</span><br><span style="color: hsl(120, 100%, 40%);">+ * the stasis topic itself. You still need to explicitly call \ref stasis_subscribe, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * similar on the topic if you wish to receive published event updates.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * So given that when subscribing to an MWI topic the following order should be adhered to:</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *   1. Add an MWI state subscriber using \ref ast_mwi_add_subscriber</span><br><span style="color: hsl(120, 100%, 40%);">+ *   2. Retrieve the topic from the subscriber using \ref ast_mwi_subscriber_topic</span><br><span style="color: hsl(120, 100%, 40%);">+ *   3. Subscribe to the topic itself using \ref stasis_subscribe or \ref stasis_subscribe_pool</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Or simply call \ref ast_mwi_subscribe_pool, which combines those steps into a single call and</span><br><span style="color: hsl(120, 100%, 40%);">+ * returns the subscriber that is now subscribed to both the stasis topic and state.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Similarly, releasing the subscriber's reference removes a reference to the underlying state,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but does not unsubscribe from the MWI topic. This should be done separately and prior to</span><br><span style="color: hsl(120, 100%, 40%);">+ * removing the subscriber's state reference:</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *   1. Unsubscribe from the stasis topic subscription using \ref stasis_unsubscribe or</span><br><span style="color: hsl(120, 100%, 40%);">+ *      \ref stasis_unsubscribe_and_join</span><br><span style="color: hsl(120, 100%, 40%);">+ *   2. Remove the MWI subscriber reference</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Or call \ref ast_mwi_unsubscribe (or _and_join), which combines those two steps into a</span><br><span style="color: hsl(120, 100%, 40%);">+ * single call.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \par ast_mwi_publisher</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Before publishing to a particular topic a publisher should be created. This can be achieved</span><br><span style="color: hsl(120, 100%, 40%);">+ * by using \ref ast_mwi_add_publisher. Publishing to a mailbox should then be done using the</span><br><span style="color: hsl(120, 100%, 40%);">+ * \ref ast_mwi_publish function. This ensures the message is published to the appropriate</span><br><span style="color: hsl(120, 100%, 40%);">+ * topic, and the last known state is maintained.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Publishing by mailbox id alone is also allowed. However, it is not recommended to do so,</span><br><span style="color: hsl(120, 100%, 40%);">+ * and exists mainly for backwards compatibility, and legacy subsystems. If, and when this</span><br><span style="color: hsl(120, 100%, 40%);">+ * method of publishing is employed a call to one of the \ref ast_delete_mwi_state functions</span><br><span style="color: hsl(120, 100%, 40%);">+ * should also be called for a given mailbox id after no more publishing will be done for</span><br><span style="color: hsl(120, 100%, 40%);">+ * that id. Otherwise a memory leak on the underlying stasis_state object will occur.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \par ast_mwi_observer</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Add an observer in order to watch for particular MWI module related events. For instance if</span><br><span style="color: hsl(120, 100%, 40%);">+ * a submodule needs to know when a subscription is added to any mailbox an observer can be</span><br><span style="color: hsl(120, 100%, 40%);">+ * added to watch for that.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #include "asterisk/utils.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/stasis_state.h"</span><br><span> </span><br><span> #if defined(__cplusplus) || defined(c_plusplus)</span><br><span> extern "C" {</span><br><span>@@ -27,6 +97,273 @@</span><br><span> </span><br><span> struct ast_json;</span><br><span> struct stasis_message_type;</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_mwi_state;</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 An MWI state subscriber</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * An ao2 managed object. Holds a reference to the latest MWI state for its lifetime.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_mwi_subscriber;</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 Add an MWI state subscriber to the mailbox</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Adding a subscriber to a mailbox will create a stasis topic for the mailbox if one</span><br><span style="color: hsl(120, 100%, 40%);">+ * does not already exist. It does not however subscribe to the topic itself. This is</span><br><span style="color: hsl(120, 100%, 40%);">+ * done separately using a call to \ref stasis_subscribe or \ref stasis_subscribe_pool.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * A subscriber can be removed by releasing its reference. Doing so releases its underlying</span><br><span style="color: hsl(120, 100%, 40%);">+ * reference to the MWI state. It does not unsubscribe from the topic. Unsubscribing from</span><br><span style="color: hsl(120, 100%, 40%);">+ * a topic should be done prior to unsubscribing the state.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param mailbox The subscription state mailbox id</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval An MWI subscriber object</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL on error</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_mwi_subscriber *ast_mwi_add_subscriber(const char *mailbox);</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 Add an MWI state subscriber, and stasis subscription to the mailbox</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Adding a subscriber to a mailbox will create a stasis topic for the mailbox if one</span><br><span style="color: hsl(120, 100%, 40%);">+ * does not already exist. Once successfully create the underlying stasis topic is then</span><br><span style="color: hsl(120, 100%, 40%);">+ * subscribed to as well.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * A subscriber can be removed by releasing its reference. Doing so releases its underlying</span><br><span style="color: hsl(120, 100%, 40%);">+ * reference to the MWI state. It does not unsubscribe from the topic. Unsubscribing from</span><br><span style="color: hsl(120, 100%, 40%);">+ * a topic should be done prior to unsubscribing the state.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param mailbox The subscription state mailbox id</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param callback The stasis subscription callback</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param data A user data object passed to the stasis subscription</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval An MWI subscriber object</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL on error</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_mwi_subscriber *ast_mwi_subscribe_pool(const char *mailbox,</span><br><span style="color: hsl(120, 100%, 40%);">+  stasis_subscription_cb callback, void *data);</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 Unsubscribe from the stasis topic and MWI.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param sub An MWI subscriber</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void *ast_mwi_unsubscribe(struct ast_mwi_subscriber *sub);</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 Unsubscribe from the stasis topic, block until the final message</span><br><span style="color: hsl(120, 100%, 40%);">+ * is received, and then unsubscribe from MWI.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param sub An MWI subscriber</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void *ast_mwi_unsubscribe_and_join(struct ast_mwi_subscriber *sub);</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 Retrieves the MWI subscriber's topic</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note Returned topic's reference count is NOT incremented. However, the topic is</span><br><span style="color: hsl(120, 100%, 40%);">+ * guaranteed to live for the lifetime of the subscriber.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param sub An MWI subscriber</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval A stasis topic subscribed to by the subscriber</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct stasis_topic *ast_mwi_subscriber_topic(struct ast_mwi_subscriber *sub);</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 Retrieves the state data object associated with the MWI subscriber</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note Returned data's reference count is incremented</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param sub An MWI subscriber</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval The state data object</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_mwi_state *ast_mwi_subscriber_data(struct ast_mwi_subscriber *sub);</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 Retrieve the stasis MWI topic subscription if available.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param sub An MWI subscriber</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval The subscriber's stasis subscription</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL if no subscription available</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct stasis_subscription *ast_mwi_subscriber_subscription(struct ast_mwi_subscriber *sub);</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 An MWI state publisher</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * An ao2 managed object. Holds a reference to the latest MWI state for its lifetime.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_mwi_publisher;</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 Add an MWI state publisher to the mailbox</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Adding a publisher to a mailbox will create a stasis topic for the mailbox if one</span><br><span style="color: hsl(120, 100%, 40%);">+ * does not already exist. A publisher can be removed by releasing its reference. Doing</span><br><span style="color: hsl(120, 100%, 40%);">+ * so releases its underlying reference to the MWI state.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param mailbox The mailbox id to publish to</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval An MWI publisher object</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULl on error</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_mwi_publisher *ast_mwi_add_publisher(const char *mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief MWI state event interface */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_mwi_observer {</span><br><span style="color: hsl(120, 100%, 40%);">+ /*!</span><br><span style="color: hsl(120, 100%, 40%);">+    * \brief Raised when MWI is being subscribed</span><br><span style="color: hsl(120, 100%, 40%);">+  *</span><br><span style="color: hsl(120, 100%, 40%);">+     * \param mailbox The mailbox id subscribed</span><br><span style="color: hsl(120, 100%, 40%);">+    * \param sub The subscriber subscribed</span><br><span style="color: hsl(120, 100%, 40%);">+        */</span><br><span style="color: hsl(120, 100%, 40%);">+   void (*on_subscribe)(const char *mailbox, struct ast_mwi_subscriber *sub);</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 Raised when MWI is being unsubscribed</span><br><span style="color: hsl(120, 100%, 40%);">+        *</span><br><span style="color: hsl(120, 100%, 40%);">+     * \param mailbox The mailbox id being unsubscribed</span><br><span style="color: hsl(120, 100%, 40%);">+    * \param sub The subscriber to unsubscribe</span><br><span style="color: hsl(120, 100%, 40%);">+    */</span><br><span style="color: hsl(120, 100%, 40%);">+   void (*on_unsubscribe)(const char *mailbox, struct ast_mwi_subscriber *sub);</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 Add an observer to receive MWI state related events.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param observer The observer handling events</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 if successfully registered, -1 otherwise</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_mwi_add_observer(struct ast_mwi_observer *observer);</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 Remove an MWI state observer.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param observer The observer being removed</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_mwi_remove_observer(struct ast_mwi_observer *observer);</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 The delegate called for each managed mailbox state.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param mwi_state The mwi state object</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param data User data passed in by the initiator</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 to continue traversing, or CMP_STOP (2) to stop traversing</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+typedef int (*on_mwi_state)(struct ast_mwi_state *mwi_state, void *data);</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 For each managed mailbox call the given handler.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param handler The mwi state handler to call for each managed mailbox</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param data User to data to pass on to the handler</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_mwi_state_callback_all(on_mwi_state handler, void *data);</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 For each managed mailbox that has a subscriber call the given handler.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param handler The mwi state handler to call for each managed mailbox</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param data User to data to pass on to the handler</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_mwi_state_callback_subscribed(on_mwi_state handler, void *data);</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 Publish MWI for the given mailbox.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param publisher The publisher to publish a mailbox update on</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param urgent_msgs The number of urgent messages in this mailbox</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param new_msgs The number of new messages in this mailbox</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param old_msgs The number of old messages in this mailbox</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param channel_id A unique identifier for a channel associated with this</span><br><span style="color: hsl(120, 100%, 40%);">+ *        change in mailbox state</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param eid The EID of the server that originally published the message</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 on success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval -1 on failure</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_mwi_publish(struct ast_mwi_publisher *publisher, int urgent_msgs,</span><br><span style="color: hsl(120, 100%, 40%);">+       int new_msgs, int old_msgs, const char *channel_id, struct ast_eid *eid);</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 Publish MWI for the given mailbox.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param mailbox The mailbox identifier string.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param context The context this mailbox resides in (NULL or "" if only using mailbox)</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param urgent_msgs The number of urgent messages in this mailbox</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param new_msgs The number of new messages in this mailbox</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param old_msgs The number of old messages in this mailbox</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param channel_id A unique identifier for a channel associated with this</span><br><span style="color: hsl(120, 100%, 40%);">+ *        change in mailbox state</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param eid The EID of the server that originally published the message</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 on success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval -1 on failure</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.28.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_mwi_publish_by_mailbox(const char *mailbox, const char *context, int urgent_msgs,</span><br><span style="color: hsl(120, 100%, 40%);">+        int new_msgs, int old_msgs, const char *channel_id, struct ast_eid *eid);</span><br><span> </span><br><span> /*!</span><br><span>  * \since 12</span><br><span>@@ -126,6 +463,7 @@</span><br><span>   /*! If applicable, a snapshot of the channel that caused this MWI change */</span><br><span>  struct ast_channel_snapshot *snapshot;</span><br><span>       struct ast_eid eid;              /*!< The EID of the server where this message originated */</span><br><span style="color: hsl(120, 100%, 40%);">+       int urgent_msgs;                 /*!< The current number of urgent messages for this mailbox */</span><br><span> };</span><br><span> </span><br><span> /*!</span><br><span>@@ -228,7 +566,7 @@</span><br><span>  * \retval 0 Success</span><br><span>  * \retval -1 Failure</span><br><span>  *</span><br><span style="color: hsl(0, 100%, 40%);">- * \since 13.26.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.27.0</span><br><span>  * \since 16.4.0</span><br><span>  */</span><br><span> int mwi_init(void);</span><br><span>diff --git a/main/mwi.c b/main/mwi.c</span><br><span>index 43b4e04..e81766c 100644</span><br><span>--- a/main/mwi.c</span><br><span>+++ b/main/mwi.c</span><br><span>@@ -22,16 +22,16 @@</span><br><span> </span><br><span> #include "asterisk.h"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/app.h"</span><br><span> #include "asterisk/mwi.h"</span><br><span> #include "asterisk/stasis_channels.h"</span><br><span> </span><br><span> /*</span><br><span>  * @{ \brief Define \ref stasis topic objects</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-static struct stasis_topic *mwi_topic_all;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct stasis_state_manager *mwi_state_manager;</span><br><span> static struct stasis_cache *mwi_state_cache;</span><br><span> static struct stasis_caching_topic *mwi_topic_cached;</span><br><span style="color: hsl(0, 100%, 40%);">-static struct stasis_topic_pool *mwi_topic_pool;</span><br><span> /* @} */</span><br><span> </span><br><span> /*! \brief Convert a MWI \ref stasis_message to a \ref ast_event */</span><br><span>@@ -84,7 +84,7 @@</span><br><span> </span><br><span> struct stasis_topic *ast_mwi_topic_all(void)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    return mwi_topic_all;</span><br><span style="color: hsl(120, 100%, 40%);">+ return stasis_state_all_topic(mwi_state_manager);</span><br><span> }</span><br><span> </span><br><span> struct stasis_cache *ast_mwi_state_cache(void)</span><br><span>@@ -99,10 +99,11 @@</span><br><span> </span><br><span> struct stasis_topic *ast_mwi_topic(const char *uniqueid)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- return stasis_topic_pool_get_topic(mwi_topic_pool, uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+ return stasis_state_topic(mwi_state_manager, uniqueid);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_mwi_state *ast_mwi_create(const char *mailbox, const char *context)</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_mwi_state *mwi_create_state(const char *mailbox, const char *context,</span><br><span style="color: hsl(120, 100%, 40%);">+       int urgent_msgs, int new_msgs, int old_msgs)</span><br><span> {</span><br><span>    struct ast_mwi_state *mwi_state;</span><br><span> </span><br><span>@@ -110,10 +111,14 @@</span><br><span> </span><br><span>     mwi_state = ao2_alloc(sizeof(*mwi_state), mwi_state_dtor);</span><br><span>   if (!mwi_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_log(LOG_ERROR, "Unable to create MWI state for mailbox '%s@%s'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                              mailbox, ast_strlen_zero(context) ? "" : context);</span><br><span>                 return NULL;</span><br><span>         }</span><br><span> </span><br><span>        if (ast_string_field_init(mwi_state, 256)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_log(LOG_ERROR, "Unable to initialize MWI state for mailbox '%s@%s'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                          mailbox, ast_strlen_zero(context) ? "" : context);</span><br><span>                 ao2_ref(mwi_state, -1);</span><br><span>              return NULL;</span><br><span>         }</span><br><span>@@ -123,9 +128,28 @@</span><br><span>             ast_string_field_set(mwi_state, uniqueid, mailbox);</span><br><span>  }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ mwi_state->urgent_msgs = urgent_msgs;</span><br><span style="color: hsl(120, 100%, 40%);">+      mwi_state->new_msgs = new_msgs;</span><br><span style="color: hsl(120, 100%, 40%);">+    mwi_state->old_msgs = old_msgs;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         return mwi_state;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_mwi_state *mwi_retrieve_then_create_state(const char *mailbox)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       int urgent_msgs;</span><br><span style="color: hsl(120, 100%, 40%);">+      int new_msgs;</span><br><span style="color: hsl(120, 100%, 40%);">+ int old_msgs;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_app_inboxcount2(mailbox, &urgent_msgs, &new_msgs, &old_msgs);</span><br><span style="color: hsl(120, 100%, 40%);">+ return mwi_create_state(mailbox, NULL, urgent_msgs, new_msgs, old_msgs);</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%);">+struct ast_mwi_state *ast_mwi_create(const char *mailbox, const char *context)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return mwi_create_state(mailbox, context, 0, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*!</span><br><span>  * \internal</span><br><span>  * \brief Create a MWI state snapshot message.</span><br><span>@@ -145,6 +169,7 @@</span><br><span> static struct stasis_message *mwi_state_create_message(</span><br><span>   const char *mailbox,</span><br><span>         const char *context,</span><br><span style="color: hsl(120, 100%, 40%);">+  int urgent_msgs,</span><br><span>     int new_msgs,</span><br><span>        int old_msgs,</span><br><span>        const char *channel_id,</span><br><span>@@ -157,14 +182,11 @@</span><br><span>              return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   mwi_state = ast_mwi_create(mailbox, context);</span><br><span style="color: hsl(120, 100%, 40%);">+ mwi_state = mwi_create_state(mailbox, context, urgent_msgs, new_msgs, old_msgs);</span><br><span>     if (!mwi_state) {</span><br><span>            return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   mwi_state->new_msgs = new_msgs;</span><br><span style="color: hsl(0, 100%, 40%);">-      mwi_state->old_msgs = old_msgs;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>   if (!ast_strlen_zero(channel_id)) {</span><br><span>          mwi_state->snapshot = ast_channel_snapshot_get_latest(channel_id);</span><br><span>        }</span><br><span>@@ -186,6 +208,183 @@</span><br><span>    return message;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This object currently acts as a typedef, but can also be thought of as a "child" object</span><br><span style="color: hsl(120, 100%, 40%);">+ * of the stasis_state_subscriber type. As such the "base" pointer should always be the</span><br><span style="color: hsl(120, 100%, 40%);">+ * first object attribute. Doing so allows this object to be easily type cast and used by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the stasis_state code.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_mwi_subscriber {</span><br><span style="color: hsl(120, 100%, 40%);">+      /*! The "base" state subscriber. (Must be first object attribute) */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct stasis_state_subscriber *base;</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%);">+struct ast_mwi_subscriber *ast_mwi_add_subscriber(const char *mailbox)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return (struct ast_mwi_subscriber *)stasis_state_add_subscriber(</span><br><span style="color: hsl(120, 100%, 40%);">+              mwi_state_manager, mailbox);</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%);">+struct ast_mwi_subscriber *ast_mwi_subscribe_pool(const char *mailbox,</span><br><span style="color: hsl(120, 100%, 40%);">+     stasis_subscription_cb callback, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct stasis_subscription *stasis_sub;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_mwi_subscriber *sub = (struct ast_mwi_subscriber *)stasis_state_subscribe_pool(</span><br><span style="color: hsl(120, 100%, 40%);">+            mwi_state_manager, mailbox, callback, data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!sub) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</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%);">+   stasis_sub = ast_mwi_subscriber_subscription(sub);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  stasis_subscription_accept_message_type(stasis_sub, ast_mwi_state_type());</span><br><span style="color: hsl(120, 100%, 40%);">+    stasis_subscription_set_filter(stasis_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return sub;</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%);">+void *ast_mwi_unsubscribe(struct ast_mwi_subscriber *sub)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return stasis_state_unsubscribe((struct stasis_state_subscriber *)sub);</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%);">+void *ast_mwi_unsubscribe_and_join(struct ast_mwi_subscriber *sub)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return stasis_state_unsubscribe_and_join((struct stasis_state_subscriber *)sub);</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%);">+struct stasis_topic *ast_mwi_subscriber_topic(struct ast_mwi_subscriber *sub)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return stasis_state_subscriber_topic((struct stasis_state_subscriber *)sub);</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%);">+struct ast_mwi_state *ast_mwi_subscriber_data(struct ast_mwi_subscriber *sub)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct stasis_state_subscriber *s = (struct stasis_state_subscriber *)sub;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_mwi_state *mwi_state = stasis_state_subscriber_data(s);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return mwi_state ?: mwi_retrieve_then_create_state(stasis_state_subscriber_id(s));</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%);">+struct stasis_subscription *ast_mwi_subscriber_subscription(struct ast_mwi_subscriber *sub)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return stasis_state_subscriber_subscription((struct stasis_state_subscriber *)sub);</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%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This object currently acts as a typedef, but can also be thought of as a "child" object</span><br><span style="color: hsl(120, 100%, 40%);">+ * of the stasis_state_publisher type. As such the "base" pointer should always be the</span><br><span style="color: hsl(120, 100%, 40%);">+ * first object attribute. Doing so allows this object to be easily type cast and used by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the stasis_state code.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_mwi_publisher {</span><br><span style="color: hsl(120, 100%, 40%);">+        /*! The "base" state publisher. (Must be first object attribute) */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct stasis_state_publisher *base;</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%);">+struct ast_mwi_publisher *ast_mwi_add_publisher(const char *mailbox)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return (struct ast_mwi_publisher *)stasis_state_add_publisher(</span><br><span style="color: hsl(120, 100%, 40%);">+                mwi_state_manager, mailbox);</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%);">+int ast_mwi_add_observer(struct ast_mwi_observer *observer)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     return stasis_state_add_observer(mwi_state_manager,</span><br><span style="color: hsl(120, 100%, 40%);">+           (struct stasis_state_observer *)observer);</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%);">+void ast_mwi_remove_observer(struct ast_mwi_observer *observer)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   stasis_state_remove_observer(mwi_state_manager,</span><br><span style="color: hsl(120, 100%, 40%);">+               (struct stasis_state_observer *)observer);</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%);">+struct mwi_handler_data {</span><br><span style="color: hsl(120, 100%, 40%);">+    on_mwi_state handler;</span><br><span style="color: hsl(120, 100%, 40%);">+ void *data;</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%);">+static int handle_mwi_state(const char *id, struct stasis_message *msg, void *user_data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct mwi_handler_data *d = user_data;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_mwi_state *mwi_state = stasis_message_data(msg);</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%);">+    if (mwi_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return d->handler(mwi_state, d->data);</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%);">+   mwi_state = mwi_create_state(id, NULL, 0, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!mwi_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</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 = d->handler(mwi_state, d->data);</span><br><span style="color: hsl(120, 100%, 40%);">+   ao2_ref(mwi_state, -1);</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%);">+void ast_mwi_state_callback_all(on_mwi_state handler, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct mwi_handler_data d = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .handler = handler,</span><br><span style="color: hsl(120, 100%, 40%);">+           .data = data</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%);">+  stasis_state_callback_all(mwi_state_manager, handle_mwi_state, &d);</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%);">+void ast_mwi_state_callback_subscribed(on_mwi_state handler, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct mwi_handler_data d = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .handler = handler,</span><br><span style="color: hsl(120, 100%, 40%);">+           .data = data</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%);">+  stasis_state_callback_subscribed(mwi_state_manager, handle_mwi_state, &d);</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%);">+int ast_mwi_publish(struct ast_mwi_publisher *pub, int urgent_msgs,</span><br><span style="color: hsl(120, 100%, 40%);">+      int new_msgs, int old_msgs, const char *channel_id, struct ast_eid *eid)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct stasis_state_publisher *p = (struct stasis_state_publisher *)pub;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct stasis_message *msg = mwi_state_create_message(stasis_state_publisher_id(p),</span><br><span style="color: hsl(120, 100%, 40%);">+           NULL, urgent_msgs, new_msgs, old_msgs, channel_id, eid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!msg) {</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%);">+   stasis_state_publish(p, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(msg, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</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%);">+int ast_mwi_publish_by_mailbox(const char *mailbox, const char *context, int urgent_msgs,</span><br><span style="color: hsl(120, 100%, 40%);">+     int new_msgs, int old_msgs, const char *channel_id, struct ast_eid *eid)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_mwi_state *mwi_state;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct stasis_message *msg = mwi_state_create_message(</span><br><span style="color: hsl(120, 100%, 40%);">+                mailbox, context, urgent_msgs, new_msgs, old_msgs, channel_id, eid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!msg) {</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%);">+   mwi_state = stasis_message_data(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ stasis_state_publish_by_id(mwi_state_manager, mwi_state->uniqueid, NULL, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     ao2_ref(msg, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int ast_publish_mwi_state_full(</span><br><span>    const char *mailbox,</span><br><span>         const char *context,</span><br><span>@@ -194,24 +393,7 @@</span><br><span>  const char *channel_id,</span><br><span>      struct ast_eid *eid)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       struct ast_mwi_state *mwi_state;</span><br><span style="color: hsl(0, 100%, 40%);">-        RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);</span><br><span style="color: hsl(0, 100%, 40%);">-  struct stasis_topic *mailbox_specific_topic;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    message = mwi_state_create_message(mailbox, context, new_msgs, old_msgs, channel_id, eid);</span><br><span style="color: hsl(0, 100%, 40%);">-      if (!message) {</span><br><span style="color: hsl(0, 100%, 40%);">-         return -1;</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%);">-       mwi_state = stasis_message_data(message);</span><br><span style="color: hsl(0, 100%, 40%);">-       mailbox_specific_topic = ast_mwi_topic(mwi_state->uniqueid);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!mailbox_specific_topic) {</span><br><span style="color: hsl(0, 100%, 40%);">-          return -1;</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%);">-       stasis_publish(mailbox_specific_topic, message);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     return ast_mwi_publish_by_mailbox(mailbox, context, 0, new_msgs, old_msgs, channel_id, eid);</span><br><span> }</span><br><span> </span><br><span> int ast_delete_mwi_state_full(const char *mailbox, const char *context, struct ast_eid *eid)</span><br><span>@@ -220,9 +402,8 @@</span><br><span>  struct stasis_message *cached_msg;</span><br><span>   struct stasis_message *clear_msg;</span><br><span>    struct ast_mwi_state *mwi_state;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct stasis_topic *mailbox_specific_topic;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        msg = mwi_state_create_message(mailbox, context, 0, 0, NULL, eid);</span><br><span style="color: hsl(120, 100%, 40%);">+    msg = mwi_state_create_message(mailbox, context, 0, 0, 0, NULL, eid);</span><br><span>        if (!msg) {</span><br><span>          return -1;</span><br><span>   }</span><br><span>@@ -244,22 +425,16 @@</span><br><span>    cached_msg = stasis_cache_get_by_eid(ast_mwi_state_cache(),</span><br><span>          ast_mwi_state_type(), mwi_state->uniqueid, &ast_eid_default);</span><br><span>         if (!cached_msg) {</span><br><span style="color: hsl(0, 100%, 40%);">-              /* Nothing to clear */</span><br><span style="color: hsl(120, 100%, 40%);">+                /* Nothing to clear from the cache, but still need to remove state */</span><br><span style="color: hsl(120, 100%, 40%);">+         stasis_state_remove_publish_by_id(mwi_state_manager, mwi_state->uniqueid, eid, NULL);</span><br><span>             return -1;</span><br><span>   }</span><br><span>    ao2_cleanup(cached_msg);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    mailbox_specific_topic = ast_mwi_topic(mwi_state->uniqueid);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!mailbox_specific_topic) {</span><br><span style="color: hsl(0, 100%, 40%);">-          return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    clear_msg = stasis_cache_clear_create(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-     if (clear_msg) {</span><br><span style="color: hsl(0, 100%, 40%);">-                stasis_publish(mailbox_specific_topic, clear_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+     stasis_state_remove_publish_by_id(mwi_state_manager, mwi_state->uniqueid, eid, clear_msg);</span><br><span>        ao2_cleanup(clear_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    return 0;</span><br><span> }</span><br><span> </span><br><span>@@ -315,13 +490,11 @@</span><br><span> </span><br><span> static void mwi_cleanup(void)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    ao2_cleanup(mwi_topic_pool);</span><br><span style="color: hsl(0, 100%, 40%);">-    mwi_topic_pool = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-  ao2_cleanup(mwi_topic_all);</span><br><span style="color: hsl(0, 100%, 40%);">-     mwi_topic_all = NULL;</span><br><span>        ao2_cleanup(mwi_state_cache);</span><br><span>        mwi_state_cache = NULL;</span><br><span>      mwi_topic_cached = stasis_caching_unsubscribe_and_join(mwi_topic_cached);</span><br><span style="color: hsl(120, 100%, 40%);">+     ao2_cleanup(mwi_state_manager);</span><br><span style="color: hsl(120, 100%, 40%);">+       mwi_state_manager = NULL;</span><br><span>    STASIS_MESSAGE_TYPE_CLEANUP(ast_mwi_state_type);</span><br><span>     STASIS_MESSAGE_TYPE_CLEANUP(ast_mwi_vm_app_type);</span><br><span> }</span><br><span>@@ -338,8 +511,8 @@</span><br><span>                 return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   mwi_topic_all = stasis_topic_create("mwi:all");</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!mwi_topic_all) {</span><br><span style="color: hsl(120, 100%, 40%);">+ mwi_state_manager = stasis_state_manager_create("mwi:all");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!mwi_state_manager) {</span><br><span>            return -1;</span><br><span>   }</span><br><span> </span><br><span>@@ -348,15 +521,10 @@</span><br><span>                return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   mwi_topic_cached = stasis_caching_topic_create(mwi_topic_all, mwi_state_cache);</span><br><span style="color: hsl(120, 100%, 40%);">+       mwi_topic_cached = stasis_caching_topic_create(ast_mwi_topic_all(), mwi_state_cache);</span><br><span>        if (!mwi_topic_cached) {</span><br><span>             return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   mwi_topic_pool = stasis_topic_pool_create(mwi_topic_all);</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!mwi_topic_pool) {</span><br><span style="color: hsl(0, 100%, 40%);">-          return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    return 0;</span><br><span> }</span><br><span>diff --git a/tests/test_mwi.c b/tests/test_mwi.c</span><br><span>new file mode 100644</span><br><span>index 0000000..3f633b3</span><br><span>--- /dev/null</span><br><span>+++ b/tests/test_mwi.c</span><br><span>@@ -0,0 +1,407 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2019, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Kevin Harwell <kharwell@digium.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</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%);">+/*** MODULEINFO</span><br><span style="color: hsl(120, 100%, 40%);">+      <depend>TEST_FRAMEWORK</depend></span><br><span style="color: hsl(120, 100%, 40%);">+   <support_level>core</support_level></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%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/astobj2.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/conversions.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/module.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/mwi.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/stasis.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/test.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define test_category "/mwi/"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define MAILBOX_PREFIX "test~" /* Hopefully sufficiently unlikely */</span><br><span style="color: hsl(120, 100%, 40%);">+#define MAILBOX_COUNT 500</span><br><span style="color: hsl(120, 100%, 40%);">+#define MAILBOX_SIZE 32</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AST_VECTOR(subscriptions, struct ast_mwi_subscriber *);</span><br><span style="color: hsl(120, 100%, 40%);">+AST_VECTOR(publishers, struct ast_mwi_publisher *);</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%);">+ * For testing purposes each subscribed mailbox is a number. This value is</span><br><span style="color: hsl(120, 100%, 40%);">+ * the summation of all mailboxes.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static size_t sum_total;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Test variable that tracks the running total of mailboxes */</span><br><span style="color: hsl(120, 100%, 40%);">+static size_t running_total;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! This value is set to check if MWI data is zero before publishing */</span><br><span style="color: hsl(120, 100%, 40%);">+static int expect_zero;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int num_to_mailbox(char *mailbox, size_t size, size_t num)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      if (snprintf(mailbox, 10, MAILBOX_PREFIX "%zu", num) == -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "Unable to convert mailbox to string\n");</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%);">+   return 0;</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%);">+static int mailbox_to_num(const char *mailbox, size_t *num)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        const char *p = strchr(mailbox, '~');</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!p) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_log(LOG_ERROR, "Prefix separator '~' not found in '%s'\n", mailbox);</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%);">+   if (ast_str_to_umax(++p, num)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "Unable to convert mailbox '%s' to numeric\n", mailbox);</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%);">+   return 0;</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%);">+static int validate_data(struct ast_mwi_state *mwi_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  size_t num;</span><br><span style="color: hsl(120, 100%, 40%);">+   size_t val;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (mailbox_to_num(mwi_state->uniqueid, &num)) {</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%);">+   running_total += num;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       val = expect_zero ? 0 : num;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (mwi_state->urgent_msgs != val || mwi_state->new_msgs != val ||</span><br><span style="color: hsl(120, 100%, 40%);">+                      mwi_state->old_msgs != val) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "Unexpected MWI state data for '%s', %d != %zu\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                               mwi_state->uniqueid, mwi_state->urgent_msgs, val);</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%);">+   return num;</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%);">+static void handle_validate(const char *mailbox, struct ast_mwi_subscriber *sub)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_mwi_state *mwi_state = ast_mwi_subscriber_data(sub);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ast_begins_with(mwi_state->uniqueid, MAILBOX_PREFIX)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                validate_data(mwi_state);</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%);">+   ao2_cleanup(mwi_state);</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%);">+struct ast_mwi_observer mwi_observer = {</span><br><span style="color: hsl(120, 100%, 40%);">+        .on_subscribe = handle_validate,</span><br><span style="color: hsl(120, 100%, 40%);">+      .on_unsubscribe = handle_validate</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%);">+static void mwi_type_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      /* No op since we are not really testing stasis topic handling here */</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%);">+static int subscriptions_destroy(struct subscriptions *subs)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  running_total = expect_zero = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_VECTOR_CALLBACK_VOID(subs, ast_mwi_unsubscribe_and_join);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_FREE(subs);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_mwi_remove_observer(&mwi_observer);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (running_total != sum_total) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_log(LOG_ERROR, "Failed to destroy all MWI subscriptions: running=%zu, sum=%zu\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                               running_total, sum_total);</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%);">+   return 0;</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%);">+static int subscriptions_create(struct subscriptions *subs)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        size_t i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ast_mwi_add_observer(&mwi_observer) ||</span><br><span style="color: hsl(120, 100%, 40%);">+                AST_VECTOR_INIT(subs, MAILBOX_COUNT)) {</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%);">+   sum_total = running_total = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        expect_zero = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    for (i = 0; i < MAILBOX_COUNT; ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+              struct ast_mwi_subscriber *sub;</span><br><span style="color: hsl(120, 100%, 40%);">+               char mailbox[MAILBOX_SIZE];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         if (num_to_mailbox(mailbox, MAILBOX_SIZE, i)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       break;</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%);">+           sub = ast_mwi_subscribe_pool(mailbox, mwi_type_cb, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!sub) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_log(LOG_ERROR, "Failed to create a MWI subscriber for mailbox '%s'\n", mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+                        break;</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%);">+           if (AST_VECTOR_APPEND(subs, sub)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_log(LOG_ERROR, "Failed to add to MWI sub to vector for mailbox '%s'\n", mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+                       ao2_ref(sub, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</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%);">+           sum_total += i;</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%);">+   if (i != MAILBOX_COUNT || running_total != sum_total) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "Failed to create all MWI subscriptions: running=%zu, sum=%zu\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                running_total, sum_total);</span><br><span style="color: hsl(120, 100%, 40%);">+            subscriptions_destroy(subs);</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%);">+   return 0;</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%);">+static int publishers_destroy(struct publishers *pubs)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     size_t i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (pubs) {</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Remove explicit publishers */</span><br><span style="color: hsl(120, 100%, 40%);">+              AST_VECTOR_CALLBACK_VOID(pubs, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+          AST_VECTOR_FREE(pubs);</span><br><span style="color: hsl(120, 100%, 40%);">+                return 0;</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%);">+   for (i = 0; i < MAILBOX_COUNT; ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+              char mailbox[MAILBOX_SIZE];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         /* Remove implicit publishers */</span><br><span style="color: hsl(120, 100%, 40%);">+              if (num_to_mailbox(mailbox, MAILBOX_SIZE, i)) {</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%);">+           ast_delete_mwi_state(mailbox, NULL);</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 0;</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%);">+static int publishers_create(struct publishers *pubs)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      size_t i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (AST_VECTOR_INIT(pubs, MAILBOX_COUNT)) {</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%);">+   for (i = 0; i < MAILBOX_COUNT; ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+              struct ast_mwi_publisher *pub;</span><br><span style="color: hsl(120, 100%, 40%);">+                char mailbox[MAILBOX_SIZE];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         if (num_to_mailbox(mailbox, MAILBOX_SIZE, i)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       break;</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%);">+           /* Create the MWI publisher */</span><br><span style="color: hsl(120, 100%, 40%);">+                pub = ast_mwi_add_publisher(mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!pub) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_log(LOG_ERROR, "Failed to create an MWI publisher for mailbox '%s'\n", mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+                        break;</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%);">+           if (AST_VECTOR_APPEND(pubs, pub)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_log(LOG_ERROR, "Failed to add to an MWI publisher to vector for mailbox '%s'\n", mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+                      ao2_ref(pub, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</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%);">+   if (i != MAILBOX_COUNT) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_log(LOG_ERROR, "Failed to create all MWI publishers: count=%zu\n", i);</span><br><span style="color: hsl(120, 100%, 40%);">+          publishers_destroy(pubs);</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%);">+   return 0;</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%);">+static int implicit_publish_cb(struct ast_mwi_state *mwi_state, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        size_t num;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_begins_with(mwi_state->uniqueid, MAILBOX_PREFIX)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Ignore any mailboxes not prefixed */</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0;</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%);">+   num = validate_data(mwi_state);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (num < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             return CMP_STOP;</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%);">+   ast_mwi_publish_by_mailbox(mwi_state->uniqueid, NULL, num, num, num, NULL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</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%);">+static int explicit_publish_cb(struct ast_mwi_state *mwi_state, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct publishers *pubs = data;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_mwi_publisher *pub;</span><br><span style="color: hsl(120, 100%, 40%);">+        size_t num;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_begins_with(mwi_state->uniqueid, MAILBOX_PREFIX)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Ignore any mailboxes not prefixed */</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0;</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%);">+   num = validate_data(mwi_state);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (num < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             return CMP_STOP;</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%);">+   if (mailbox_to_num(mwi_state->uniqueid, &num)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               return CMP_STOP;</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%);">+   /* Mailbox number will always be the index */</span><br><span style="color: hsl(120, 100%, 40%);">+ pub = AST_VECTOR_GET(pubs, num);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!pub) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_log(LOG_ERROR, "Unable to locate MWI publisher for mailbox '%s'\n", mwi_state->uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+            return CMP_STOP;</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%);">+   ast_mwi_publish(pub, num, num, num, NULL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0;</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%);">+static int publish(on_mwi_state cb, void *user_data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       /* First time there is no state data */</span><br><span style="color: hsl(120, 100%, 40%);">+       expect_zero = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    running_total = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_mwi_state_callback_all(cb, user_data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (running_total != sum_total) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_log(LOG_ERROR, "Failed MWI state callback (1): running=%zu, sum=%zu\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         running_total, sum_total);</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%);">+   /* Second time check valid state data exists */</span><br><span style="color: hsl(120, 100%, 40%);">+       running_total = expect_zero = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_mwi_state_callback_all(cb, user_data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (running_total != sum_total) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_log(LOG_ERROR, "Failed MWI state callback (2): running=%zu, sum=%zu\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         running_total, sum_total);</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%);">+   return 0;</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%);">+AST_TEST_DEFINE(implicit_publish)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct subscriptions subs;</span><br><span style="color: hsl(120, 100%, 40%);">+    int rc = AST_TEST_PASS;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case TEST_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+               info->name = __func__;</span><br><span style="color: hsl(120, 100%, 40%);">+             info->category = test_category;</span><br><span style="color: hsl(120, 100%, 40%);">+            info->summary = "Test implicit publishing of MWI state";</span><br><span style="color: hsl(120, 100%, 40%);">+         info->description = info->summary;</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_NOT_RUN;</span><br><span style="color: hsl(120, 100%, 40%);">+      case TEST_EXECUTE:</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</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%);">+   ast_test_validate(test, !subscriptions_create(&subs));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_test_validate_cleanup(test, !publish(implicit_publish_cb, NULL),</span><br><span style="color: hsl(120, 100%, 40%);">+          rc, cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+cleanup:</span><br><span style="color: hsl(120, 100%, 40%);">+     if (subscriptions_destroy(&subs) || publishers_destroy(NULL)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return AST_TEST_FAIL;</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 rc;</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%);">+AST_TEST_DEFINE(explicit_publish)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct subscriptions subs;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct publishers pubs;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc = AST_TEST_PASS;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case TEST_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+               info->name = __func__;</span><br><span style="color: hsl(120, 100%, 40%);">+             info->category = test_category;</span><br><span style="color: hsl(120, 100%, 40%);">+            info->summary = "Test explicit publishing of MWI state";</span><br><span style="color: hsl(120, 100%, 40%);">+         info->description = info->summary;</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_NOT_RUN;</span><br><span style="color: hsl(120, 100%, 40%);">+      case TEST_EXECUTE:</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</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%);">+   ast_test_validate(test, !subscriptions_create(&subs));</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_test_validate_cleanup(test, !publishers_create(&pubs), rc, cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_test_validate_cleanup(test, !publish(explicit_publish_cb, &pubs),</span><br><span style="color: hsl(120, 100%, 40%);">+             rc, cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+cleanup:</span><br><span style="color: hsl(120, 100%, 40%);">+     if (subscriptions_destroy(&subs) || publishers_destroy(&pubs)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</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 rc;</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%);">+static int unload_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_TEST_UNREGISTER(implicit_publish);</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_TEST_UNREGISTER(explicit_publish);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</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%);">+static int load_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_TEST_REGISTER(implicit_publish);</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_TEST_REGISTER(explicit_publish);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return AST_MODULE_LOAD_SUCCESS;</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%);">+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "MWI testing");</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/11463">change 11463</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/+/11463"/><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-Change-Id: I93f935f9090cd5ddff6d4bc80ff90703c05cf776 </div>
<div style="display:none"> Gerrit-Change-Number: 11463 </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@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>