diff --git a/apps/app_minivm.c b/apps/app_minivm.c index 211acc1db5d0a3c020305d88d8cca98ac5e1eaec..5c9e57e27e27496f52c6467a9c4dc46598dc3cb0 100644 --- a/apps/app_minivm.c +++ b/apps/app_minivm.c @@ -164,6 +164,7 @@ #include "asterisk/say.h" #include "asterisk/module.h" #include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/dsp.h" #include "asterisk/localtime.h" #include "asterisk/cli.h" diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 5c06be711a471e2bf6b9754d2a09c5a266099b1a..c0edd447b5ce4e443ae1cabb76d869650b09c29a 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -120,6 +120,7 @@ #include "asterisk/module.h" #include "asterisk/adsi.h" #include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/manager.h" #include "asterisk/dsp.h" #include "asterisk/localtime.h" diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 9f030420931ae44af077c48dcc96e8d37b558aad..29d3b91a934c0f3fc06f400352f9ba6fc3771723 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -107,7 +107,7 @@ #include "asterisk/musiconhold.h" #include "asterisk/say.h" #include "asterisk/tdd.h" -#include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/dsp.h" #include "asterisk/astdb.h" #include "asterisk/manager.h" diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 6f88d098cd17b20886ac8b1c18a9dd992cd9db32..e41d9919040463f6f8c809df6b6bb8de3b9df0a2 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -92,6 +92,7 @@ #include "asterisk/manager.h" #include "asterisk/callerid.h" #include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/astdb.h" #include "asterisk/musiconhold.h" #include "asterisk/features.h" diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index 46342ce31240e27b525d342403d13fcdf5645d16..fa3a0814697a1720393c7aefbba56cc72b5886d5 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -68,6 +68,7 @@ #include "asterisk/astdb.h" #include "asterisk/features.h" #include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/musiconhold.h" #include "asterisk/utils.h" #include "asterisk/netsock2.h" diff --git a/channels/chan_sip.c b/channels/chan_sip.c index bb2de27db05f23f6892c4de303e51a4fb9e8ea46..cd0db387afd9e8194b1f7051ea19694226fb9865 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -278,7 +278,7 @@ #include "sip/include/security_events.h" #include "sip/include/route.h" #include "asterisk/sip_api.h" -#include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/bridge.h" #include "asterisk/stasis.h" #include "asterisk/stasis_endpoints.h" diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index 910b7b811763255da10faa984bfaee0cf83896e6..fb31c9ffd03f6e0eaf943375f6621ab175c85e72 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -68,6 +68,7 @@ #include "asterisk/causes.h" #include "asterisk/pickup.h" #include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/musiconhold.h" #include "asterisk/utils.h" #include "asterisk/dsp.h" diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c index 7051961018dc3b02ac16fee4981097352503bf71..c1328c1f9a4a0f978bef7b4e1e4ddb14e378a5c6 100644 --- a/channels/chan_unistim.c +++ b/channels/chan_unistim.c @@ -67,6 +67,7 @@ #include "asterisk/callerid.h" #include "asterisk/cli.h" #include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/musiconhold.h" #include "asterisk/causes.h" #include "asterisk/indications.h" diff --git a/include/asterisk/app.h b/include/asterisk/app.h index 9aea08d181a4df8d5a311f605f6c71f5eea356b5..42645560ede8032385096ff262aa65dd91a625fb 100644 --- a/include/asterisk/app.h +++ b/include/asterisk/app.h @@ -1469,200 +1469,6 @@ void ast_safe_fork_cleanup(void); */ int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen defunit); -/*! - * \since 12 - * \brief Publish a MWI state update via stasis - * - * \param[in] mailbox The mailbox identifier string. - * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) - * \param[in] new_msgs The number of new messages in this mailbox - * \param[in] old_msgs The number of old messages in this mailbox - * - * \retval 0 Success - * \retval -1 Failure - */ -#define ast_publish_mwi_state(mailbox, context, new_msgs, old_msgs) \ - ast_publish_mwi_state_full(mailbox, context, new_msgs, old_msgs, NULL, NULL) - -/*! - * \since 12 - * \brief Publish a MWI state update associated with some channel - * - * \param[in] mailbox The mailbox identifier string. - * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) - * \param[in] new_msgs The number of new messages in this mailbox - * \param[in] old_msgs The number of old messages in this mailbox - * \param[in] channel_id A unique identifier for a channel associated with this - * change in mailbox state - * - * \retval 0 Success - * \retval -1 Failure - */ -#define ast_publish_mwi_state_channel(mailbox, context, new_msgs, old_msgs, channel_id) \ - ast_publish_mwi_state_full(mailbox, context, new_msgs, old_msgs, channel_id, NULL) - -/*! - * \since 12 - * \brief Publish a MWI state update via stasis with all parameters - * - * \param[in] mailbox The mailbox identifier string. - * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) - * \param[in] new_msgs The number of new messages in this mailbox - * \param[in] old_msgs The number of old messages in this mailbox - * \param[in] channel_id A unique identifier for a channel associated with this - * change in mailbox state - * \param[in] eid The EID of the server that originally published the message - * - * \retval 0 Success - * \retval -1 Failure - */ -int ast_publish_mwi_state_full( - const char *mailbox, - const char *context, - int new_msgs, - int old_msgs, - const char *channel_id, - struct ast_eid *eid); - -/*! - * \since 12.2.0 - * \brief Delete MWI state cached by stasis - * - * \param[in] mailbox The mailbox identifier string. - * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) - * - * \retval 0 Success - * \retval -1 Failure - */ -#define ast_delete_mwi_state(mailbox, context) \ - ast_delete_mwi_state_full(mailbox, context, NULL) - -/*! - * \since 12.2.0 - * \brief Delete MWI state cached by stasis with all parameters - * - * \param[in] mailbox The mailbox identifier string. - * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) - * \param[in] eid The EID of the server that originally published the message - * - * \retval 0 Success - * \retval -1 Failure - */ -int ast_delete_mwi_state_full(const char *mailbox, const char *context, struct ast_eid *eid); - -/*! \addtogroup StasisTopicsAndMessages - * @{ - */ - -/*! - * \brief The structure that contains MWI state - * \since 12 - */ -struct ast_mwi_state { - AST_DECLARE_STRING_FIELDS( - AST_STRING_FIELD(uniqueid); /*!< Unique identifier for this mailbox */ - ); - int new_msgs; /*!< The current number of new messages for this mailbox */ - int old_msgs; /*!< The current number of old messages for this mailbox */ - /*! If applicable, a snapshot of the channel that caused this MWI change */ - struct ast_channel_snapshot *snapshot; - struct ast_eid eid; /*!< The EID of the server where this message originated */ -}; - -/*! - * \brief Object that represents an MWI update with some additional application - * defined data - */ -struct ast_mwi_blob { - struct ast_mwi_state *mwi_state; /*!< MWI state */ - struct ast_json *blob; /*!< JSON blob of data */ -}; - -/*! - * \since 12 - * \brief Create a \ref ast_mwi_state object - * - * \param[in] mailbox The mailbox identifier string. - * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) - * - * \retval \ref ast_mwi_state object on success - * \retval NULL on error - */ -struct ast_mwi_state *ast_mwi_create(const char *mailbox, const char *context); - -/*! - * \since 12 - * \brief Creates a \ref ast_mwi_blob message. - * - * The \a blob JSON object requires a \c "type" field describing the blob. It - * should also be treated as immutable and not modified after it is put into the - * message. - * - * \param mwi_state MWI state associated with the update - * \param message_type The type of message to create - * \param blob JSON object representing the data. - * \return \ref ast_mwi_blob message. - * \return \c NULL on error - */ -struct stasis_message *ast_mwi_blob_create(struct ast_mwi_state *mwi_state, - struct stasis_message_type *message_type, - struct ast_json *blob); - -/*! - * \brief Get the \ref stasis topic for MWI messages - * \retval The topic structure for MWI messages - * \retval NULL if it has not been allocated - * \since 12 - */ -struct stasis_topic *ast_mwi_topic_all(void); - -/*! - * \brief Get the \ref stasis topic for MWI messages on a unique ID - * \param uniqueid The unique id for which to get the topic - * \retval The topic structure for MWI messages for a given uniqueid - * \retval NULL if it failed to be found or allocated - * \since 12 - */ -struct stasis_topic *ast_mwi_topic(const char *uniqueid); - -/*! - * \brief Get the \ref stasis caching topic for MWI messages - * \retval The caching topic structure for MWI messages - * \retval NULL if it has not been allocated - * \since 12 - */ -struct stasis_topic *ast_mwi_topic_cached(void); - -/*! - * \brief Backend cache for ast_mwi_topic_cached(). - * \retval Cache of \ref ast_mwi_state. - */ -struct stasis_cache *ast_mwi_state_cache(void); - -/*! - * \brief Get the \ref stasis message type for MWI messages - * \retval The message type structure for MWI messages - * \retval NULL on error - * \since 12 - */ -struct stasis_message_type *ast_mwi_state_type(void); - -/*! - * \brief Get the \ref stasis message type for voicemail application specific messages - * - * This message type exists for those messages a voicemail application may wish to send - * that have no logical relationship with other voicemail applications. Voicemail apps - * that use this message type must pass a \ref ast_mwi_blob. Any extraneous information - * in the JSON blob must be packed as key/value pair tuples of strings. - * - * At least one key/value tuple must have a key value of "Event". - * - * \retval The \ref stasis_message_type for voicemail application specific messages - * \retval NULL on error - * \since 12 - */ -struct stasis_message_type *ast_mwi_vm_app_type(void); - /*! * \brief Get the \ref stasis topic for queue messages * \retval The topic structure for queue messages @@ -1689,7 +1495,6 @@ struct stasis_topic *ast_queue_topic(const char *queuename); */ int app_init(void); -#define AST_MAX_MAILBOX_UNIQUEID (AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2) #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/include/asterisk/mwi.h b/include/asterisk/mwi.h new file mode 100644 index 0000000000000000000000000000000000000000..150222406dabf3e6fdeecb1004235caf07d0346b --- /dev/null +++ b/include/asterisk/mwi.h @@ -0,0 +1,242 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2019, Sangoma Technologies Corporation + * + * Kevin Harwell <kharwell@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#ifndef _ASTERISK_MWI_H +#define _ASTERISK_MWI_H + +#include "asterisk/utils.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +struct ast_json; +struct stasis_message_type; + +/*! + * \since 12 + * \brief Publish a MWI state update via stasis + * + * \param[in] mailbox The mailbox identifier string. + * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) + * \param[in] new_msgs The number of new messages in this mailbox + * \param[in] old_msgs The number of old messages in this mailbox + * + * \retval 0 Success + * \retval -1 Failure + */ +#define ast_publish_mwi_state(mailbox, context, new_msgs, old_msgs) \ + ast_publish_mwi_state_full(mailbox, context, new_msgs, old_msgs, NULL, NULL) + +/*! + * \since 12 + * \brief Publish a MWI state update associated with some channel + * + * \param[in] mailbox The mailbox identifier string. + * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) + * \param[in] new_msgs The number of new messages in this mailbox + * \param[in] old_msgs The number of old messages in this mailbox + * \param[in] channel_id A unique identifier for a channel associated with this + * change in mailbox state + * + * \retval 0 Success + * \retval -1 Failure + */ +#define ast_publish_mwi_state_channel(mailbox, context, new_msgs, old_msgs, channel_id) \ + ast_publish_mwi_state_full(mailbox, context, new_msgs, old_msgs, channel_id, NULL) + +/*! + * \since 12 + * \brief Publish a MWI state update via stasis with all parameters + * + * \param[in] mailbox The mailbox identifier string. + * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) + * \param[in] new_msgs The number of new messages in this mailbox + * \param[in] old_msgs The number of old messages in this mailbox + * \param[in] channel_id A unique identifier for a channel associated with this + * change in mailbox state + * \param[in] eid The EID of the server that originally published the message + * + * \retval 0 Success + * \retval -1 Failure + */ +int ast_publish_mwi_state_full( + const char *mailbox, + const char *context, + int new_msgs, + int old_msgs, + const char *channel_id, + struct ast_eid *eid); + +/*! + * \since 12.2.0 + * \brief Delete MWI state cached by stasis + * + * \param[in] mailbox The mailbox identifier string. + * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) + * + * \retval 0 Success + * \retval -1 Failure + */ +#define ast_delete_mwi_state(mailbox, context) \ + ast_delete_mwi_state_full(mailbox, context, NULL) + +/*! + * \since 12.2.0 + * \brief Delete MWI state cached by stasis with all parameters + * + * \param[in] mailbox The mailbox identifier string. + * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) + * \param[in] eid The EID of the server that originally published the message + * + * \retval 0 Success + * \retval -1 Failure + */ +int ast_delete_mwi_state_full(const char *mailbox, const char *context, struct ast_eid *eid); + +/*! \addtogroup StasisTopicsAndMessages + * @{ + */ + +/*! + * \brief The structure that contains MWI state + * \since 12 + */ +struct ast_mwi_state { + AST_DECLARE_STRING_FIELDS( + AST_STRING_FIELD(uniqueid); /*!< Unique identifier for this mailbox */ + ); + int new_msgs; /*!< The current number of new messages for this mailbox */ + int old_msgs; /*!< The current number of old messages for this mailbox */ + /*! If applicable, a snapshot of the channel that caused this MWI change */ + struct ast_channel_snapshot *snapshot; + struct ast_eid eid; /*!< The EID of the server where this message originated */ +}; + +/*! + * \brief Object that represents an MWI update with some additional application + * defined data + */ +struct ast_mwi_blob { + struct ast_mwi_state *mwi_state; /*!< MWI state */ + struct ast_json *blob; /*!< JSON blob of data */ +}; + +/*! + * \since 12 + * \brief Create a \ref ast_mwi_state object + * + * \param[in] mailbox The mailbox identifier string. + * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) + * + * \retval \ref ast_mwi_state object on success + * \retval NULL on error + */ +struct ast_mwi_state *ast_mwi_create(const char *mailbox, const char *context); + +/*! + * \since 12 + * \brief Creates a \ref ast_mwi_blob message. + * + * The \a blob JSON object requires a \c "type" field describing the blob. It + * should also be treated as immutable and not modified after it is put into the + * message. + * + * \param mwi_state MWI state associated with the update + * \param message_type The type of message to create + * \param blob JSON object representing the data. + * \return \ref ast_mwi_blob message. + * \return \c NULL on error + */ +struct stasis_message *ast_mwi_blob_create(struct ast_mwi_state *mwi_state, + struct stasis_message_type *message_type, + struct ast_json *blob); + +/*! + * \brief Get the \ref stasis topic for MWI messages + * \retval The topic structure for MWI messages + * \retval NULL if it has not been allocated + * \since 12 + */ +struct stasis_topic *ast_mwi_topic_all(void); + +/*! + * \brief Get the \ref stasis topic for MWI messages on a unique ID + * \param uniqueid The unique id for which to get the topic + * \retval The topic structure for MWI messages for a given uniqueid + * \retval NULL if it failed to be found or allocated + * \since 12 + */ +struct stasis_topic *ast_mwi_topic(const char *uniqueid); + +/*! + * \brief Get the \ref stasis caching topic for MWI messages + * \retval The caching topic structure for MWI messages + * \retval NULL if it has not been allocated + * \since 12 + */ +struct stasis_topic *ast_mwi_topic_cached(void); + +/*! + * \brief Backend cache for ast_mwi_topic_cached(). + * \retval Cache of \ref ast_mwi_state. + */ +struct stasis_cache *ast_mwi_state_cache(void); + +/*! + * \brief Get the \ref stasis message type for MWI messages + * \retval The message type structure for MWI messages + * \retval NULL on error + * \since 12 + */ +struct stasis_message_type *ast_mwi_state_type(void); + +/*! + * \brief Get the \ref stasis message type for voicemail application specific messages + * + * This message type exists for those messages a voicemail application may wish to send + * that have no logical relationship with other voicemail applications. Voicemail apps + * that use this message type must pass a \ref ast_mwi_blob. Any extraneous information + * in the JSON blob must be packed as key/value pair tuples of strings. + * + * At least one key/value tuple must have a key value of "Event". + * + * \retval The \ref stasis_message_type for voicemail application specific messages + * \retval NULL on error + * \since 12 + */ +struct stasis_message_type *ast_mwi_vm_app_type(void); + +/*! + * \brief Initialize the mwi core + * + * \retval 0 Success + * \retval -1 Failure + * + * \since 13.26.0 + * \since 16.4.0 + */ +int mwi_init(void); + +#define AST_MAX_MAILBOX_UNIQUEID (AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2) + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* _ASTERISK_MWI_H */ diff --git a/main/app.c b/main/app.c index d272e40b42f8772169061d82f7a2faa1b9b2ed95..701bbd847cdd681b7cb3205737d2eddba190732a 100644 --- a/main/app.c +++ b/main/app.c @@ -70,8 +70,6 @@ #include "asterisk/json.h" #include "asterisk/format_cache.h" -#define MWI_TOPIC_BUCKETS 57 - AST_THREADSTORAGE_PUBLIC(ast_str_thread_global_buf); static pthread_t shaun_of_the_dead_thread = AST_PTHREADT_NULL; @@ -86,57 +84,10 @@ static AST_LIST_HEAD_STATIC(zombies, zombie); /* * @{ \brief Define \ref stasis topic objects */ -static struct stasis_topic *mwi_topic_all; -static struct stasis_cache *mwi_state_cache; -static struct stasis_caching_topic *mwi_topic_cached; -static struct stasis_topic_pool *mwi_topic_pool; - static struct stasis_topic *queue_topic_all; static struct stasis_topic_pool *queue_topic_pool; /* @} */ -/*! \brief Convert a MWI \ref stasis_message to a \ref ast_event */ -static struct ast_event *mwi_to_event(struct stasis_message *message) -{ - struct ast_event *event; - struct ast_mwi_state *mwi_state; - char *mailbox; - char *context; - - if (!message) { - return NULL; - } - - mwi_state = stasis_message_data(message); - - /* Strip off @context */ - context = mailbox = ast_strdupa(mwi_state->uniqueid); - strsep(&context, "@"); - if (ast_strlen_zero(context)) { - context = "default"; - } - - event = ast_event_new(AST_EVENT_MWI, - AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox, - AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context, - AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, mwi_state->new_msgs, - AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, mwi_state->old_msgs, - AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, &mwi_state->eid, sizeof(mwi_state->eid), - AST_EVENT_IE_END); - - return event; -} - -/* - * @{ \brief Define \ref stasis message types for MWI - */ -STASIS_MESSAGE_TYPE_DEFN(ast_mwi_state_type, - .to_event = mwi_to_event, ); -STASIS_MESSAGE_TYPE_DEFN(ast_mwi_vm_app_type); -/* @} */ - - - static void *shaun_of_the_dead(void *data) { struct zombie *cur; @@ -3150,247 +3101,6 @@ int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen uni return 0; } - - -static void mwi_state_dtor(void *obj) -{ - struct ast_mwi_state *mwi_state = obj; - ast_string_field_free_memory(mwi_state); - ao2_cleanup(mwi_state->snapshot); - mwi_state->snapshot = NULL; -} - -struct stasis_topic *ast_mwi_topic_all(void) -{ - return mwi_topic_all; -} - -struct stasis_cache *ast_mwi_state_cache(void) -{ - return mwi_state_cache; -} - -struct stasis_topic *ast_mwi_topic_cached(void) -{ - return stasis_caching_get_topic(mwi_topic_cached); -} - -struct stasis_topic *ast_mwi_topic(const char *uniqueid) -{ - return stasis_topic_pool_get_topic(mwi_topic_pool, uniqueid); -} - -struct ast_mwi_state *ast_mwi_create(const char *mailbox, const char *context) -{ - struct ast_mwi_state *mwi_state; - - ast_assert(!ast_strlen_zero(mailbox)); - - mwi_state = ao2_alloc(sizeof(*mwi_state), mwi_state_dtor); - if (!mwi_state) { - return NULL; - } - - if (ast_string_field_init(mwi_state, 256)) { - ao2_ref(mwi_state, -1); - return NULL; - } - if (!ast_strlen_zero(context)) { - ast_string_field_build(mwi_state, uniqueid, "%s@%s", mailbox, context); - } else { - ast_string_field_set(mwi_state, uniqueid, mailbox); - } - - return mwi_state; -} - -/*! - * \internal - * \brief Create a MWI state snapshot message. - * \since 12.2.0 - * - * \param[in] mailbox The mailbox identifier string. - * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) - * \param[in] new_msgs The number of new messages in this mailbox - * \param[in] old_msgs The number of old messages in this mailbox - * \param[in] channel_id A unique identifier for a channel associated with this - * change in mailbox state - * \param[in] eid The EID of the server that originally published the message - * - * \retval message on success. Use ao2_cleanup() when done with it. - * \retval NULL on error. - */ -static struct stasis_message *mwi_state_create_message( - const char *mailbox, - const char *context, - int new_msgs, - int old_msgs, - const char *channel_id, - struct ast_eid *eid) -{ - struct ast_mwi_state *mwi_state; - struct stasis_message *message; - - if (!ast_mwi_state_type()) { - return NULL; - } - - mwi_state = ast_mwi_create(mailbox, context); - if (!mwi_state) { - return NULL; - } - - mwi_state->new_msgs = new_msgs; - mwi_state->old_msgs = old_msgs; - - if (!ast_strlen_zero(channel_id)) { - mwi_state->snapshot = ast_channel_snapshot_get_latest(channel_id); - } - - if (eid) { - mwi_state->eid = *eid; - } else { - mwi_state->eid = ast_eid_default; - } - - /* - * XXX As far as stasis is concerned, all MWI events are local. - * - * We may in the future want to make MWI aggregate local/remote - * message counts similar to how device state aggregates state. - */ - message = stasis_message_create_full(ast_mwi_state_type(), mwi_state, &ast_eid_default); - ao2_cleanup(mwi_state); - return message; -} - -int ast_publish_mwi_state_full( - const char *mailbox, - const char *context, - int new_msgs, - int old_msgs, - const char *channel_id, - struct ast_eid *eid) -{ - struct ast_mwi_state *mwi_state; - RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup); - struct stasis_topic *mailbox_specific_topic; - - message = mwi_state_create_message(mailbox, context, new_msgs, old_msgs, channel_id, eid); - if (!message) { - return -1; - } - - mwi_state = stasis_message_data(message); - mailbox_specific_topic = ast_mwi_topic(mwi_state->uniqueid); - if (!mailbox_specific_topic) { - return -1; - } - - stasis_publish(mailbox_specific_topic, message); - - return 0; -} - -int ast_delete_mwi_state_full(const char *mailbox, const char *context, struct ast_eid *eid) -{ - RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); - struct stasis_message *cached_msg; - struct stasis_message *clear_msg; - struct ast_mwi_state *mwi_state; - struct stasis_topic *mailbox_specific_topic; - - msg = mwi_state_create_message(mailbox, context, 0, 0, NULL, eid); - if (!msg) { - return -1; - } - - mwi_state = stasis_message_data(msg); - - /* - * XXX As far as stasis is concerned, all MWI events are local. - * - * For now, it is assumed that there is only one entity - * maintaining the state of a particular mailbox. - * - * If we ever have multiple MWI event entities maintaining - * the same mailbox that wish to delete their cached entry - * we will need to do something about the race condition - * potential between checking the cache and removing the - * cache entry. - */ - cached_msg = stasis_cache_get_by_eid(ast_mwi_state_cache(), - ast_mwi_state_type(), mwi_state->uniqueid, &ast_eid_default); - if (!cached_msg) { - /* Nothing to clear */ - return -1; - } - ao2_cleanup(cached_msg); - - mailbox_specific_topic = ast_mwi_topic(mwi_state->uniqueid); - if (!mailbox_specific_topic) { - return -1; - } - - clear_msg = stasis_cache_clear_create(msg); - if (clear_msg) { - stasis_publish(mailbox_specific_topic, clear_msg); - } - - ao2_cleanup(clear_msg); - return 0; -} - -static const char *mwi_state_get_id(struct stasis_message *message) -{ - if (ast_mwi_state_type() == stasis_message_type(message)) { - struct ast_mwi_state *mwi_state = stasis_message_data(message); - return mwi_state->uniqueid; - } else if (stasis_subscription_change_type() == stasis_message_type(message)) { - struct stasis_subscription_change *change = stasis_message_data(message); - return change->uniqueid; - } - - return NULL; -} - -static void mwi_blob_dtor(void *obj) -{ - struct ast_mwi_blob *mwi_blob = obj; - - ao2_cleanup(mwi_blob->mwi_state); - ast_json_unref(mwi_blob->blob); -} - -struct stasis_message *ast_mwi_blob_create(struct ast_mwi_state *mwi_state, - struct stasis_message_type *message_type, - struct ast_json *blob) -{ - struct ast_mwi_blob *obj; - struct stasis_message *msg; - - ast_assert(blob != NULL); - - if (!message_type) { - return NULL; - } - - obj = ao2_alloc(sizeof(*obj), mwi_blob_dtor); - if (!obj) { - return NULL; - } - - obj->mwi_state = mwi_state; - ao2_ref(obj->mwi_state, +1); - obj->blob = ast_json_ref(blob); - - /* This is not a normal MWI event. Only used by the MinivmNotify app. */ - msg = stasis_message_create(message_type, obj); - ao2_ref(obj, -1); - - return msg; -} - struct stasis_topic *ast_queue_topic_all(void) { return queue_topic_all; @@ -3407,43 +3117,12 @@ static void app_cleanup(void) queue_topic_pool = NULL; ao2_cleanup(queue_topic_all); queue_topic_all = NULL; - ao2_cleanup(mwi_topic_pool); - mwi_topic_pool = NULL; - ao2_cleanup(mwi_topic_all); - mwi_topic_all = NULL; - ao2_cleanup(mwi_state_cache); - mwi_state_cache = NULL; - mwi_topic_cached = stasis_caching_unsubscribe_and_join(mwi_topic_cached); - STASIS_MESSAGE_TYPE_CLEANUP(ast_mwi_state_type); - STASIS_MESSAGE_TYPE_CLEANUP(ast_mwi_vm_app_type); } int app_init(void) { ast_register_cleanup(app_cleanup); - if (STASIS_MESSAGE_TYPE_INIT(ast_mwi_state_type) != 0) { - return -1; - } - if (STASIS_MESSAGE_TYPE_INIT(ast_mwi_vm_app_type) != 0) { - return -1; - } - mwi_topic_all = stasis_topic_create("mwi:all"); - if (!mwi_topic_all) { - return -1; - } - mwi_state_cache = stasis_cache_create(mwi_state_get_id); - if (!mwi_state_cache) { - return -1; - } - mwi_topic_cached = stasis_caching_topic_create(mwi_topic_all, mwi_state_cache); - if (!mwi_topic_cached) { - return -1; - } - mwi_topic_pool = stasis_topic_pool_create(mwi_topic_all); - if (!mwi_topic_pool) { - return -1; - } queue_topic_all = stasis_topic_create("queue:all"); if (!queue_topic_all) { return -1; diff --git a/main/asterisk.c b/main/asterisk.c index 6d9a5f56ca3d4063e8007d66d60295224992e0df..737f0d06e55d6c67cac2ad3194c6cfb695646488 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -210,6 +210,7 @@ int daemon(int, int); /* defined in libresolv of all places */ #include "asterisk/cdr.h" #include "asterisk/pbx.h" #include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/lock.h" #include "asterisk/utils.h" #include "asterisk/file.h" @@ -4122,6 +4123,7 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou read_pjproject_startup_options(); check_init(ast_pj_init(), "Embedded PJProject"); check_init(app_init(), "App Core"); + check_init(mwi_init(), "MWI Core"); check_init(devstate_init(), "Device State Core"); check_init(ast_msg_init(), "Messaging API"); check_init(ast_channels_init(), "Channel"); diff --git a/main/manager.c b/main/manager.c index cd2e79a44886714a7b10487e7d66a1a6ed1b8c97..b5388c24b08f31905134cc789536d6622ce82aa3 100644 --- a/main/manager.c +++ b/main/manager.c @@ -71,6 +71,7 @@ #include "asterisk/lock.h" #include "asterisk/cli.h" #include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/pbx.h" #include "asterisk/md5.h" #include "asterisk/acl.h" diff --git a/main/manager_mwi.c b/main/manager_mwi.c index a7f94de2477752fa5924d1cabe9a34915a0620c1..7542b5b1a4faf96eb8b20239986baf14c62b7342 100644 --- a/main/manager_mwi.c +++ b/main/manager_mwi.c @@ -27,6 +27,7 @@ #include "asterisk/manager.h" #include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/channel.h" #include "asterisk/stasis_message_router.h" #include "asterisk/stasis.h" diff --git a/main/mwi.c b/main/mwi.c new file mode 100644 index 0000000000000000000000000000000000000000..43b4e044ced5ae640538a1af7f92b4bd3a78384e --- /dev/null +++ b/main/mwi.c @@ -0,0 +1,362 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2019, Sangoma Technologies Corporation + * + * Kevin Harwell <kharwell@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*** MODULEINFO + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +#include "asterisk/mwi.h" +#include "asterisk/stasis_channels.h" + +/* + * @{ \brief Define \ref stasis topic objects + */ +static struct stasis_topic *mwi_topic_all; +static struct stasis_cache *mwi_state_cache; +static struct stasis_caching_topic *mwi_topic_cached; +static struct stasis_topic_pool *mwi_topic_pool; +/* @} */ + +/*! \brief Convert a MWI \ref stasis_message to a \ref ast_event */ +static struct ast_event *mwi_to_event(struct stasis_message *message) +{ + struct ast_event *event; + struct ast_mwi_state *mwi_state; + char *mailbox; + char *context; + + if (!message) { + return NULL; + } + + mwi_state = stasis_message_data(message); + + /* Strip off @context */ + context = mailbox = ast_strdupa(mwi_state->uniqueid); + strsep(&context, "@"); + if (ast_strlen_zero(context)) { + context = "default"; + } + + event = ast_event_new(AST_EVENT_MWI, + AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox, + AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context, + AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, mwi_state->new_msgs, + AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, mwi_state->old_msgs, + AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, &mwi_state->eid, sizeof(mwi_state->eid), + AST_EVENT_IE_END); + + return event; +} + +/* + * @{ \brief Define \ref stasis message types for MWI + */ +STASIS_MESSAGE_TYPE_DEFN(ast_mwi_state_type, + .to_event = mwi_to_event, ); +STASIS_MESSAGE_TYPE_DEFN(ast_mwi_vm_app_type); +/* @} */ + +static void mwi_state_dtor(void *obj) +{ + struct ast_mwi_state *mwi_state = obj; + ast_string_field_free_memory(mwi_state); + ao2_cleanup(mwi_state->snapshot); + mwi_state->snapshot = NULL; +} + +struct stasis_topic *ast_mwi_topic_all(void) +{ + return mwi_topic_all; +} + +struct stasis_cache *ast_mwi_state_cache(void) +{ + return mwi_state_cache; +} + +struct stasis_topic *ast_mwi_topic_cached(void) +{ + return stasis_caching_get_topic(mwi_topic_cached); +} + +struct stasis_topic *ast_mwi_topic(const char *uniqueid) +{ + return stasis_topic_pool_get_topic(mwi_topic_pool, uniqueid); +} + +struct ast_mwi_state *ast_mwi_create(const char *mailbox, const char *context) +{ + struct ast_mwi_state *mwi_state; + + ast_assert(!ast_strlen_zero(mailbox)); + + mwi_state = ao2_alloc(sizeof(*mwi_state), mwi_state_dtor); + if (!mwi_state) { + return NULL; + } + + if (ast_string_field_init(mwi_state, 256)) { + ao2_ref(mwi_state, -1); + return NULL; + } + if (!ast_strlen_zero(context)) { + ast_string_field_build(mwi_state, uniqueid, "%s@%s", mailbox, context); + } else { + ast_string_field_set(mwi_state, uniqueid, mailbox); + } + + return mwi_state; +} + +/*! + * \internal + * \brief Create a MWI state snapshot message. + * \since 12.2.0 + * + * \param[in] mailbox The mailbox identifier string. + * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) + * \param[in] new_msgs The number of new messages in this mailbox + * \param[in] old_msgs The number of old messages in this mailbox + * \param[in] channel_id A unique identifier for a channel associated with this + * change in mailbox state + * \param[in] eid The EID of the server that originally published the message + * + * \retval message on success. Use ao2_cleanup() when done with it. + * \retval NULL on error. + */ +static struct stasis_message *mwi_state_create_message( + const char *mailbox, + const char *context, + int new_msgs, + int old_msgs, + const char *channel_id, + struct ast_eid *eid) +{ + struct ast_mwi_state *mwi_state; + struct stasis_message *message; + + if (!ast_mwi_state_type()) { + return NULL; + } + + mwi_state = ast_mwi_create(mailbox, context); + if (!mwi_state) { + return NULL; + } + + mwi_state->new_msgs = new_msgs; + mwi_state->old_msgs = old_msgs; + + if (!ast_strlen_zero(channel_id)) { + mwi_state->snapshot = ast_channel_snapshot_get_latest(channel_id); + } + + if (eid) { + mwi_state->eid = *eid; + } else { + mwi_state->eid = ast_eid_default; + } + + /* + * XXX As far as stasis is concerned, all MWI events are local. + * + * We may in the future want to make MWI aggregate local/remote + * message counts similar to how device state aggregates state. + */ + message = stasis_message_create_full(ast_mwi_state_type(), mwi_state, &ast_eid_default); + ao2_cleanup(mwi_state); + return message; +} + +int ast_publish_mwi_state_full( + const char *mailbox, + const char *context, + int new_msgs, + int old_msgs, + const char *channel_id, + struct ast_eid *eid) +{ + struct ast_mwi_state *mwi_state; + RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup); + struct stasis_topic *mailbox_specific_topic; + + message = mwi_state_create_message(mailbox, context, new_msgs, old_msgs, channel_id, eid); + if (!message) { + return -1; + } + + mwi_state = stasis_message_data(message); + mailbox_specific_topic = ast_mwi_topic(mwi_state->uniqueid); + if (!mailbox_specific_topic) { + return -1; + } + + stasis_publish(mailbox_specific_topic, message); + + return 0; +} + +int ast_delete_mwi_state_full(const char *mailbox, const char *context, struct ast_eid *eid) +{ + RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); + struct stasis_message *cached_msg; + struct stasis_message *clear_msg; + struct ast_mwi_state *mwi_state; + struct stasis_topic *mailbox_specific_topic; + + msg = mwi_state_create_message(mailbox, context, 0, 0, NULL, eid); + if (!msg) { + return -1; + } + + mwi_state = stasis_message_data(msg); + + /* + * XXX As far as stasis is concerned, all MWI events are local. + * + * For now, it is assumed that there is only one entity + * maintaining the state of a particular mailbox. + * + * If we ever have multiple MWI event entities maintaining + * the same mailbox that wish to delete their cached entry + * we will need to do something about the race condition + * potential between checking the cache and removing the + * cache entry. + */ + cached_msg = stasis_cache_get_by_eid(ast_mwi_state_cache(), + ast_mwi_state_type(), mwi_state->uniqueid, &ast_eid_default); + if (!cached_msg) { + /* Nothing to clear */ + return -1; + } + ao2_cleanup(cached_msg); + + mailbox_specific_topic = ast_mwi_topic(mwi_state->uniqueid); + if (!mailbox_specific_topic) { + return -1; + } + + clear_msg = stasis_cache_clear_create(msg); + if (clear_msg) { + stasis_publish(mailbox_specific_topic, clear_msg); + } + + ao2_cleanup(clear_msg); + return 0; +} + +static const char *mwi_state_get_id(struct stasis_message *message) +{ + if (ast_mwi_state_type() == stasis_message_type(message)) { + struct ast_mwi_state *mwi_state = stasis_message_data(message); + return mwi_state->uniqueid; + } else if (stasis_subscription_change_type() == stasis_message_type(message)) { + struct stasis_subscription_change *change = stasis_message_data(message); + return change->uniqueid; + } + + return NULL; +} + +static void mwi_blob_dtor(void *obj) +{ + struct ast_mwi_blob *mwi_blob = obj; + + ao2_cleanup(mwi_blob->mwi_state); + ast_json_unref(mwi_blob->blob); +} + +struct stasis_message *ast_mwi_blob_create(struct ast_mwi_state *mwi_state, + struct stasis_message_type *message_type, + struct ast_json *blob) +{ + struct ast_mwi_blob *obj; + struct stasis_message *msg; + + ast_assert(blob != NULL); + + if (!message_type) { + return NULL; + } + + obj = ao2_alloc(sizeof(*obj), mwi_blob_dtor); + if (!obj) { + return NULL; + } + + obj->mwi_state = mwi_state; + ao2_ref(obj->mwi_state, +1); + obj->blob = ast_json_ref(blob); + + /* This is not a normal MWI event. Only used by the MinivmNotify app. */ + msg = stasis_message_create(message_type, obj); + ao2_ref(obj, -1); + + return msg; +} + +static void mwi_cleanup(void) +{ + ao2_cleanup(mwi_topic_pool); + mwi_topic_pool = NULL; + ao2_cleanup(mwi_topic_all); + mwi_topic_all = NULL; + ao2_cleanup(mwi_state_cache); + mwi_state_cache = NULL; + mwi_topic_cached = stasis_caching_unsubscribe_and_join(mwi_topic_cached); + STASIS_MESSAGE_TYPE_CLEANUP(ast_mwi_state_type); + STASIS_MESSAGE_TYPE_CLEANUP(ast_mwi_vm_app_type); +} + +int mwi_init(void) +{ + ast_register_cleanup(mwi_cleanup); + + if (STASIS_MESSAGE_TYPE_INIT(ast_mwi_state_type) != 0) { + return -1; + } + + if (STASIS_MESSAGE_TYPE_INIT(ast_mwi_vm_app_type) != 0) { + return -1; + } + + mwi_topic_all = stasis_topic_create("mwi:all"); + if (!mwi_topic_all) { + return -1; + } + + mwi_state_cache = stasis_cache_create(mwi_state_get_id); + if (!mwi_state_cache) { + return -1; + } + + mwi_topic_cached = stasis_caching_topic_create(mwi_topic_all, mwi_state_cache); + if (!mwi_topic_cached) { + return -1; + } + + mwi_topic_pool = stasis_topic_pool_create(mwi_topic_all); + if (!mwi_topic_pool) { + return -1; + } + + return 0; +} diff --git a/res/res_corosync.c b/res/res_corosync.c index 6e66c4fef03697d60edee36eecf3da4d51714196..03f2c5e5121aa17be2801c302a9c25939be29b14 100644 --- a/res/res_corosync.c +++ b/res/res_corosync.c @@ -42,7 +42,7 @@ #include "asterisk/event.h" #include "asterisk/cli.h" #include "asterisk/devicestate.h" -#include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/stasis.h" #include "asterisk/stasis_message_router.h" #include "asterisk/stasis_system.h" diff --git a/res/res_mwi_devstate.c b/res/res_mwi_devstate.c index 209fc8b452856c295369b1491f0d9e2f3c184571..2c516fff8c91705d707e765531776bb585f10f37 100644 --- a/res/res_mwi_devstate.c +++ b/res/res_mwi_devstate.c @@ -22,7 +22,7 @@ #include "asterisk.h" -#include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/devicestate.h" #include "asterisk/module.h" #include "asterisk/stasis_message_router.h" diff --git a/res/res_mwi_external.c b/res/res_mwi_external.c index 82c74b990f9eb96e502ea4201454110797161a47..9d56558596c73aa4b839fec7dcdb83e5f1976031 100644 --- a/res/res_mwi_external.c +++ b/res/res_mwi_external.c @@ -55,6 +55,7 @@ #include "asterisk.h" #include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/module.h" #include "asterisk/res_mwi_external.h" #include "asterisk/sorcery.h" diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index 72f8b59492c8c8f6e15835837961c70fcd84167b..abd7ac0a50f6bf88eeafd0e2596daf1ea8a52041 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -38,7 +38,7 @@ #include "asterisk/taskprocessor.h" #include "asterisk/sorcery.h" #include "asterisk/stasis.h" -#include "asterisk/app.h" +#include "asterisk/mwi.h" struct mwi_subscription; static struct ao2_container *unsolicited_mwi; diff --git a/res/res_pjsip_publish_asterisk.c b/res/res_pjsip_publish_asterisk.c index 692f9a747906413a27c16a644dbd12292ff9ed12..5fea3bf7a8688ac35e5a63d837e8317ff032cee1 100644 --- a/res/res_pjsip_publish_asterisk.c +++ b/res/res_pjsip_publish_asterisk.c @@ -36,7 +36,7 @@ #include "asterisk/res_pjsip_pubsub.h" #include "asterisk/module.h" #include "asterisk/logger.h" -#include "asterisk/app.h" +#include "asterisk/mwi.h" /*** DOCUMENTATION <configInfo name="res_pjsip_publish_asterisk" language="en_US"> diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 394b1acc548f47b1b6cd3b33bc3ec41e728b7334..8f400b5b681055198d448b865d22fca4a542a664 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -31,7 +31,7 @@ #include <pjsip_simple.h> #include <pjlib.h> -#include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/res_pjsip_pubsub.h" #include "asterisk/module.h" #include "asterisk/linkedlists.h" diff --git a/res/res_smdi.c b/res/res_smdi.c index c6f3f3af5fbc5ac8f9512db8bcf87befe3618af3..e34f4f363b83f6f2520c0f3333fbb77b47a6ad66 100644 --- a/res/res_smdi.c +++ b/res/res_smdi.c @@ -61,6 +61,7 @@ #include "asterisk/stringfields.h" #include "asterisk/linkedlists.h" #include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/pbx.h" #include "asterisk/channel.h" diff --git a/res/res_xmpp.c b/res/res_xmpp.c index 218262cbb6b11a3cdcf1e70e6cae644266db7b03..0f304375fe1bb8f41a42f3de57bd7acc47e738d8 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -55,6 +55,7 @@ #include "asterisk/module.h" #include "asterisk/manager.h" #include "asterisk/app.h" +#include "asterisk/mwi.h" #include "asterisk/message.h" #include "asterisk/manager.h" #include "asterisk/cli.h"