29 #include <pjsip_simple.h>
32 #include "asterisk/res_pjsip.h"
33 #include "asterisk/res_pjsip_pubsub.h"
34 #include "asterisk/res_pjsip_body_generator_types.h"
39 #include "asterisk/serializer.h"
49 static char *default_voicemail_extension;
51 #define STASIS_BUCKETS 13
52 #define MWI_BUCKETS 53
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);
77 .new_subscribe = mwi_new_subscribe,
78 .subscription_established = mwi_subscription_established,
79 .get_notify_data = mwi_get_notify_data,
84 .body_type = AST_SIP_MESSAGE_ACCUMULATOR,
85 .accept = { MWI_TYPE
"/"MWI_SUBTYPE, },
86 .subscription_shutdown = mwi_subscription_shutdown,
88 .notifier = &mwi_notifier,
148 mwi_stasis_sub = ao2_alloc(
sizeof(*mwi_stasis_sub) + strlen(mailbox), NULL);
149 if (!mwi_stasis_sub) {
154 strcpy(mwi_stasis_sub->
mailbox, mailbox);
169 return mwi_stasis_sub;
172 static int stasis_sub_hash(
const void *obj,
const int flags)
183 key =
object->mailbox;
192 static int stasis_sub_cmp(
void *obj,
void *arg,
int flags)
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));
219 static void mwi_subscription_destructor(
void *obj)
223 ast_debug(3,
"Destroying MWI subscription for endpoint %s\n", sub->
id);
225 ast_sip_subscription_destroy(sub->
sip_sub);
237 sub = ao2_alloc(
sizeof(*sub) + strlen(endpoint_id),
238 mwi_subscription_destructor);
245 strcpy(sub->
id, endpoint_id);
259 STASIS_BUCKETS, stasis_sub_hash, NULL, stasis_sub_cmp);
266 if (!is_solicited && !ast_strlen_zero(endpoint->
aors)) {
274 ast_debug(3,
"Created %s MWI subscription for endpoint %s\n", is_solicited ?
"solicited" :
"unsolicited", sub->
id);
279 static int mwi_sub_hash(
const void *obj,
const int flags)
284 switch (flags & OBJ_SEARCH_MASK) {
299 static int mwi_sub_cmp(
void *obj,
void *arg,
int flags)
303 const char *right_key = arg;
306 switch (flags & OBJ_SEARCH_MASK) {
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));
326 static int get_message_count(
void *obj,
void *arg,
int flags)
345 static void set_voicemail_extension(pj_pool_t *
pool, pjsip_sip_uri *local_uri,
348 pjsip_sip_uri *account_uri;
349 const char *vm_exten;
351 if (ast_strlen_zero(voicemail_extension)) {
352 vm_exten = default_voicemail_extension;
354 vm_exten = voicemail_extension;
357 if (!ast_strlen_zero(vm_exten)) {
358 account_uri = pjsip_uri_clone(pool, local_uri);
359 pj_strdup2(pool, &account_uri->user, vm_exten);
367 pjsip_evsub_state
state;
371 static int send_unsolicited_mwi_notify_to_contact(
void *obj,
void *arg,
int flags)
376 pjsip_evsub_state
state = mwi_data->state;
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);
388 .body_type = AST_SIP_MESSAGE_ACCUMULATOR,
389 .body_data = mwi_data->counter,
392 if (ast_sip_create_request(
"NOTIFY", NULL, endpoint, NULL, contact, &tdata)) {
393 ast_log(LOG_WARNING,
"Unable to create unsolicited NOTIFY request to endpoint %s URI %s\n", sub->
id, contact->
uri);
397 body.type = MWI_TYPE;
398 body.subtype = MWI_SUBTYPE;
401 pjsip_tx_data_dec_ref(tdata);
405 from = PJSIP_MSG_FROM_HDR(tdata->msg);
406 from_uri = pjsip_uri_get_uri(from->uri);
414 if (ast_sip_pubsub_generate_body_content(body.type, body.subtype, &body_data, &body_text)) {
415 ast_log(LOG_WARNING,
"Unable to generate SIP MWI NOTIFY body.\n");
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));
442 ast_sip_add_body(tdata, &body);
443 ast_sip_send_request(tdata, NULL, endpoint, NULL, NULL);
457 if ((aor = ast_sip_location_retrieve_aor(resource))) {
471 while ((aor_name =
ast_strip(strsep(&aors_copy,
",")))) {
472 struct ast_sip_aor *check_aor = ast_sip_location_retrieve_aor(aor_name);
480 ast_debug(1,
"Found an aor (%s) that matches voicemail_extension %s\n", aor_name, resource);
494 "endpoint", sub->
id), ao2_cleanup);
499 ast_log(LOG_WARNING,
"Unable to send unsolicited MWI to %s because endpoint does not exist\n",
503 if (ast_strlen_zero(endpoint->
aors)) {
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",
514 while ((aor_name =
ast_strip(strsep(&endpoint_aors,
",")))) {
519 .endpoint = endpoint,
524 ast_log(LOG_WARNING,
"Unable to locate AOR %s for unsolicited MWI\n", aor_name);
528 contacts = ast_sip_location_retrieve_aor_contacts(aor);
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',
546 .
body_type = AST_SIP_MESSAGE_ACCUMULATOR,
547 .body_data = &counter,
553 const char *resource = ast_sip_subscription_get_resource_name(sub->
sip_sub);
555 struct ast_sip_aor *aor = find_aor_for_resource(endpoint, resource);
556 pjsip_dialog *dlg = ast_sip_subscription_get_dialog(sub->
sip_sub);
557 pjsip_sip_uri *sip_uri = ast_sip_subscription_get_sip_uri(sub->
sip_sub);
559 if (aor && dlg && sip_uri) {
564 ao2_cleanup(endpoint);
570 send_unsolicited_mwi_notify(sub, &counter);
573 static int unsubscribe_stasis(
void *obj,
void *arg,
int flags)
578 ast_debug(3,
"Removing stasis subscription to mailbox %s\n", mwi_stasis->
mailbox);
584 static int create_unsolicited_mwi_subscriptions(
struct ast_sip_endpoint *endpoint,
595 mwi_datastore = ast_sip_subscription_get_datastore(sub, MWI_DATASTORE);
596 if (!mwi_datastore) {
600 mwi_sub = mwi_datastore->
data;
603 ast_sip_subscription_remove_datastore(sub, MWI_DATASTORE);
618 if (unsolicited_mwi && endpoint) {
619 ao2_lock(unsolicited_mwi);
620 create_unsolicited_mwi_subscriptions(endpoint, 1, 1, unsolicited_mwi, solicited_mwi);
621 ao2_unlock(unsolicited_mwi);
625 ao2_cleanup(solicited_mwi);
626 ao2_cleanup(endpoint);
629 static void mwi_ds_destroy(
void *data)
645 mwi_datastore = ast_sip_subscription_alloc_datastore(&mwi_ds_info, MWI_DATASTORE);
646 if (!mwi_datastore) {
650 mwi_datastore->
data = sub;
656 res = ast_sip_subscription_add_datastore(sub->
sip_sub, mwi_datastore);
701 while ((*mwi_sub = ao2_iterator_next(mwi_subs))) {
702 *mwi_stasis = ao2_find((*mwi_sub)->stasis_subs, mailbox,
OBJ_SEARCH_KEY);
711 return *mwi_stasis ? 1 : 0;
729 static int allow_and_or_replace_unsolicited(
struct ast_sip_endpoint *endpoint,
const char *mailbox,
735 if (!has_mwi_subscription(unsolicited_mwi, endpoint, mailbox, &mwi_sub, &mwi_stasis)) {
752 ast_debug(1,
"Unsolicited subscription being replaced by solicited for "
755 unsubscribe_stasis(mwi_stasis, NULL, 0);
769 static int send_notify(
void *obj,
void *arg,
int flags);
783 static int is_unsolicited_allowed(
struct ast_sip_endpoint *endpoint,
const char *mailbox,
789 if (ast_strlen_zero(mailbox)) {
797 if (has_mwi_subscription(unsolicited_mwi, endpoint, mailbox, &mwi_sub, &mwi_stasis)) {
807 if (!has_mwi_subscription(solicited_mwi, endpoint, mailbox, &mwi_sub, &mwi_stasis)) {
824 send_notify(mwi_sub, NULL, 0);
844 static int mwi_validate_for_aor(
void *obj,
void *arg,
int flags)
858 if (unsolicited_mwi) {
859 ao2_lock(unsolicited_mwi);
863 while ((mailbox =
ast_strip(strsep(&mailboxes,
",")))) {
864 if (ast_strlen_zero(mailbox)) {
868 if (!allow_and_or_replace_unsolicited(endpoint, mailbox, unsolicited_mwi)) {
869 ast_debug(1,
"Endpoint '%s' already configured for unsolicited MWI for mailbox '%s'. "
873 if (unsolicited_mwi) {
874 ao2_unlock(unsolicited_mwi);
881 if (unsolicited_mwi) {
882 ao2_unlock(unsolicited_mwi);
889 static int mwi_on_aor(
void *obj,
void *arg,
int flags)
901 while ((mailbox =
ast_strip(strsep(&mailboxes,
",")))) {
904 if (ast_strlen_zero(mailbox)) {
908 mwi_stasis_sub = mwi_stasis_subscription_alloc(mailbox, sub);
909 if (!mwi_stasis_sub) {
923 struct mwi_subscription *sub = mwi_subscription_alloc(endpoint, 1, sip_sub);
929 if (add_mwi_datastore(sub)) {
930 ast_log(LOG_WARNING,
"Unable to add datastore for MWI subscription to %s\n",
945 aor = find_aor_for_resource(endpoint, name);
947 ast_log(LOG_WARNING,
"Unable to locate aor %s. MWI subscription failed.\n", name);
951 sub = mwi_create_subscription(endpoint, sip_sub);
953 mwi_on_aor(aor, sub, 0);
965 sub = mwi_create_subscription(endpoint, sip_sub);
970 ast_sip_for_each_aor(endpoint->
aors, mwi_on_aor, sub);
975 const char *resource)
979 if (ast_strlen_zero(resource)) {
980 if (ast_sip_for_each_aor(endpoint->
aors, mwi_validate_for_aor, endpoint)) {
986 aor = find_aor_for_resource(endpoint, 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",
998 if (mwi_validate_for_aor(aor, endpoint, 0)) {
1007 const char *resource = ast_sip_subscription_get_resource_name(sip_sub);
1009 struct ast_sip_endpoint *endpoint = ast_sip_subscription_get_endpoint(sip_sub);
1013 if (ast_strlen_zero(resource)) {
1014 sub = mwi_subscribe_all(endpoint, sip_sub);
1016 sub = mwi_subscribe_single(endpoint, sip_sub, resource);
1019 ao2_cleanup(endpoint);
1028 ast_sip_subscription_remove_datastore(sip_sub, MWI_DATASTORE);
1032 if (solicited_mwi) {
1038 ao2_cleanup(endpoint);
1048 struct ast_sip_endpoint *endpoint = ast_sip_subscription_get_endpoint(sub);
1050 mwi_datastore = ast_sip_subscription_get_datastore(sub, MWI_DATASTORE);
1051 if (!mwi_datastore) {
1054 mwi_sub = mwi_datastore->
data;
1056 counter = ao2_alloc(
sizeof(*counter), NULL);
1058 ao2_cleanup(mwi_datastore);
1062 if ((aor = find_aor_for_resource(endpoint, ast_sip_subscription_get_resource_name(sub)))) {
1063 pjsip_dialog *dlg = ast_sip_subscription_get_dialog(sub);
1064 pjsip_sip_uri *sip_uri = ast_sip_subscription_get_sip_uri(sub);
1066 if (dlg && sip_uri) {
1071 ao2_cleanup(endpoint);
1074 ao2_cleanup(mwi_datastore);
1078 static void mwi_subscription_mailboxes_str(
struct ao2_container *stasis_subs,
1085 while ((node = ao2_iterator_next(&i))) {
1103 mwi_datastore = ast_sip_subscription_get_datastore(sub, MWI_DATASTORE);
1104 if (!mwi_datastore) {
1108 mwi_sub = mwi_datastore->
data;
1112 mwi_subscription_mailboxes_str(mwi_sub->
stasis_subs, buf);
1118 static int serialized_notify(
void *userdata)
1122 send_mwi_notify(mwi_sub);
1127 static int serialized_cleanup(
void *userdata)
1134 ao2_cleanup(mwi_sub);
1138 ao2_cleanup(mwi_sub);
1142 static int send_notify(
void *obj,
void *arg,
int flags)
1146 ? ast_sip_subscription_get_serializer(mwi_sub->
sip_sub)
1147 : ast_serializer_pool_get(mwi_serializer_pool);
1163 serialized_cleanup,
ao2_bump(mwi_sub))) {
1170 send_notify(mwi_sub, NULL, 0);
1188 static int create_unsolicited_mwi_subscriptions(
struct ast_sip_endpoint *endpoint,
1211 if (aggregate_sub && !recreate) {
1215 if (!aggregate_sub) {
1216 aggregate_sub = mwi_subscription_alloc(endpoint, 0, NULL);
1217 if (!aggregate_sub) {
1231 if (solicited_mwi) {
1232 ao2_lock(solicited_mwi);
1236 while ((mailbox =
ast_strip(strsep(&mailboxes,
",")))) {
1240 if (!is_unsolicited_allowed(endpoint, mailbox, unsolicited_mwi, solicited_mwi)) {
1244 sub = aggregate_sub ?: mwi_subscription_alloc(endpoint, 0, NULL);
1249 mwi_stasis_sub = mwi_stasis_subscription_alloc(mailbox, sub);
1250 if (mwi_stasis_sub) {
1254 if (!aggregate_sub) {
1257 send_notify(sub, NULL, 0);
1262 if (aggregate_sub && !sub_added) {
1268 if (aggregate_sub) {
1274 if (send_now && sub_added) {
1275 send_notify(aggregate_sub, NULL, 0);
1280 if (solicited_mwi) {
1281 ao2_unlock(solicited_mwi);
1287 static int create_mwi_subscriptions_for_endpoint(
void *obj,
void *arg,
void *data,
int flags)
1289 return create_unsolicited_mwi_subscriptions(obj, 0, 0, arg, data);
1292 static int unsubscribe(
void *obj,
void *arg,
int flags)
1301 static void create_mwi_subscriptions(
void)
1309 if (!unsolicited_mwi) {
1313 var = ast_variable_new(
"mailboxes !=",
"",
"");
1332 ao2_lock(unsolicited_mwi);
1334 ao2_callback_data(endpoints,
OBJ_NODATA, create_mwi_subscriptions_for_endpoint, unsolicited_mwi, solicited_mwi);
1335 ao2_unlock(unsolicited_mwi);
1338 ao2_cleanup(solicited_mwi);
1343 static int send_contact_notify(
void *obj,
void *arg,
int flags)
1346 const char *aor = arg;
1348 if (!mwi_sub->
aors || !strstr(mwi_sub->
aors, aor)) {
1353 serialized_notify,
ao2_bump(mwi_sub))) {
1361 static void mwi_contact_changed(
const struct ast_sip_contact *contact)
1378 ao2_cleanup(endpoint);
1383 if (!unsolicited_mwi) {
1384 ao2_cleanup(endpoint);
1390 ao2_lock(unsolicited_mwi);
1391 create_unsolicited_mwi_subscriptions(endpoint, 0, 0, unsolicited_mwi, solicited_mwi);
1392 ao2_unlock(unsolicited_mwi);
1393 ao2_cleanup(endpoint);
1394 ao2_cleanup(solicited_mwi);
1397 aor = strsep(&
id,
";@");
1402 static void mwi_contact_updated(
const void *
object)
1404 mwi_contact_changed(
object);
1408 static void mwi_contact_added(
const void *
object)
1410 mwi_contact_changed(
object);
1414 static void mwi_contact_deleted(
const void *
object)
1432 ao2_cleanup(endpoint);
1437 found_contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->
aors);
1438 ao2_cleanup(endpoint);
1439 if (found_contact) {
1440 ao2_cleanup(found_contact);
1445 if (!unsolicited_mwi) {
1449 ao2_lock(unsolicited_mwi);
1450 mwi_subs = ao2_find(unsolicited_mwi, contact->
endpoint_name,
1453 for (; (mwi_sub = ao2_iterator_next(mwi_subs)); ao2_cleanup(mwi_sub)) {
1454 unsubscribe(mwi_sub, NULL, 0);
1458 ao2_unlock(unsolicited_mwi);
1465 .updated = mwi_contact_updated,
1466 .deleted = mwi_contact_deleted,
1470 static int send_initial_notify_all(
void *obj)
1474 if (unsolicited_mwi) {
1495 if (strcmp(type,
"FullyBooted")) {
1500 send_initial_notify_all, NULL);
1505 static void global_loaded(
const char *object_type)
1507 ast_free(default_voicemail_extension);
1508 default_voicemail_extension = ast_sip_get_default_voicemail_extension();
1509 ast_serializer_pool_set_alerts(mwi_serializer_pool,
1510 ast_sip_get_mwi_tps_queue_high(), ast_sip_get_mwi_tps_queue_low());
1517 static int reload(
void)
1519 if (!ast_sip_get_mwi_disable_initial_unsolicited()) {
1520 create_mwi_subscriptions();
1525 static int unload_module(
void)
1545 if (unsolicited_mwi) {
1552 if (ast_serializer_pool_destroy(mwi_serializer_pool)) {
1553 ast_log(LOG_WARNING,
"Unload incomplete. Try again later\n");
1556 mwi_serializer_pool = NULL;
1558 ast_sip_unregister_subscription_handler(&mwi_handler);
1560 ast_free(default_voicemail_extension);
1561 default_voicemail_extension = NULL;
1568 static int load_module(
void)
1572 if (ast_sip_register_subscription_handler(&mwi_handler)) {
1576 mwi_serializer_pool = ast_serializer_pool_create(
"pjsip/mwi",
1577 MWI_SERIALIZER_POOL_SIZE, ast_sip_threadpool(), MAX_UNLOAD_TIMEOUT_TIME);
1578 if (!mwi_serializer_pool) {
1579 ast_log(AST_LOG_WARNING,
"Failed to create MWI serializer pool. The default SIP pool will be used for MWI\n");
1583 mwi_sub_hash, NULL, mwi_sub_cmp);
1584 if (!mwi_container) {
1592 mwi_sub_hash, NULL, mwi_sub_cmp);
1593 if (!mwi_container) {
1604 if (!ast_sip_get_mwi_disable_initial_unsolicited()) {
1605 create_mwi_subscriptions();
1608 send_initial_notify_all, NULL);
1618 if (!mwi_serializer_pool) {
1630 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"PJSIP MWI resource",
1631 .support_level = AST_MODULE_SUPPORT_CORE,
1632 .load = load_module,
1633 .unload = unload_module,
1636 .requires =
"res_pjsip,res_pjsip_pubsub",
struct ast_mwi_subscriber * mwi_subscriber
struct ast_sip_mwi_configuration mwi
const ast_string_field mailboxes
Asterisk main include file. File version handling, generic pbx functions.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
unsigned int is_solicited
The arg parameter is a search key, but is not an object.
Data used to create bodies for NOTIFY/PUBLISH requests.
char * voicemail_extension
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
static struct stasis_rest_handlers mailboxes
REST handler for /api-docs/mailboxes.json.
Structure for variables, used for configurations and for channel variables.
static pj_pool_t * pool
Global memory pool for configuration and timers.
struct stasis_subscription * ast_mwi_subscriber_subscription(struct ast_mwi_subscriber *sub)
Retrieve the stasis MWI topic subscription if available.
void(* created)(const void *object)
Callback for when an object is created.
struct ast_sip_endpoint_subscription_configuration subscription
Assume that the ao2_container is already locked.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Structure for a data store type.
Message counter used for message-summary XML bodies.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
Return all matching objects.
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
#define ast_strdup(str)
A wrapper for strdup()
Structure for a data store object.
struct ast_mwi_state * ast_mwi_subscriber_data(struct ast_mwi_subscriber *sub)
Retrieves the state data object associated with the MWI subscriber.
const ast_string_field mailboxes
struct ao2_container * stasis_subs
char * voicemail_extension
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
struct stasis_message_type * ast_manager_get_generic_type(void)
Get the stasis_message_type for generic messages.
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
unsigned int subscribe_replaces_unsolicited
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
struct ast_sip_subscription * sip_sub
void(* destroy)(void *data)
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
struct ao2_container * container
#define ast_debug(level,...)
Log a DEBUG message.
An entity with which Asterisk communicates.
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.
Structure representing a "virtual" SIP subscription.
int ast_shutdown_final(void)
#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.
Support for dynamic strings.
#define ao2_unlink(container, obj)
Remove an object from a container.
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
Interface for a sorcery object type observer.
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
struct stasis_message_type * ast_mwi_state_type(void)
Get the Stasis Message Bus API message type for MWI messages.
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
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.
static struct stasis_rest_handlers endpoints
REST handler for /api-docs/endpoints.json.
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...
Support for logging to various files, console and syslog Configuration in file logger.conf.
Module has failed to load, may be in an inconsistent state.
An API for managing task processing threads that can be shared across modules.
void(* loaded)(const char *object_type)
Callback for when an object type is loaded/reloaded.
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
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.
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
The arg parameter is an object of the same type.
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.
A ast_taskprocessor structure is a singleton by name.
const ast_string_field fromuser
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
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.
struct stasis_message_type * stasis_subscription_change_type(void)
Gets the message type for subscription change notices.
Search option field mask.
const ast_string_field aors
The structure that contains MWI state.
#define AO2_GLOBAL_OBJ_STATIC(name)
Define a global object holder to be used to hold an ao2 object, statically initialized.
#define ASTERISK_GPL_KEY
The text the key() function should return.
const char * default_accept
Default body type defined for the event package this notifier handles.
Wrapper for stasis subscription.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
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.
#define ao2_global_obj_replace(holder, obj)
Replace an ao2 object in the global holder.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
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.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Sorcery Data Access Layer API.
char message_account[PJSIP_MAX_URL_SIZE]
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
#define ao2_link(container, obj)
Add an object to a container.