29#include <pjsip_simple.h>
51#define STASIS_BUCKETS 13
54#define MWI_TYPE "application"
55#define MWI_SUBTYPE "simple-message-summary"
57#define MWI_DATASTORE "MWI datastore"
60#define MWI_SERIALIZER_POOL_SIZE 8
63#define MAX_UNLOAD_TIMEOUT_TIME 10
71 const char *resource);
149 if (!mwi_stasis_sub) {
169 return mwi_stasis_sub;
183 key =
object->mailbox;
196 const char *right_key = arg;
201 right_key = sub_right->
mailbox;
204 cmp = strcmp(sub_left->
mailbox, right_key);
207 cmp = strncmp(sub_left->
mailbox, right_key, strlen(right_key));
223 ast_debug(3,
"Destroying MWI subscription for endpoint %s\n",
sub->id);
224 if (
sub->is_solicited) {
245 strcpy(
sub->id, endpoint_id);
260 if (!
sub->stasis_subs) {
303 const char *right_key = arg;
308 right_key = sub_right->
id;
311 cmp = strcmp(sub_left->
id, right_key);
314 cmp = strncmp(sub_left->
id, right_key, strlen(right_key));
348 pjsip_sip_uri *account_uri;
349 const char *vm_exten;
354 vm_exten = voicemail_extension;
358 account_uri = pjsip_uri_clone(pool, local_uri);
359 pj_strdup2(pool, &account_uri->user, vm_exten);
378 const char *state_name;
379 pjsip_tx_data *tdata;
380 pjsip_sub_state_hdr *sub_state;
381 pjsip_event_hdr *
event;
382 pjsip_from_hdr *from;
383 pjsip_sip_uri *from_uri;
384 const pjsip_hdr *allow_events = pjsip_evsub_get_allow_events_hdr(
NULL);
389 .body_data = mwi_data->
counter,
401 pjsip_tx_data_dec_ref(tdata);
405 from = PJSIP_MSG_FROM_HDR(tdata->msg);
406 from_uri = pjsip_uri_get_uri(from->uri);
417 pjsip_tx_data_dec_ref(tdata);
424 case PJSIP_EVSUB_STATE_ACTIVE:
425 state_name =
"active";
427 case PJSIP_EVSUB_STATE_TERMINATED:
429 state_name =
"terminated";
433 sub_state = pjsip_sub_state_hdr_create(tdata->pool);
434 pj_cstr(&sub_state->sub_state, state_name);
435 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) sub_state);
437 event = pjsip_event_hdr_create(tdata->pool);
438 pj_cstr(&
event->event_type,
"message-summary");
439 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)
event);
441 pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, allow_events));
480 ast_debug(1,
"Found an aor (%s) that matches voicemail_extension %s\n", aor_name, resource);
499 ast_log(
LOG_WARNING,
"Unable to send unsolicited MWI to %s because endpoint does not exist\n",
504 ast_log(
LOG_WARNING,
"Unable to send unsolicited MWI to %s because the endpoint has no"
505 " configured AORs\n",
sub->id);
511 ast_debug(5,
"Sending unsolicited MWI NOTIFY to endpoint %s, new messages: %d, old messages: %d\n",
530 ast_debug(1,
"No contacts bound to AOR %s. Cannot send unsolicited MWI until a contact registers.\n", aor_name);
543 .message_account[0] =
'\0',
547 .body_data = &counter,
552 if (
sub->is_solicited) {
559 if (aor && dlg && sip_uri) {
578 ast_debug(3,
"Removing stasis subscription to mailbox %s\n", mwi_stasis->
mailbox);
596 if (!mwi_datastore) {
618 if (unsolicited_mwi && endpoint) {
646 if (!mwi_datastore) {
711 return *mwi_stasis ? 1 : 0;
752 ast_debug(1,
"Unsolicited subscription being replaced by solicited for "
769static int send_notify(
void *obj,
void *arg,
int flags);
858 if (unsolicited_mwi) {
869 ast_debug(1,
"Endpoint '%s' already configured for unsolicited MWI for mailbox '%s'. "
873 if (unsolicited_mwi) {
881 if (unsolicited_mwi) {
909 if (!mwi_stasis_sub) {
975 const char *resource)
988 ast_debug(1,
"Unable to locate aor %s. MWI subscription failed.\n", resource);
993 ast_debug(1,
"AOR %s has no configured mailboxes. MWI subscription failed.\n",
1032 if (solicited_mwi) {
1051 if (!mwi_datastore) {
1066 if (dlg && sip_uri) {
1104 if (!mwi_datastore) {
1211 if (aggregate_sub && !recreate) {
1215 if (!aggregate_sub) {
1217 if (!aggregate_sub) {
1231 if (solicited_mwi) {
1250 if (mwi_stasis_sub) {
1254 if (!aggregate_sub) {
1262 if (aggregate_sub && !sub_added) {
1268 if (aggregate_sub) {
1274 if (send_now && sub_added) {
1280 if (solicited_mwi) {
1309 if (!unsolicited_mwi) {
1346 const char *aor = arg;
1383 if (!unsolicited_mwi) {
1439 if (found_contact) {
1445 if (!unsolicited_mwi) {
1474 if (unsolicited_mwi) {
1495 if (strcmp(
type,
"FullyBooted")) {
1545 if (unsolicited_mwi) {
1579 ast_log(
AST_LOG_WARNING,
"Failed to create MWI serializer pool. The default SIP pool will be used for MWI\n");
1584 if (!mwi_container) {
1593 if (!mwi_container) {
1636 .
requires =
"res_pjsip,res_pjsip_pubsub",
Asterisk main include file. File version handling, generic pbx functions.
int ast_shutdown_final(void)
#define ast_strdup(str)
A wrapper for strdup()
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ao2_iterator_next(iter)
#define ao2_link(container, obj)
Add an object to a container.
@ AO2_ALLOC_OPT_LOCK_MUTEX
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_callback_data(container, flags, cb_fn, arg, data)
#define ao2_unlink(container, obj)
Remove an object from a container.
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
#define ao2_find(container, arg, flags)
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define ao2_global_obj_replace(holder, obj)
Replace an ao2 object in the global holder.
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
@ OBJ_SEARCH_MASK
Search option field mask.
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
#define ao2_alloc(data_size, destructor_fn)
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
struct stasis_message_type * stasis_subscription_change_type(void)
Gets the message type for subscription change notices.
struct ast_flags ast_options
@ AST_OPT_FLAG_FULLY_BOOTED
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
char * strsep(char **str, const char *delims)
#define ast_variable_new(name, value, filename)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Support for logging to various files, console and syslog Configuration in file logger....
#define ast_debug(level,...)
Log a DEBUG message.
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
static struct ao2_container * endpoints
struct stasis_message_type * ast_manager_get_generic_type(void)
Get the stasis_message_type for generic messages.
Asterisk module definitions.
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODPRI_CHANNEL_DEPEND
@ AST_MODULE_SUPPORT_CORE
#define ASTERISK_GPL_KEY
The text the key() function should return.
@ AST_MODULE_LOAD_SUCCESS
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
struct stasis_message_type * ast_mwi_state_type(void)
Get the Stasis Message Bus API message type for MWI messages.
struct stasis_subscription * ast_mwi_subscriber_subscription(struct ast_mwi_subscriber *sub)
Retrieve the stasis MWI topic subscription if available.
void * ast_mwi_unsubscribe_and_join(struct ast_mwi_subscriber *sub)
Unsubscribe from the stasis topic, block until the final message is received, and then unsubscribe fr...
struct ast_mwi_subscriber * ast_mwi_subscribe_pool(const char *mailbox, stasis_subscription_cb callback, void *data)
Add an MWI state subscriber, and stasis subscription to the mailbox.
struct ast_mwi_state * ast_mwi_subscriber_data(struct ast_mwi_subscriber *sub)
Retrieves the state data object associated with the MWI subscriber.
static struct stasis_rest_handlers mailboxes
REST handler for /api-docs/mailboxes.json.
struct stasis_forward * sub
struct ao2_container * container
static struct stasis_subscription * mwi_sub
struct ast_sip_contact * ast_sip_location_retrieve_contact_from_aor_list(const char *aor_list)
Retrieve the first bound contact from a list of AORs.
struct ast_sip_aor * ast_sip_location_retrieve_aor(const char *aor_name)
Retrieve a named AOR.
int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg)
For every aor in the comma separated aors string call the given 'on_aor' handler.
char * ast_sip_get_default_voicemail_extension(void)
Retrieve the default voicemail extension.
int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint, void *token, void(*callback)(void *token, pjsip_event *e))
General purpose method for sending a SIP request.
int ast_sip_add_body(pjsip_tx_data *tdata, const struct ast_sip_body *body)
Add a body to an outbound SIP message.
unsigned int ast_sip_get_mwi_disable_initial_unsolicited(void)
Retrieve the global setting 'disable sending unsolicited mwi on startup'.
struct ast_threadpool * ast_sip_threadpool(void)
Retrieve the SIP threadpool object.
int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint, const char *uri, struct ast_sip_contact *contact, pjsip_tx_data **tdata)
General purpose method for creating a SIP request.
int ast_sip_get_mwi_tps_queue_low(void)
Retrieve the global MWI taskprocessor low water clear alert level.
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
unsigned int ast_sip_get_mwi_tps_queue_high(void)
Retrieve the global MWI taskprocessor high water alert trigger level.
struct ao2_container * ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor)
Retrieve all contacts currently available for an AOR.
static void mwi_contact_deleted(const void *object)
Function called when a contact is deleted.
static int mwi_new_subscribe(struct ast_sip_endpoint *endpoint, const char *resource)
static void send_unsolicited_mwi_notify(struct mwi_subscription *sub, struct ast_sip_message_accumulator *counter)
static void mwi_subscription_destructor(void *obj)
static struct ast_sorcery_observer global_observer
static struct mwi_subscription * mwi_create_subscription(struct ast_sip_endpoint *endpoint, struct ast_sip_subscription *sip_sub)
static int send_notify(void *obj, void *arg, int flags)
static void mwi_to_ami(struct ast_sip_subscription *sub, struct ast_str **buf)
static void global_loaded(const char *object_type)
static int stasis_sub_hash(const void *obj, const int flags)
static void mwi_contact_added(const void *object)
Function called when a contact is added.
static int unsubscribe(void *obj, void *arg, int flags)
static void send_mwi_notify(struct mwi_subscription *sub)
static void set_voicemail_extension(pj_pool_t *pool, pjsip_sip_uri *local_uri, struct ast_sip_message_accumulator *counter, const char *voicemail_extension)
static int mwi_on_aor(void *obj, void *arg, int flags)
static int allow_and_or_replace_unsolicited(struct ast_sip_endpoint *endpoint, const char *mailbox, struct ao2_container *unsolicited_mwi)
#define MAX_UNLOAD_TIMEOUT_TIME
static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flags)
static int get_message_count(void *obj, void *arg, int flags)
static int has_mwi_subscription(struct ao2_container *container, struct ast_sip_endpoint *endpoint, const char *mailbox, struct mwi_subscription **mwi_sub, struct mwi_stasis_subscription **mwi_stasis)
static int add_mwi_datastore(struct mwi_subscription *sub)
static void mwi_contact_updated(const void *object)
Function called when a contact is updated.
static void mwi_subscription_shutdown(struct ast_sip_subscription *sub)
static int create_unsolicited_mwi_subscriptions(struct ast_sip_endpoint *endpoint, int recreate, int send_now, struct ao2_container *unsolicited_mwi, struct ao2_container *solicited_mwi)
static struct mwi_subscription * mwi_subscription_alloc(struct ast_sip_endpoint *endpoint, unsigned int is_solicited, struct ast_sip_subscription *sip_sub)
static struct ast_datastore_info mwi_ds_info
static struct mwi_stasis_subscription * mwi_stasis_subscription_alloc(const char *mailbox, struct mwi_subscription *mwi_sub)
static int mwi_subscription_established(struct ast_sip_subscription *sub)
static struct ast_serializer_pool * mwi_serializer_pool
static void mwi_ds_destroy(void *data)
static char * default_voicemail_extension
static int is_unsolicited_allowed(struct ast_sip_endpoint *endpoint, const char *mailbox, struct ao2_container *unsolicited_mwi, struct ao2_container *solicited_mwi)
static const struct ast_sorcery_observer mwi_contact_observer
Observer for contacts so unsolicited MWI is sent when a contact changes.
static void create_mwi_subscriptions(void)
static struct mwi_subscription * mwi_subscribe_all(struct ast_sip_endpoint *endpoint, struct ast_sip_subscription *sip_sub)
static void * mwi_get_notify_data(struct ast_sip_subscription *sub)
static struct mwi_subscription * mwi_subscribe_single(struct ast_sip_endpoint *endpoint, struct ast_sip_subscription *sip_sub, const char *name)
static struct ast_sip_notifier mwi_notifier
static void mwi_startup_event_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Event callback which fires initial unsolicited MWI NOTIFY messages when we're fully booted.
static int mwi_validate_for_aor(void *obj, void *arg, int flags)
Determine if an endpoint is a candidate to be able to subscribe for MWI.
static int send_contact_notify(void *obj, void *arg, int flags)
Function called to send MWI NOTIFY on any unsolicited mailboxes relating to this AOR.
static void mwi_contact_changed(const struct ast_sip_contact *contact)
Create mwi subscriptions and notify.
static int serialized_notify(void *userdata)
static int mwi_sub_cmp(void *obj, void *arg, int flags)
static struct ast_sip_aor * find_aor_for_resource(struct ast_sip_endpoint *endpoint, const char *resource)
static int serialized_cleanup(void *userdata)
static int unsubscribe_stasis(void *obj, void *arg, int flags)
static void mwi_stasis_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
static int load_module(void)
static void mwi_subscription_mailboxes_str(struct ao2_container *stasis_subs, struct ast_str **str)
static int stasis_sub_cmp(void *obj, void *arg, int flags)
static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, void *data, int flags)
static int unload_module(void)
AO2_GLOBAL_OBJ_STATIC(mwi_unsolicited)
static int mwi_sub_hash(const void *obj, const int flags)
static int send_initial_notify_all(void *obj)
Task invoked to send initial MWI NOTIFY for unsolicited.
#define MWI_SERIALIZER_POOL_SIZE
static struct ast_sip_subscription_handler mwi_handler
struct ast_sip_endpoint * ast_sip_subscription_get_endpoint(struct ast_sip_subscription *sub)
Get the endpoint that is associated with this subscription.
void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler *handler)
Unregister a subscription handler.
int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *handler)
Register a subscription handler.
void ast_sip_subscription_destroy(struct ast_sip_subscription *sub)
Alert the pubsub core that the subscription is ready for destruction.
void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name)
Remove a subscription datastore from the subscription.
int ast_sip_pubsub_generate_body_content(const char *content_type, const char *content_subtype, struct ast_sip_body_data *data, struct ast_str **str)
Generate body content for a PUBLISH or NOTIFY.
struct ast_datastore * ast_sip_subscription_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Alternative for ast_datastore_alloc()
struct ast_taskprocessor * ast_sip_subscription_get_serializer(struct ast_sip_subscription *sub)
Get the serializer for the subscription.
int ast_sip_subscription_notify(struct ast_sip_subscription *sub, struct ast_sip_body_data *notify_data, int terminate)
Notify a SIP subscription of a state change.
int ast_sip_subscription_add_datastore(struct ast_sip_subscription *subscription, struct ast_datastore *datastore)
Add a datastore to a SIP subscription.
const char * ast_sip_subscription_get_resource_name(struct ast_sip_subscription *sub)
Get the name of the subscribed resource.
pjsip_sip_uri * ast_sip_subscription_get_sip_uri(struct ast_sip_subscription *sub)
Retrieve the local sip uri for this subscription.
#define AST_SIP_MESSAGE_ACCUMULATOR
pjsip_dialog * ast_sip_subscription_get_dialog(struct ast_sip_subscription *sub)
Get the pjsip dialog that is associated with this subscription.
struct ast_datastore * ast_sip_subscription_get_datastore(struct ast_sip_subscription *subscription, const char *name)
Retrieve a subscription datastore.
struct ast_taskprocessor * ast_serializer_pool_get(struct ast_serializer_pool *pool)
Retrieve a serializer from the pool.
int ast_serializer_pool_set_alerts(struct ast_serializer_pool *pool, long high, long low)
Set taskprocessor alert levels for the serializers in the pool.
struct ast_serializer_pool * ast_serializer_pool_create(const char *name, unsigned int size, struct ast_threadpool *threadpool, int timeout)
Create a serializer pool.
int ast_serializer_pool_destroy(struct ast_serializer_pool *pool)
Destroy the serializer pool.
Sorcery Data Access Layer API.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Remove an observer from a specific object type.
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Add an observer to a specific object type.
void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to reload persistent objects.
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
#define stasis_subscribe_pool(topic, callback, data)
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Structure for a data store type.
void(* destroy)(void *data)
Structure for a data store object.
The structure that contains MWI state.
char * voicemail_extension
const ast_string_field mailboxes
Data used to create bodies for NOTIFY/PUBLISH requests.
struct ast_sip_mwi_configuration mwi
An entity with which Asterisk communicates.
const ast_string_field aors
struct ast_sip_endpoint_subscription_configuration subscription
Message counter used for message-summary XML bodies.
char message_account[PJSIP_MAX_URL_SIZE]
char * voicemail_extension
const ast_string_field mailboxes
const ast_string_field fromuser
unsigned int subscribe_replaces_unsolicited
const char * default_accept
Default body type defined for the event package this notifier handles.
Structure representing a "virtual" SIP subscription.
Interface for a sorcery object type observer.
void(* loaded)(const char *object_type)
Callback for when an object type is loaded/reloaded.
void(* created)(const void *object)
Callback for when an object is created.
Support for dynamic strings.
A ast_taskprocessor structure is a singleton by name.
Structure for variables, used for configurations and for channel variables.
Wrapper for stasis subscription.
struct ast_mwi_subscriber * mwi_subscriber
struct ast_sip_subscription * sip_sub
unsigned int is_solicited
struct ao2_container * stasis_subs
struct ast_sip_endpoint * endpoint
struct ast_sip_message_accumulator * counter
struct mwi_subscription * sub
An API for managing task processing threads that can be shared across modules.
#define ast_test_flag(p, flag)
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.