31 #include <pjsip_simple.h>
239 .name = {
"PubSub Module", 13 },
240 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
244 #define MOD_DATA_PERSISTENCE "sub_persistence"
245 #define MOD_DATA_MSG "sub_msg"
253 #define PUBLICATIONS_BUCKETS 37
256 #define DEFAULT_PUBLISH_EXPIRES 3600
259 #define DATASTORE_BUCKETS 53
262 #define DEFAULT_EXPIRES 3600
429 "TerminateInProgress",
560 int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
562 pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
593 if (!sub_tree->
evsub) {
599 ast_debug(3,
"Transport destroyed. Removing subscription '%s->%s' prune on boot: %d\n",
604 pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
654 char tag[PJ_GUID_STRING_LENGTH + 1];
660 "subscription_persistence",
NULL);
662 pjsip_dialog *dlg = sub_tree->
dlg;
686 ast_debug(3,
"Updating persistence for '%s->%s' prune on boot: %s\n",
695 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
NULL);
696 pjsip_contact_hdr *contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT,
NULL);
706 (pjsip_sip_uri *)pjsip_uri_get_uri(contact_hdr->uri),
710 ast_debug(3,
"adding transport monitor on %s for '%s->%s' prune on boot: %d\n",
711 rdata->tp_info.transport->obj_name,
714 sub_tree->
transport = rdata->tp_info.transport;
724 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri,
738 if (rdata->msg_info.msg_buf) {
767 ast_debug(3,
"Unregistering transport monitor on %s '%s->%s'\n",
783 size_t num_accept,
const char *
body_type);
788 pjsip_event_hdr *event_header;
792 event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &
str_event_name, rdata->msg_info.msg->hdr.next);
795 endpoint ? endpoint :
"Unknown");
803 endpoint ? endpoint :
"Unknown");
823 "application/rlmi+xml",
849 pjsip_accept_hdr *accept_header = (pjsip_accept_hdr *) &rdata->msg_info.msg->hdr;
851 size_t num_accept_headers = 0;
853 while ((accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, accept_header->next)) &&
857 for (i = 0; i < accept_header->count && num_accept_headers <
AST_SIP_MAX_ACCEPT; ++i) {
859 ast_copy_pj_str(accept[num_accept_headers], &accept_header->values[i],
sizeof(accept[num_accept_headers]));
860 ++num_accept_headers;
865 if (num_accept_headers == 0) {
870 num_accept_headers = 1;
883 pjsip_supported_hdr *supported_header = (pjsip_supported_hdr *) &rdata->msg_info.msg->hdr;
885 while ((supported_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, supported_header->next))) {
888 for (i = 0; i < supported_header->count; i++) {
889 if (!pj_stricmp2(&supported_header->values[i],
"eventlist")) {
928 ast_log(
LOG_WARNING,
"Found resource list %s, but its event type (%s) does not match SUBSCRIBE's (%s)\n",
1050 ast_debug(1,
"Already visited resource %s. Avoiding duplicate resource or potential loop.\n", resource);
1056 int resp =
handler->notifier->new_subscribe(endpoint, resource);
1057 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1060 handler->notifier->get_resource_display_name(endpoint, resource, display_name,
sizeof(display_name));
1065 "Subscription to leaf resource %s was successful, but encountered allocation error afterwards\n",
1069 ast_debug(2,
"Subscription to leaf resource %s resulted in success. Adding to parent %s\n",
1075 ast_debug(2,
"Subscription to leaf resource %s resulted in error response %d\n",
1079 ast_debug(2,
"Resource %s (child of %s) is a list\n", resource, parent->
resource);
1082 ast_debug(1,
"Cannot build children of resource %s due to allocation failure\n", resource);
1087 ast_debug(1,
"List %s had no successful children.\n", resource);
1092 ast_debug(2,
"List %s had successful children. Adding to parent %s\n",
1164 ast_debug(2,
"Subscription '%s->%s' is not to a list\n",
1170 return handler->notifier->new_subscribe(endpoint, resource);
1173 ast_debug(2,
"Subscription '%s->%s' is a list\n",
1213 ast_debug(2,
"Removing subscription '%s->%s' from list of subscriptions\n",
1225 ast_debug(3,
"Destroying SIP subscription from '%s->%s'\n",
1261 pjsip_sip_uri *request_uri;
1265 ast_log(
LOG_ERROR,
"No dialog message saved for SIP subscription. Cannot allocate subscription for resource %s\n",
resource);
1278 if (!
sub->datastores) {
1284 if (!
sub->body_text) {
1289 sub->uri = pjsip_sip_uri_create(
tree->
dlg->pool, PJ_FALSE);
1290 request_uri = pjsip_uri_get_uri(msg->line.req.uri);
1291 pjsip_sip_uri_assign(
tree->
dlg->pool,
sub->uri, request_uri);
1303 sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;
1331 sub->body_generator = generator;
1342 ast_debug(1,
"Child subscription to resource %s could not be created\n",
1348 ast_debug(1,
"Child subscription to resource %s could not be appended\n",
1376 if (
sub->handler->subscription_shutdown) {
1377 sub->handler->subscription_shutdown(
sub);
1403 ast_debug(3,
"Destroying subscription tree %p '%s->%s'\n",
1410 if (sub_tree->
dlg) {
1423 ast_debug(3,
"Removing subscription %p '%s->%s' reference to subscription tree %p\n",
1508 *dlg_status = PJ_ENOMEM;
1515 if (*dlg_status != PJ_EEXISTS) {
1526 pjsip_ua_unregister_dlg(pjsip_ua_instance(),
dlg);
1528 dlg->local.tag_hval = pj_hash_calc_tolower(0,
NULL, &
dlg->local.info->tag);
1529 pjsip_ua_register_dlg(pjsip_ua_instance(),
dlg);
1542 pjsip_dlg_dec_lock(
dlg);
1544 #ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
1545 pjsip_evsub_add_ref(sub_tree->
evsub);
1549 pjsip_msg_clone(
dlg->pool, rdata->msg_info.msg));
1593 pjsip_rx_data *rdata = recreate_data->
rdata;
1599 pjsip_sip_uri *request_uri;
1600 size_t resource_size;
1603 pjsip_expires_hdr *expires_header;
1606 request_uri = pjsip_uri_get_uri(rdata->msg_info.msg->line.req.uri);
1607 resource_size = pj_strlen(&request_uri->user) + 1;
1619 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Could not get subscription handler.\n",
1627 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Body generator not available.\n",
1640 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: The endpoint was not found\n",
1647 expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
1648 rdata->msg_info.msg->hdr.next);
1649 if (!expires_header) {
1650 expires_header = pjsip_expires_hdr_create(rdata->tp_info.pool, 0);
1651 if (!expires_header) {
1652 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Could not update expires header.\n",
1658 pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr *) expires_header);
1664 ast_debug(3,
"Expired subscription retrived from persistent store '%s' %s\n",
1670 expires_header->ivalue = expires;
1672 memset(&tree, 0,
sizeof(tree));
1675 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1676 pj_status_t dlg_status;
1679 &tree, &dlg_status, persistence);
1681 if (dlg_status != PJ_EEXISTS) {
1682 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Could not create subscription tree.\n",
1695 ind->
expires = expires_header->ivalue;
1720 pj_pool_t *pool = arg;
1722 pjsip_rx_data rdata;
1727 ast_debug(3,
"Deleting subscription marked as 'prune' from persistent store '%s' %s\n",
1735 ast_debug(3,
"Expired subscription retrived from persistent store '%s' %s\n",
1742 pj_pool_reset(pool);
1743 rdata.tp_info.pool = pool;
1748 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: The message could not be parsed\n",
1754 if (
rdata.msg_info.msg->type != PJSIP_REQUEST_MSG) {
1755 ast_log(
LOG_NOTICE,
"Failed recreating '%s' subscription: Stored a SIP response instead of a request.\n",
1764 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Could not get distributor serializer.\n",
1773 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Could not continue under distributor serializer.\n",
1790 PJSIP_POOL_RDATA_INC);
1792 ast_log(
LOG_WARNING,
"Could not create a memory pool for recreating SIP subscriptions\n");
1800 ao2_ref(persisted_subscriptions, -1);
1820 if (strcmp(
type,
"FullyBooted")) {
1838 if (!on_subscription) {
1844 if (on_subscription(i, arg)) {
1864 if (sub_tree->
dlg) {
1893 dlg =
sub->tree->dlg;
1897 return pjsip_msg_find_hdr_by_name(msg, &
name,
NULL);
1908 pjsip_tx_data *tdata;
1925 ast_log(
LOG_WARNING,
"No contacts configured for endpoint %s. Unable to create SIP subsription\n",
1946 if (pjsip_evsub_initiate(
evsub,
NULL, -1, &tdata) == PJ_SUCCESS) {
1947 pjsip_evsub_send_request(sub_tree->
evsub, tdata);
1953 pjsip_evsub_terminate(
evsub, PJ_TRUE);
1966 return sub->tree->dlg;
1978 return sub->tree->serializer;
2006 for (buf_size = PJSIP_MAX_PKT_LEN; size == -1 && buf_size < (PJSIP_MAX_PKT_LEN * 2); buf_size *= 2) {
2007 buf = pj_pool_alloc(tdata->pool, buf_size);
2008 size = pjsip_msg_print(tdata->msg,
buf, buf_size);
2015 tdata->buf.start =
buf;
2016 tdata->buf.cur = tdata->buf.start;
2017 tdata->buf.end = tdata->buf.start + buf_size;
2024 #ifdef TEST_FRAMEWORK
2026 pjsip_evsub *evsub = sub_tree->
evsub;
2032 pjsip_tx_data_dec_ref(tdata);
2036 res = pjsip_evsub_send_request(sub_tree->
evsub, tdata);
2043 pjsip_evsub_get_state_name(evsub),
2046 return (res == PJ_SUCCESS ? 0 : -1);
2063 static void add_rlmi_resource(pj_pool_t *pool, pj_xml_node *rlmi,
const pjsip_generic_string_hdr *cid,
2064 const char *resource_name,
const pjsip_sip_uri *resource_uri, pjsip_evsub_state
state)
2066 static pj_str_t
cid_name = {
"cid", 3 };
2067 pj_xml_node *resource;
2069 pj_xml_node *instance;
2070 pj_xml_attr *cid_attr;
2072 char uri[PJSIP_MAX_URL_SIZE];
2075 const pj_str_t cid_stripped = {
2076 .ptr = cid->hvalue.ptr + 1,
2077 .slen = cid->hvalue.slen - 2,
2084 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, resource_uri, uri,
sizeof(uri));
2087 pj_strdup2(pool, &
name->content, resource_name);
2093 state == PJSIP_EVSUB_STATE_TERMINATED ?
"terminated" :
"active");
2099 cid_attr = pj_xml_attr_new(pool, &
cid_name, &cid_stripped);
2100 pj_xml_add_attr(instance, cid_attr);
2116 pjsip_generic_string_hdr *
cid;
2146 static const pj_str_t
cid_name = {
"Content-ID", 10 };
2147 pjsip_generic_string_hdr *cid;
2153 alloc_size =
sizeof(
id) + pj_strlen(&
sub->uri->host) + 3;
2154 cid_value.ptr = pj_pool_alloc(pool, alloc_size);
2155 cid_value.slen = sprintf(cid_value.ptr,
"<%s@%.*s>",
2157 (
int) pj_strlen(&
sub->uri->host), pj_strbuf(&
sub->uri->host));
2158 cid = pjsip_generic_string_hdr_create(pool, &
cid_name, &cid_value);
2166 pj_xml_node *rlmi = msg_body->data;
2168 num_printed = pj_xml_print(rlmi,
buf, size, PJ_TRUE);
2178 const pj_xml_node *rlmi = data;
2180 return pj_xml_clone(pool, rlmi);
2203 pjsip_multipart_part *rlmi_part;
2204 char version_str[32];
2205 char uri[PJSIP_MAX_URL_SIZE];
2206 pjsip_generic_string_hdr *cid;
2215 snprintf(version_str,
sizeof(version_str),
"%u",
sub->version++);
2228 rlmi_part = pjsip_multipart_create_part(pool);
2230 rlmi_part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
2231 pjsip_media_type_cp(pool, &rlmi_part->body->content_type, &
rlmi_media_type);
2233 rlmi_part->body->data = pj_xml_clone(pool, rlmi);
2238 pj_list_insert_before(&rlmi_part->hdr,
cid);
2244 unsigned int force_full_state);
2280 bp->
state =
sub->subscription_state;
2299 pjsip_msg_body *body;
2313 bp->
part = pjsip_multipart_create_part(pool);
2314 bp->
part->body = body;
2315 pj_list_insert_before(&bp->
part->hdr, bp->
cid);
2331 pjsip_param *media_type_param;
2333 pj_str_t pj_boundary;
2335 pjsip_media_type_init2(&
media_type,
"multipart",
"related");
2337 media_type_param = pj_pool_alloc(pool,
sizeof(*media_type_param));
2338 pj_list_init(media_type_param);
2340 pj_strdup2(pool, &media_type_param->name,
"type");
2341 pj_strdup2(pool, &media_type_param->value,
"\"application/rlmi+xml\"");
2343 pj_list_insert_before(&
media_type.param, media_type_param);
2346 return pjsip_multipart_create(pool, &
media_type, &pj_boundary);
2362 unsigned int force_full_state)
2365 pjsip_multipart_part *rlmi_part;
2366 pjsip_msg_body *multipart;
2368 unsigned int use_full_state = force_full_state ? 1 :
sub->full_state;
2391 pjsip_multipart_add_part(pool, multipart, rlmi_part);
2394 pjsip_multipart_add_part(pool, multipart,
AST_VECTOR_GET(&body_parts, i)->part);
2409 unsigned int force_full_state)
2411 pjsip_msg_body *body;
2426 body = pjsip_msg_body_create(pool, &
type, &subtype, &
text);
2443 pjsip_require_hdr *require;
2445 require = pjsip_require_hdr_create(pool);
2446 pj_strdup2(pool, &require->values[0],
"eventlist");
2464 pjsip_evsub *evsub = sub_tree->
evsub;
2465 pjsip_tx_data *tdata;
2474 NULL,
NULL, &tdata) != PJ_SUCCESS) {
2479 if (!tdata->msg->body) {
2480 pjsip_tx_data_dec_ref(tdata);
2486 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) require);
2502 pjsip_dialog *
dlg = sub_tree->
dlg;
2504 pjsip_dlg_inc_lock(
dlg);
2517 pjsip_dlg_dec_lock(
dlg);
2530 ?
"SUBSCRIPTION_TERMINATED" :
"SUBSCRIPTION_STATE_CHANGED",
2533 pjsip_dlg_dec_lock(
dlg);
2571 pjsip_dialog *
dlg =
sub->tree->dlg;
2573 pjsip_dlg_inc_lock(
dlg);
2576 pjsip_dlg_dec_lock(
dlg);
2582 pjsip_dlg_dec_lock(
dlg);
2586 sub->body_changed = 1;
2588 sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2592 if (
sub->tree->notification_batch_interval) {
2603 sub->tree->root->resource);
2607 pjsip_dlg_dec_lock(
dlg);
2618 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR,
sub->uri,
buf, size);
2627 uri = pjsip_uri_get_uri(
dlg->remote.info->uri);
2629 if (pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, uri,
buf, size) < 0) {
2636 return sub->resource;
2641 return sub->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ? 1 : 0;
2653 pj_list_init(&res_hdr);
2659 return pjsip_evsub_accept(sub_tree->
evsub, rdata, response, &res_hdr) == PJ_SUCCESS ? 0 : -1;
2759 ast_log(
LOG_ERROR,
"No event package specified for publish handler. Cannot register\n");
2766 ast_log(
LOG_ERROR,
"Could not allocate publications container for event '%s'\n",
2823 ast_log(
LOG_ERROR,
"No event package specified for subscription handler. Cannot register\n");
2830 "Unable to register subscription handler for event %s. A handler is already registered\n",
2901 size_t num_accept,
const char *
body_type)
2906 for (i = 0; i < num_accept; ++i) {
2909 ast_debug(3,
"Body generator %p found for accept type %s\n", generator, accept[i]);
2911 ast_log(
LOG_WARNING,
"Body generator '%s/%s'(%p) does not accept the type of data this event generates\n",
2918 ast_debug(3,
"No body generator found for accept type %s\n", accept[i]);
2946 if (
sub->handler->notifier->subscription_established(
sub)) {
2996 ast_log(
LOG_ERROR,
"Unable to create expiration timer of %d seconds for %s\n",
3009 pjsip_expires_hdr *expires_header;
3015 pjsip_uri *request_uri;
3016 pjsip_sip_uri *request_uri_sip;
3017 size_t resource_size;
3020 pj_status_t dlg_status;
3025 if (!endpoint->subscription.allow) {
3031 request_uri = rdata->msg_info.msg->line.req.uri;
3033 if (!PJSIP_URI_SCHEME_IS_SIP(request_uri) && !PJSIP_URI_SCHEME_IS_SIPS(request_uri)) {
3034 char uri_str[PJSIP_MAX_URL_SIZE];
3036 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str,
sizeof(uri_str));
3042 request_uri_sip = pjsip_uri_get_uri(request_uri);
3043 resource_size = pj_strlen(&request_uri_sip->user) + 1;
3053 expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next);
3054 if (expires_header) {
3055 if (expires_header->ivalue == 0) {
3056 ast_debug(1,
"Subscription request from endpoint %s rejected. Expiration of 0 is invalid\n",
3061 if (expires_header->ivalue < endpoint->subscription.minexpiry) {
3062 ast_log(
LOG_WARNING,
"Subscription expiration %d is too brief for endpoint %s. Minimum is %u\n",
3081 memset(&tree, 0,
sizeof(tree));
3084 if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3092 if (dlg_status != PJ_EEXISTS) {
3141 pjsip_generic_string_hdr *etag_hdr,
unsigned int *expires,
int *entity_id)
3143 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
NULL);
3146 char etag[pj_strlen(&etag_hdr->hvalue) + 1];
3150 if (sscanf(etag,
"%30d", entity_id) != 1) {
3159 }
else if (!etag_hdr && rdata->msg_info.msg->body) {
3161 }
else if (etag_hdr && !rdata->msg_info.msg->body) {
3163 }
else if (etag_hdr && rdata->msg_info.msg->body) {
3175 ast_debug(3,
"Destroying SIP publication\n");
3187 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
NULL);
3209 dst = publication->
data;
3211 dst += resource_len;
3218 pjsip_rx_data *rdata)
3220 pjsip_tx_data *tdata;
3221 pjsip_transaction *tsx;
3227 if (PJSIP_IS_STATUS_IN_CLASS(status_code, 200)) {
3237 if (pjsip_tsx_create_uas(&
pubsub_module, rdata, &tsx) != PJ_SUCCESS) {
3238 pjsip_tx_data_dec_ref(tdata);
3242 pjsip_tsx_recv_msg(tsx, rdata);
3244 if (pjsip_tsx_send_msg(tsx, tdata) != PJ_SUCCESS) {
3245 pjsip_tx_data_dec_ref(tdata);
3256 char *resource_name;
3257 size_t resource_size;
3260 pjsip_uri *request_uri;
3261 pjsip_sip_uri *request_uri_sip;
3264 request_uri = rdata->msg_info.msg->line.req.uri;
3266 if (!PJSIP_URI_SCHEME_IS_SIP(request_uri) && !PJSIP_URI_SCHEME_IS_SIPS(request_uri)) {
3267 char uri_str[PJSIP_MAX_URL_SIZE];
3269 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str,
sizeof(uri_str));
3275 request_uri_sip = pjsip_uri_get_uri(request_uri);
3276 resource_size = pj_strlen(&request_uri_sip->user) + 1;
3278 ast_copy_pj_str(resource_name, &request_uri_sip->user, resource_size);
3288 ast_debug(1,
"No 'inbound-publication' defined for resource '%s'\n", resource_name);
3294 ast_debug(1,
"Resource %s has a defined endpoint '%s', but does not match endpoint '%s' that received the request\n",
3300 for (event_configuration_name = resource->events; event_configuration_name; event_configuration_name = event_configuration_name->
next) {
3301 if (!strcmp(event_configuration_name->
name,
handler->event_name)) {
3306 if (!event_configuration_name) {
3307 ast_debug(1,
"Event '%s' is not configured for '%s'\n",
handler->event_name, resource_name);
3312 resp =
handler->new_publication(endpoint, resource_name, event_configuration_name->
value);
3314 if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3343 if (publication->handler->publish_expire) {
3344 publication->handler->publish_expire(publication);
3366 pjsip_event_hdr *event_header;
3370 static const pj_str_t str_sip_if_match = {
"SIP-If-Match", 12 };
3371 pjsip_generic_string_hdr *etag_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_sip_if_match,
NULL);
3374 unsigned int expires = 0;
3375 int entity_id, response = 0;
3380 event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &
str_event_name, rdata->msg_info.msg->hdr.next);
3381 if (!event_header) {
3402 static const pj_str_t str_conditional_request_failed = {
"Conditional Request Failed", 26 };
3413 publication->expires = expires;
3416 switch (publish_type) {
3422 if (
handler->publication_state_change(publication, rdata->msg_info.msg->body,
3430 handler->publication_state_change(publication, rdata->msg_info.msg->body,
3482 pj_size_t accept_len;
3496 accept_len = strlen(generator->
type) + strlen(generator->
subtype) + 1;
3499 pj_strset(&accept,
ast_alloca(accept_len + 1), accept_len);
3500 sprintf((
char *) pj_strbuf(&accept),
"%s/%s", generator->
type, generator->
subtype);
3503 PJSIP_H_ACCEPT,
NULL, 1, &accept);
3514 if (iter == generator) {
3538 if (iter == supplement) {
3549 return sub->body_generator->type;
3554 return sub->body_generator->subtype;
3573 ast_log(
LOG_WARNING,
"%s/%s body generator does not accept the type of data provided\n",
3592 if (!strcmp(generator->
type, supplement->
type) &&
3628 int found_counts = 0;
3635 memset(summary, 0,
sizeof(*summary));
3640 if (sscanf(line,
"voice-message: %d/%d (%d/%d)",
3649 return !found_counts;
3656 const char *endpoint_name;
3665 ast_debug(1,
"Incoming MWI: Endpoint not found in rdata (%p)\n", rdata);
3671 ast_debug(1,
"Incoming MWI: Found endpoint: %s\n", endpoint_name);
3673 ast_debug(1,
"Incoming MWI: No incoming mailbox specified for endpoint '%s'\n", endpoint_name);
3675 "Endpoint: %s", endpoint_name);
3681 atsign = strchr(
mailbox,
'@');
3683 ast_debug(1,
"Incoming MWI: No '@' found in endpoint %s's incoming mailbox '%s'. Can't parse context\n",
3684 endpoint_name, endpoint->incoming_mwi_mailbox);
3692 body =
ast_alloca(rdata->msg_info.msg->body->len + 1);
3693 rdata->msg_info.msg->body->print_body(rdata->msg_info.msg->body, body,
3694 rdata->msg_info.msg->body->len + 1);
3697 ast_debug(1,
"Incoming MWI: Endpoint: '%s' There was an issue getting message info from body '%s'\n",
3705 ast_log(
LOG_ERROR,
"Incoming MWI: Endpoint: '%s' Could not publish MWI to stasis. "
3706 "Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3707 endpoint_name, endpoint->incoming_mwi_mailbox, summary.
message_account,
3712 ast_debug(1,
"Incoming MWI: Endpoint: '%s' Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3713 endpoint_name, endpoint->incoming_mwi_mailbox, summary.
message_account,
3719 "MessageAccount: %s\r\n"
3720 "VoiceMessagesNew: %d\r\n"
3721 "VoiceMessagesOld: %d\r\n"
3722 "VoiceMessagesUrgentNew: %d\r\n"
3723 "VoiceMessagesUrgentOld: %d",
3724 endpoint_name, endpoint->incoming_mwi_mailbox, summary.
message_account,
3737 if (rdata->msg_info.msg->body &&
3739 "application",
"simple-message-summary")) {
3747 if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method())) {
3751 }
else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_notify_method)) {
3762 sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
3850 ast_debug(3,
"evsub %p state %s event %s sub_tree %p sub_tree state %s\n",
evsub,
3851 pjsip_evsub_get_state_name(
evsub), pjsip_event_str(
event->type), sub_tree,
3854 if (!sub_tree || pjsip_evsub_get_state(
evsub) != PJSIP_EVSUB_STATE_TERMINATED) {
3867 char task_name[256];
3870 ast_debug(3,
"Cancelling timer: %s\n", task_name);
3880 #ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
3881 pjsip_evsub_dec_ref(sub_tree->
evsub);
3900 pjsip_dialog *
dlg = sub_tree->
dlg;
3902 ast_debug(3,
"sub_tree %p sub_tree state %s\n", sub_tree,
3905 pjsip_dlg_inc_lock(
dlg);
3907 pjsip_dlg_dec_lock(
dlg);
3919 pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
3920 pjsip_dlg_dec_lock(
dlg);
3928 "SUBSCRIPTION_TERMINATED" :
"SUBSCRIPTION_REFRESHED",
3931 pjsip_dlg_dec_lock(
dlg);
3940 ast_debug(3,
"sub_tree %p sub_tree state %s\n", sub_tree,
3961 return strcmp(s1, s2);
4005 int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
4010 ast_debug(3,
"evsub %p sub_tree %p sub_tree state %s\n",
evsub, sub_tree,
4018 char task_name[256];
4021 ast_debug(3,
"Cancelling timer: %s\n", task_name);
4031 if (pjsip_evsub_get_state(sub_tree->
evsub) == PJSIP_EVSUB_STATE_TERMINATED) {
4051 memset(&tree, 0,
sizeof(tree));
4054 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
4060 sub_tree->
root = new_root;
4070 pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
4092 pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
4100 sub->handler->subscriber->state_change(
sub, rdata->msg_info.msg->body,
4101 pjsip_evsub_get_state(evsub));
4107 pjsip_tx_data *tdata;
4109 if (!sub_tree->
evsub) {
4114 if (pjsip_evsub_initiate(sub_tree->
evsub,
NULL, -1, &tdata) == PJ_SUCCESS) {
4115 pjsip_evsub_send_request(sub_tree->
evsub, tdata);
4117 pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
4188 sub_tree, arg,
"InboundSubscriptionDetail") : 0;
4194 sub_tree, arg,
"OutboundSubscriptionDetail") : 0;
4260 astman_send_listack(s, m,
"A listing of resource lists follows, presented as ResourceListDetail events",
4270 #define AMI_SHOW_SUBSCRIPTIONS_INBOUND "PJSIPShowSubscriptionsInbound"
4271 #define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND "PJSIPShowSubscriptionsOutbound"
4273 #define MAX_REGEX_ERROR_LEN 128
4299 if (!sub_tree->
dlg) {
4303 callid = &sub_tree->
dlg->call_id->id;
4304 if (
cli->wordlen <= pj_strlen(callid)
4305 && !strncasecmp(
cli->a->word, pj_strbuf(callid),
cli->wordlen)
4306 && (++
cli->which >
cli->a->n)) {
4337 if (!strcasecmp(
a->argv[3],
"inbound")) {
4339 }
else if (!strcasecmp(
a->argv[3],
"outbound")) {
4349 cli.wordlen = strlen(
a->word);
4372 const char *
callid = (
const char *)
cli->buf;
4373 pj_str_t *sub_callid;
4381 int key_filler_width;
4384 if (!sub_tree->
dlg) {
4387 sub_callid = &sub_tree->
dlg->call_id->id;
4388 if (pj_strcmp2(sub_callid,
callid)) {
4399 "===========================================================================\n",
4400 "ParameterName",
"ParameterValue");
4427 value = strchr(key,
':');
4431 value_end = strchr(
value,
'\n');
4437 key_len =
value - key;
4438 key_filler_width = 20 - key_len;
4439 if (key_filler_width < 0) {
4440 key_filler_width = 0;
4442 value_len = value_end -
value;
4445 key_len, key, key_filler_width,
"",
4448 key = value_end + 1;
4476 e->
command =
"pjsip show subscription {inbound|outbound}";
4478 " pjsip show subscription inbound <call-id>\n"
4479 " pjsip show subscription outbound <call-id>\n"
4480 " Show active subscription with the dialog call-id\n";
4490 if (!strcasecmp(
a->argv[3],
"inbound")) {
4492 }
else if (!strcasecmp(
a->argv[3],
"outbound")) {
4503 cli.buf = (
void *)
a->argv[4];
4509 #define CLI_SHOW_SUB_FORMAT_HEADER \
4510 "Endpoint: <Endpoint/Caller-ID.............................................>\n" \
4511 "Resource: <Resource/Event.................................................>\n" \
4512 " Expiry: <Expiry> <Call-id..............................................>\n" \
4513 "===========================================================================\n\n"
4514 #define CLI_SHOW_SUB_FORMAT_ENTRY \
4515 "Endpoint: %s/%s\n" \
4516 "Resource: %s/%s\n" \
4517 " Expiry: %8d %s\n\n"
4521 char caller_id[256];
4532 if (sub_tree->
dlg) {
4577 e->
command =
"pjsip show subscriptions {inbound|outbound} [like]";
4579 " pjsip show subscriptions inbound [like <regex>]\n"
4580 " Show active inbound subscriptions\n"
4581 " pjsip show subscriptions outbound [like <regex>]\n"
4582 " Show active outbound subscriptions\n"
4584 " The regex selects a subscriptions output that matches.\n"
4585 " i.e., All output lines for a subscription are checked\n"
4586 " as a block by the regex.\n";
4592 if (
a->argc != 4 &&
a->argc != 6) {
4595 if (!strcasecmp(
a->argv[3],
"inbound")) {
4597 }
else if (!strcasecmp(
a->argv[3],
"outbound")) {
4607 if (strcasecmp(
a->argv[4],
"like")) {
4615 rc = regcomp(
cli.like,
regex, REG_EXTENDED | REG_NOSUB);
4620 ast_cli(
a->fd,
"Regular expression '%s' failed to compile: %s\n",
4642 ast_cli(
a->fd,
"%d active subscriptions%s%s%s\n",
4644 regex ?
" matched \"" :
"",
4656 #define CLI_LIST_SUB_FORMAT_HEADER "%-30.30s %-30.30s %6.6s %s\n"
4657 #define CLI_LIST_SUB_FORMAT_ENTRY "%-30.30s %-30.30s %6d %s\n"
4661 char ep_cid_buf[50];
4662 char res_evt_buf[50];
4666 snprintf(ep_cid_buf,
sizeof(ep_cid_buf),
"%s/%s",
4673 snprintf(res_evt_buf,
sizeof(res_evt_buf),
"%s/%s",
4678 if (sub_tree->
dlg) {
4724 e->
command =
"pjsip list subscriptions {inbound|outbound} [like]";
4726 " pjsip list subscriptions inbound [like <regex>]\n"
4727 " List active inbound subscriptions\n"
4728 " pjsip list subscriptions outbound [like <regex>]\n"
4729 " List active outbound subscriptions\n"
4731 " The regex selects output lines that match.\n";
4737 if (
a->argc != 4 &&
a->argc != 6) {
4740 if (!strcasecmp(
a->argv[3],
"inbound")) {
4742 }
else if (!strcasecmp(
a->argv[3],
"outbound")) {
4752 if (strcasecmp(
a->argv[4],
"like")) {
4760 rc = regcomp(
cli.like,
regex, REG_EXTENDED | REG_NOSUB);
4765 ast_cli(
a->fd,
"Regular expression '%s' failed to compile: %s\n",
4786 "Endpoint/CLI",
"Resource/Event",
"Expiry",
"Call-id");
4788 ast_cli(
a->fd,
"\n%d active subscriptions%s%s%s\n",
4790 regex ?
" matched \"" :
"",