31#include <pjsip_simple.h> 
  446    .name = { 
"PubSub Module", 13 },
 
  447    .priority = PJSIP_MOD_PRIORITY_APPLICATION,
 
 
  451#define MOD_DATA_PERSISTENCE "sub_persistence" 
  452#define MOD_DATA_MSG "sub_msg" 
  460#define PUBLICATIONS_BUCKETS 37 
  463#define DEFAULT_PUBLISH_EXPIRES 3600 
  466#define DATASTORE_BUCKETS 53 
  469#define DEFAULT_EXPIRES 3600 
  636    "TerminateInProgress",
 
 
  767        int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
 
  769        pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
 
  800    if (!sub_tree->
evsub) {
 
  806    ast_debug(3, 
"Transport destroyed.  Removing subscription '%s->%s'  prune on boot: %d\n",
 
  811    pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
 
 
  861    char tag[PJ_GUID_STRING_LENGTH + 1];
 
  867        "subscription_persistence", 
NULL);
 
  869    pjsip_dialog *dlg = sub_tree->
dlg;
 
 
  893    ast_debug(3, 
"Updating persistence for '%s->%s'  prune on boot: %s\n",
 
  902        pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, 
NULL);
 
  903        pjsip_contact_hdr *contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, 
NULL);
 
  913                            (pjsip_sip_uri *)pjsip_uri_get_uri(contact_hdr->uri),
 
  917                        ast_debug(3, 
"adding transport monitor on %s for '%s->%s'  prune on boot: %d\n",
 
  918                            rdata->tp_info.transport->obj_name,
 
  932            pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri,
 
  946            if (rdata->msg_info.msg_buf) {
 
 
  975        ast_debug(3, 
"Unregistering transport monitor on %s '%s->%s'\n",
 
 
  991        size_t num_accept, 
const char *
body_type);
 
  996    pjsip_event_hdr *event_header;
 
 1000    event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &
str_event_name, rdata->msg_info.msg->hdr.next);
 
 1001    if (!event_header) {
 
 1003            endpoint ? endpoint : 
"Unknown");
 
 1011            endpoint ? endpoint : 
"Unknown");
 
 
 1030    "multipart/related",
 
 1031    "application/rlmi+xml",
 
 
 1057    pjsip_accept_hdr *accept_header = (pjsip_accept_hdr *) &rdata->msg_info.msg->hdr;
 
 1059    size_t num_accept_headers = 0;
 
 1061    while ((accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, accept_header->next)) &&
 
 1065        for (i = 0; i < accept_header->count && num_accept_headers < 
AST_SIP_MAX_ACCEPT; ++i) {
 
 1067                ast_copy_pj_str(accept[num_accept_headers], &accept_header->values[i], 
sizeof(accept[num_accept_headers]));
 
 1068                ++num_accept_headers;
 
 1073    if (num_accept_headers == 0) {
 
 1078        num_accept_headers = 1;
 
 
 1091    pjsip_supported_hdr *supported_header = (pjsip_supported_hdr *) &rdata->msg_info.msg->hdr;
 
 1093    while ((supported_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, supported_header->next))) {
 
 1096        for (i = 0; i < supported_header->count; i++) {
 
 1097            if (!pj_stricmp2(&supported_header->values[i], 
"eventlist")) {
 
 
 1136        ast_log(
LOG_WARNING, 
"Found resource list %s, but its event type (%s) does not match SUBSCRIBE's (%s)\n",
 
 
 1228#define NEW_SUBSCRIBE(notifier, endpoint, resource, rdata) notifier->new_subscribe_with_rdata ? notifier->new_subscribe_with_rdata(endpoint, resource, rdata) : notifier->new_subscribe(endpoint, resource) 
 1262            ast_debug(1, 
"Already visited resource %s. Avoiding duplicate resource or potential loop.\n", resource);
 
 1269            if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
 
 1272                    handler->notifier->get_resource_display_name(endpoint, resource, display_name, 
sizeof(display_name));
 
 1277                        "Subscription to leaf resource %s was successful, but encountered allocation error afterwards\n",
 
 1281                ast_debug(2, 
"Subscription to leaf resource %s resulted in success. Adding to parent %s\n",
 
 1287                ast_debug(2, 
"Subscription to leaf resource %s resulted in error response %d\n",
 
 1291            ast_debug(2, 
"Resource %s (child of %s) is a list\n", resource, parent->
resource);
 
 1294                ast_debug(1, 
"Cannot build children of resource %s due to allocation failure\n", resource);
 
 1299                ast_debug(1, 
"List %s had no successful children.\n", resource);
 
 1304                ast_debug(2, 
"List %s had successful children. Adding to parent %s\n",
 
 
 1378        ast_debug(2, 
"Subscription '%s->%s' is not to a list\n",
 
 1387    ast_debug(2, 
"Subscription '%s->%s' is a list\n",
 
 
 1427                ast_debug(2, 
"Removing subscription '%s->%s' from list of subscriptions\n",
 
 
 1439    ast_debug(3, 
"Destroying SIP subscription from '%s->%s'\n",
 
 
 1475    pjsip_sip_uri *request_uri;
 
 1479        ast_log(
LOG_ERROR, 
"No dialog message saved for SIP subscription. Cannot allocate subscription for resource %s\n", 
resource);
 
 1492    if (!
sub->datastores) {
 
 1498    if (!
sub->body_text) {
 
 1503    sub->uri = pjsip_sip_uri_create(
tree->
dlg->pool, PJ_FALSE);
 
 1504    request_uri = pjsip_uri_get_uri(msg->line.req.uri);
 
 1505    pjsip_sip_uri_assign(
tree->
dlg->pool, 
sub->uri, request_uri);
 
 1517    sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;
 
 
 1545    sub->body_generator = generator;
 
 1556            ast_debug(1, 
"Child subscription to resource %s could not be created\n",
 
 1562            ast_debug(1, 
"Child subscription to resource %s could not be appended\n",
 
 
 1590    if (
sub->handler->subscription_shutdown) {
 
 1591        sub->handler->subscription_shutdown(
sub);
 
 
 1618    ast_debug(3, 
"Destroying subscription tree %p '%s->%s'\n",
 
 1625    if (sub_tree->
dlg) {
 
 
 1638    ast_debug(3, 
"Removing subscription %p '%s->%s' reference to subscription tree %p\n",
 
 
 1723        *dlg_status = PJ_ENOMEM;
 
 1730        if (*dlg_status != PJ_EEXISTS) {
 
 1741        pjsip_ua_unregister_dlg(pjsip_ua_instance(), 
dlg);
 
 1743        dlg->local.tag_hval = pj_hash_calc_tolower(0, 
NULL, &
dlg->local.info->tag);
 
 1744        pjsip_ua_register_dlg(pjsip_ua_instance(), 
dlg);
 
 1757    pjsip_dlg_dec_lock(
dlg);
 
 1759#ifdef HAVE_PJSIP_EVSUB_GRP_LOCK 
 1760    pjsip_evsub_add_ref(sub_tree->
evsub);
 
 1764            pjsip_msg_clone(
dlg->pool, rdata->msg_info.msg));
 
 
 1808    pjsip_rx_data *rdata = recreate_data->
rdata;
 
 1814    size_t resource_size;
 
 1817    pjsip_expires_hdr *expires_header;
 
 1819    const pj_str_t *
user;
 
 1822    resource_size = pj_strlen(
user) + 1;
 
 1834        ast_log(
LOG_WARNING, 
"Failed recreating '%s' subscription: Could not get subscription handler.\n",
 
 1842        ast_log(
LOG_WARNING, 
"Failed recreating '%s' subscription: Body generator not available.\n",
 
 1855        ast_log(
LOG_WARNING, 
"Failed recreating '%s' subscription: The endpoint was not found\n",
 
 1862    expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
 
 1863        rdata->msg_info.msg->hdr.next);
 
 1864    if (!expires_header) {
 
 1865        expires_header = pjsip_expires_hdr_create(rdata->tp_info.pool, 0);
 
 1866        if (!expires_header) {
 
 1867            ast_log(
LOG_WARNING, 
"Failed recreating '%s' subscription: Could not update expires header.\n",
 
 1873        pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr *) expires_header);
 
 1879        ast_debug(3, 
"Expired subscription retrived from persistent store '%s' %s\n",
 
 1885    expires_header->ivalue = expires;
 
 1887    memset(&tree, 0, 
sizeof(tree));
 
 1890    if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
 
 1891        pj_status_t dlg_status;
 
 1894            &tree, &dlg_status, persistence);
 
 1896            if (dlg_status != PJ_EEXISTS) {
 
 1897                ast_log(
LOG_WARNING, 
"Failed recreating '%s' subscription: Could not create subscription tree.\n",
 
 1910            ind->
expires = expires_header->ivalue;
 
 
 1935    pj_pool_t *pool = arg;
 
 1937    pjsip_rx_data rdata;
 
 1942        ast_debug(3, 
"Deleting subscription marked as 'prune' from persistent store '%s' %s\n",
 
 1950        ast_debug(3, 
"Expired subscription retrived from persistent store '%s' %s\n",
 
 1957    pj_pool_reset(pool);
 
 1958    rdata.tp_info.pool = pool;
 
 1963        ast_log(
LOG_WARNING, 
"Failed recreating '%s' subscription: The message could not be parsed\n",
 
 1969    if (
rdata.msg_info.msg->type != PJSIP_REQUEST_MSG) {
 
 1970        ast_log(
LOG_NOTICE, 
"Failed recreating '%s' subscription: Stored a SIP response instead of a request.\n",
 
 1979        ast_log(
LOG_WARNING, 
"Failed recreating '%s' subscription: Could not get distributor serializer.\n",
 
 1988        ast_log(
LOG_WARNING, 
"Failed recreating '%s' subscription: Could not continue under distributor serializer.\n",
 
 
 2005        PJSIP_POOL_RDATA_INC);
 
 2007        ast_log(
LOG_WARNING, 
"Could not create a memory pool for recreating SIP subscriptions\n");
 
 2015    ao2_ref(persisted_subscriptions, -1);
 
 
 2035    if (strcmp(
type, 
"FullyBooted")) {
 
 
 2053    if (!on_subscription) {
 
 2059        if (on_subscription(i, arg)) {
 
 
 2079    if (sub_tree->
dlg) {
 
 
 2108    dlg = 
sub->tree->dlg;
 
 2112    return pjsip_msg_find_hdr_by_name(msg, &
name, 
NULL);
 
 
 2123    pjsip_tx_data *tdata;
 
 2140        ast_log(
LOG_WARNING, 
"No contacts configured for endpoint %s. Unable to create SIP subsription\n",
 
 2161    if (pjsip_evsub_initiate(
evsub, 
NULL, -1, &tdata) == PJ_SUCCESS) {
 
 2162        pjsip_evsub_send_request(sub_tree->
evsub, tdata);
 
 2168        pjsip_evsub_terminate(
evsub, PJ_TRUE);
 
 
 2181    return sub->tree->dlg;
 
 
 2193    return sub->tree->serializer;
 
 
 2221    for (buf_size = PJSIP_MAX_PKT_LEN; size == -1 && buf_size < (PJSIP_MAX_PKT_LEN * 2); buf_size *= 2) {
 
 2222        buf = pj_pool_alloc(tdata->pool, buf_size);
 
 2223        size = pjsip_msg_print(tdata->msg, 
buf, buf_size);
 
 2230    tdata->buf.start = 
buf;
 
 2231    tdata->buf.cur = tdata->buf.start;
 
 2232    tdata->buf.end = tdata->buf.start + buf_size;
 
 
 2239#ifdef TEST_FRAMEWORK 
 2241    pjsip_evsub *evsub = sub_tree->
evsub;
 
 2247        pjsip_tx_data_dec_ref(tdata);
 
 2251    res = pjsip_evsub_send_request(sub_tree->
evsub, tdata);
 
 2258        pjsip_evsub_get_state_name(evsub),
 
 2261    return (res == PJ_SUCCESS ? 0 : -1);
 
 
 2278static void add_rlmi_resource(pj_pool_t *pool, pj_xml_node *rlmi, 
const pjsip_generic_string_hdr *cid,
 
 2279        const char *resource_name, 
const pjsip_sip_uri *resource_uri, pjsip_evsub_state 
state)
 
 2281    static pj_str_t cid_name = { 
"cid", 3 };
 
 2282    pj_xml_node *resource;
 
 2284    pj_xml_node *instance;
 
 2285    pj_xml_attr *cid_attr;
 
 2287    char uri[PJSIP_MAX_URL_SIZE];
 
 2288    char name_sanitized[PJSIP_MAX_URL_SIZE];
 
 2291    const pj_str_t cid_stripped = {
 
 2292        .ptr = cid->hvalue.ptr + 1,
 
 2293        .slen = cid->hvalue.slen - 2,
 
 2300    pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, resource_uri, uri, 
sizeof(uri));
 
 2304    pj_strdup2(pool, &
name->content, name_sanitized);
 
 2310            state == PJSIP_EVSUB_STATE_TERMINATED ? 
"terminated" : 
"active");
 
 2316    cid_attr = pj_xml_attr_new(pool, &cid_name, &cid_stripped);
 
 2317    pj_xml_add_attr(instance, cid_attr);
 
 
 2333    pjsip_generic_string_hdr *
cid;
 
 
 2363    static const pj_str_t cid_name = { 
"Content-ID", 10 };
 
 2364    pjsip_generic_string_hdr *cid;
 
 2370    alloc_size = 
sizeof(
id) + pj_strlen(&
sub->uri->host) + 3;
 
 2371    cid_value.ptr = pj_pool_alloc(pool, alloc_size);
 
 2372    cid_value.slen = sprintf(cid_value.ptr, 
"<%s@%.*s>",
 
 2374            (
int) pj_strlen(&
sub->uri->host), pj_strbuf(&
sub->uri->host));
 
 2375    cid = pjsip_generic_string_hdr_create(pool, &cid_name, &cid_value);
 
 
 2383    pj_xml_node *rlmi = msg_body->data;
 
 2385    num_printed = pj_xml_print(rlmi, 
buf, size, PJ_TRUE);
 
 
 2395    const pj_xml_node *rlmi = data;
 
 2397    return pj_xml_clone(pool, rlmi);
 
 
 2420    pjsip_multipart_part *rlmi_part;
 
 2421    char version_str[32];
 
 2422    char uri[PJSIP_MAX_URL_SIZE];
 
 2423    pjsip_generic_string_hdr *cid;
 
 2432    snprintf(version_str, 
sizeof(version_str), 
"%u", 
sub->version++);
 
 2445    rlmi_part = pjsip_multipart_create_part(pool);
 
 2447    rlmi_part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
 
 2448    pjsip_media_type_cp(pool, &rlmi_part->body->content_type, &
rlmi_media_type);
 
 2450    rlmi_part->body->data = pj_xml_clone(pool, rlmi);
 
 2455    pj_list_insert_before(&rlmi_part->hdr, 
cid);
 
 
 2461        unsigned int force_full_state);
 
 2497    bp->
state = 
sub->subscription_state;
 
 
 2516    pjsip_msg_body *body;
 
 2530    bp->
part = pjsip_multipart_create_part(pool);
 
 2531    bp->
part->body = body;
 
 2532    pj_list_insert_before(&bp->
part->hdr, bp->
cid);
 
 
 2547    pjsip_media_type media_type;
 
 2548    pjsip_param *media_type_param;
 
 2550    pj_str_t pj_boundary;
 
 2552    pjsip_media_type_init2(&media_type, 
"multipart", 
"related");
 
 2554    media_type_param = pj_pool_alloc(pool, 
sizeof(*media_type_param));
 
 2555    pj_list_init(media_type_param);
 
 2557    pj_strdup2(pool, &media_type_param->name, 
"type");
 
 2558    pj_strdup2(pool, &media_type_param->value, 
"\"application/rlmi+xml\"");
 
 2560    pj_list_insert_before(&media_type.param, media_type_param);
 
 2563    return pjsip_multipart_create(pool, &media_type, &pj_boundary);
 
 
 2579        unsigned int force_full_state)
 
 2582    pjsip_multipart_part *rlmi_part;
 
 2583    pjsip_msg_body *multipart;
 
 2585    unsigned int use_full_state = force_full_state ? 1 : 
sub->full_state;
 
 2608    pjsip_multipart_add_part(pool, multipart, rlmi_part);
 
 2611        pjsip_multipart_add_part(pool, multipart, 
AST_VECTOR_GET(&body_parts, i)->part);
 
 
 2626        unsigned int force_full_state)
 
 2628    pjsip_msg_body *body;
 
 2643            body = pjsip_msg_body_create(pool, &
type, &subtype, &
text);
 
 
 2660    pjsip_require_hdr *require;
 
 2662    require = pjsip_require_hdr_create(pool);
 
 2663    pj_strdup2(pool, &require->values[0], 
"eventlist");
 
 
 2673    sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
 
 
 2691    pjsip_evsub *evsub = sub_tree->
evsub;
 
 2692    pjsip_tx_data *tdata;
 
 2701                NULL, 
NULL, &tdata) != PJ_SUCCESS) {
 
 2706    if (!tdata->msg->body) {
 
 2707        pjsip_tx_data_dec_ref(tdata);
 
 2713        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) require);
 
 
 2735    pjsip_dialog *
dlg = sub_tree->
dlg;
 
 2737    pjsip_dlg_inc_lock(
dlg);
 
 2750        pjsip_dlg_dec_lock(
dlg);
 
 2763            ? 
"SUBSCRIPTION_TERMINATED" : 
"SUBSCRIPTION_STATE_CHANGED",
 
 2766    pjsip_dlg_dec_lock(
dlg);
 
 
 2804    pjsip_dialog *
dlg = 
sub->tree->dlg;
 
 2806    pjsip_dlg_inc_lock(
dlg);
 
 2809        pjsip_dlg_dec_lock(
dlg);
 
 2815        pjsip_dlg_dec_lock(
dlg);
 
 2819    sub->body_changed = 1;
 
 2821        sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
 
 2825    if (
sub->tree->notification_batch_interval) {
 
 2836                sub->tree->root->resource);
 
 2840    pjsip_dlg_dec_lock(
dlg);
 
 
 2851    pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, 
sub->uri, 
buf, size);
 
 
 2860    uri = pjsip_uri_get_uri(
dlg->remote.info->uri);
 
 2862    if (pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, uri, 
buf, size) < 0) {
 
 
 2869    return sub->resource;
 
 
 2874    return sub->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ? 1 : 0;
 
 
 2886    pj_list_init(&res_hdr);
 
 2892    return pjsip_evsub_accept(sub_tree->
evsub, rdata, response, &res_hdr) == PJ_SUCCESS ? 0 : -1;
 
 
 2992        ast_log(
LOG_ERROR, 
"No event package specified for publish handler. Cannot register\n");
 
 2999        ast_log(
LOG_ERROR, 
"Could not allocate publications container for event '%s'\n",
 
 
 3056        ast_log(
LOG_ERROR, 
"No event package specified for subscription handler. Cannot register\n");
 
 3063            "Unable to register subscription handler for event %s.  A handler is already registered\n",
 
 
 3134        size_t num_accept, 
const char *
body_type)
 
 3139    for (i = 0; i < num_accept; ++i) {
 
 3142            ast_debug(3, 
"Body generator %p found for accept type %s\n", generator, accept[i]);
 
 3144                ast_log(
LOG_WARNING, 
"Body generator '%s/%s'(%p) does not accept the type of data this event generates\n",
 
 3151            ast_debug(3, 
"No body generator found for accept type %s\n", accept[i]);
 
 
 3179    if (
sub->handler->notifier->subscription_established(
sub)) {
 
 3185        ast_debug(3, 
"No notify data, not generating any body content\n");
 
 
 3230            ast_log(
LOG_ERROR, 
"Unable to create expiration timer of %d seconds for %s\n",
 
 
 3243    pjsip_expires_hdr *expires_header;
 
 3249    pjsip_uri *request_uri;
 
 3250    size_t resource_size;
 
 3253    pj_status_t dlg_status;
 
 3254    const pj_str_t *
user;
 
 3259    if (!endpoint->subscription.allow) {
 
 3265    request_uri = rdata->msg_info.msg->line.req.uri;
 
 3268        char uri_str[PJSIP_MAX_URL_SIZE];
 
 3270        pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, 
sizeof(uri_str));
 
 3277    resource_size = pj_strlen(
user) + 1;
 
 3287    expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next);
 
 3288    if (expires_header) {
 
 3289        if (expires_header->ivalue == 0) {
 
 3290            ast_debug(1, 
"Subscription request from endpoint %s rejected. Expiration of 0 is invalid\n",
 
 3295        if (expires_header->ivalue < endpoint->subscription.minexpiry) {
 
 3296            ast_log(
LOG_WARNING, 
"Subscription expiration %d is too brief for endpoint %s. Minimum is %u\n",
 
 3315    memset(&tree, 0, 
sizeof(tree));
 
 3318    if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
 
 3326        if (dlg_status != PJ_EEXISTS) {
 
 3327            ast_debug(3, 
"No dialog exists, rejecting\n");
 
 
 3376    pjsip_generic_string_hdr *etag_hdr, 
unsigned int *expires, 
int *entity_id)
 
 3378    pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, 
NULL);
 
 3381        char etag[pj_strlen(&etag_hdr->hvalue) + 1];
 
 3385        if (sscanf(etag, 
"%30d", entity_id) != 1) {
 
 3394    } 
else if (!etag_hdr && rdata->msg_info.msg->body) {
 
 3396    } 
else if (etag_hdr && !rdata->msg_info.msg->body) {
 
 3398    } 
else if (etag_hdr && rdata->msg_info.msg->body) {
 
 
 3410    ast_debug(3, 
"Destroying SIP publication\n");
 
 
 3422    pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, 
NULL);
 
 3444    dst = publication->
data;
 
 3446    dst += resource_len;
 
 
 3453        pjsip_rx_data *rdata)
 
 3455    pjsip_tx_data *tdata;
 
 3456    pjsip_transaction *tsx;
 
 3462    if (PJSIP_IS_STATUS_IN_CLASS(status_code, 200)) {
 
 3472    if (pjsip_tsx_create_uas(&
pubsub_module, rdata, &tsx) != PJ_SUCCESS) {
 
 3473        pjsip_tx_data_dec_ref(tdata);
 
 3477    pjsip_tsx_recv_msg(tsx, rdata);
 
 3479    if (pjsip_tsx_send_msg(tsx, tdata) != PJ_SUCCESS) {
 
 3480        pjsip_tx_data_dec_ref(tdata);
 
 
 3491    char *resource_name;
 
 3492    size_t resource_size;
 
 3495    pjsip_uri *request_uri;
 
 3497    const pj_str_t *
user;
 
 3499    request_uri = rdata->msg_info.msg->line.req.uri;
 
 3502        char uri_str[PJSIP_MAX_URL_SIZE];
 
 3504        pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, 
sizeof(uri_str));
 
 3511    resource_size = pj_strlen(
user) + 1;
 
 3523        ast_debug(1, 
"No 'inbound-publication' defined for resource '%s'\n", resource_name);
 
 3529        ast_debug(1, 
"Resource %s has a defined endpoint '%s', but does not match endpoint '%s' that received the request\n",
 
 3535    for (event_configuration_name = resource->events; event_configuration_name; event_configuration_name = event_configuration_name->
next) {
 
 3536        if (!strcmp(event_configuration_name->
name, 
handler->event_name)) {
 
 3541    if (!event_configuration_name) {
 
 3542        ast_debug(1, 
"Event '%s' is not configured for '%s'\n", 
handler->event_name, resource_name);
 
 3547    resp = 
handler->new_publication(endpoint, resource_name, event_configuration_name->
value);
 
 3549    if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
 
 3564        ast_debug(3, 
"Publication state change failed\n");
 
 
 3579    if (publication->handler->publish_expire) {
 
 3580        publication->handler->publish_expire(publication);
 
 
 3602    pjsip_event_hdr *event_header;
 
 3606    static const pj_str_t str_sip_if_match = { 
"SIP-If-Match", 12 };
 
 3607    pjsip_generic_string_hdr *etag_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_sip_if_match, 
NULL);
 
 3610    unsigned int expires = 0;
 
 3611    int entity_id, response = 0;
 
 3616    event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &
str_event_name, rdata->msg_info.msg->hdr.next);
 
 3617    if (!event_header) {
 
 3638            static const pj_str_t str_conditional_request_failed = { 
"Conditional Request Failed", 26 };
 
 3649        publication->expires = expires;
 
 3652    switch (publish_type) {
 
 3658            if (
handler->publication_state_change(publication, rdata->msg_info.msg->body,
 
 3666            handler->publication_state_change(publication, rdata->msg_info.msg->body,
 
 
 3718    pj_size_t accept_len;
 
 3732    accept_len = strlen(generator->
type) + strlen(generator->
subtype) + 1;
 
 3735    pj_strset(&accept, 
ast_alloca(accept_len + 1), accept_len);
 
 3736    sprintf((
char *) pj_strbuf(&accept), 
"%s/%s", generator->
type, generator->
subtype);
 
 3739            PJSIP_H_ACCEPT, 
NULL, 1, &accept);
 
 
 3750        if (iter == generator) {
 
 
 3774        if (iter == supplement) {
 
 
 3785    return sub->body_generator->type;
 
 
 3790    return sub->body_generator->subtype;
 
 
 3809        ast_log(
LOG_WARNING, 
"%s/%s body generator does not accept the type of data provided\n",
 
 3828        if (!strcmp(generator->
type, supplement->
type) &&
 
 
 3864    int found_counts = 0;
 
 3871    memset(summary, 0, 
sizeof(*summary));
 
 3876        if (sscanf(line, 
"voice-message: %d/%d (%d/%d)",
 
 3885    return !found_counts;
 
 
 3892    const char *endpoint_name;
 
 3901        ast_debug(1, 
"Incoming MWI: Endpoint not found in rdata (%p)\n", rdata);
 
 3907    ast_debug(1, 
"Incoming MWI: Found endpoint: %s\n", endpoint_name);
 
 3909        ast_debug(1, 
"Incoming MWI: No incoming mailbox specified for endpoint '%s'\n", endpoint_name);
 
 3911            "Endpoint: %s", endpoint_name);
 
 3916    mailbox = 
ast_strdupa(endpoint->incoming_mwi_mailbox);
 
 3917    atsign = strchr(mailbox, 
'@');
 
 3919        ast_debug(1, 
"Incoming MWI: No '@' found in endpoint %s's incoming mailbox '%s'.  Can't parse context\n",
 
 3920            endpoint_name, endpoint->incoming_mwi_mailbox);
 
 3926    context = atsign + 1;
 
 3928    body = 
ast_alloca(rdata->msg_info.msg->body->len + 1);
 
 3929    rdata->msg_info.msg->body->print_body(rdata->msg_info.msg->body, body,
 
 3930        rdata->msg_info.msg->body->len + 1);
 
 3933        ast_debug(1, 
"Incoming MWI: Endpoint: '%s' There was an issue getting message info from body '%s'\n",
 
 3941        ast_log(
LOG_ERROR, 
"Incoming MWI: Endpoint: '%s' Could not publish MWI to stasis.  " 
 3942            "Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
 
 3943            endpoint_name, endpoint->incoming_mwi_mailbox, summary.
message_account,
 
 3948        ast_debug(1, 
"Incoming MWI: Endpoint: '%s' Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
 
 3949            endpoint_name, endpoint->incoming_mwi_mailbox, summary.
message_account,
 
 3955            "MessageAccount: %s\r\n" 
 3956            "VoiceMessagesNew: %d\r\n" 
 3957            "VoiceMessagesOld: %d\r\n" 
 3958            "VoiceMessagesUrgentNew: %d\r\n" 
 3959            "VoiceMessagesUrgentOld: %d",
 
 3960                endpoint_name, endpoint->incoming_mwi_mailbox, summary.
message_account,
 
 
 3973    if (rdata->msg_info.msg->body &&
 
 3975                                "application", 
"simple-message-summary")) {
 
 
 3983    if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method())) {
 
 3987    } 
else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_notify_method)) {
 
 
 4085        char task_name[256];
 
 4088        ast_debug(3, 
"Cancelling timer: %s\n", task_name);
 
 4098#ifdef HAVE_PJSIP_EVSUB_GRP_LOCK 
 4099    pjsip_evsub_dec_ref(sub_tree->
evsub);
 
 
 4116#if PJ_VERSION_NUM >= 0x020D0000 
 4117# define HAVE_PJSIP_EVSUB_PENDING_NOTIFY 1 
 4134    ast_debug(3, 
"evsub %p state %s event %s sub_tree %p sub_tree state %s\n", 
evsub,
 
 4135        pjsip_evsub_get_state_name(
evsub), pjsip_event_str(
event->type), sub_tree,
 
 4138    if (!sub_tree || pjsip_evsub_get_state(
evsub) != PJSIP_EVSUB_STATE_TERMINATED) {
 
 4150#ifdef HAVE_PJSIP_EVSUB_PENDING_NOTIFY 
 4155    if (
event->body.tsx_state.type == PJSIP_EVENT_RX_MSG &&
 
 4156        !pjsip_method_cmp(&
event->body.tsx_state.tsx->method, &pjsip_subscribe_method) &&
 
 4157        pjsip_evsub_get_expires(
evsub) == 0) {
 
 4158        ast_debug(3, 
"Subscription ending, do nothing.\n");
 
 
 4170    pjsip_dialog *
dlg = sub_tree->
dlg;
 
 4172    ast_debug(3, 
"sub_tree %p sub_tree state %s\n", sub_tree,
 
 4175    pjsip_dlg_inc_lock(
dlg);
 
 4177        pjsip_dlg_dec_lock(
dlg);
 
 4189            pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
 
 4190            pjsip_dlg_dec_lock(
dlg);
 
 4198                "SUBSCRIPTION_TERMINATED" : 
"SUBSCRIPTION_REFRESHED",
 
 4201    pjsip_dlg_dec_lock(
dlg);
 
 
 4210    ast_debug(3, 
"sub_tree %p sub_tree state %s\n", sub_tree,
 
 
 4231        return strcmp(s1, s2);
 
 
 4283        int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
 
 4289    ast_debug(3, 
"evsub %p sub_tree %p sub_tree state %s\n", 
evsub, sub_tree,
 
 4297        char task_name[256];
 
 4300        ast_debug(3, 
"Cancelling timer: %s\n", task_name);
 
 4310    if (pjsip_evsub_get_state(sub_tree->
evsub) == PJSIP_EVSUB_STATE_TERMINATED) {
 
 4336            memset(&tree, 0, 
sizeof(tree));
 
 4339            if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
 
 4345                        sub_tree->
root = new_root;
 
 4363                            ast_log(
LOG_ERROR, 
"Failed to push task to destroy old subscriptions for RLS '%s->%s'.\n",
 
 4372                pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
 
 4381#ifdef HAVE_PJSIP_EVSUB_PENDING_NOTIFY 
 
 4403        pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
 
 4411    sub->handler->subscriber->state_change(
sub, rdata->msg_info.msg->body,
 
 4412            pjsip_evsub_get_state(evsub));
 
 
 4418    pjsip_tx_data *tdata;
 
 4420    if (!sub_tree->
evsub) {
 
 4425    if (pjsip_evsub_initiate(sub_tree->
evsub, 
NULL, -1, &tdata) == PJ_SUCCESS) {
 
 4426        pjsip_evsub_send_request(sub_tree->
evsub, tdata);
 
 4428        pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
 
 
 4499        sub_tree, arg, 
"InboundSubscriptionDetail") : 0;
 
 
 4505        sub_tree, arg, 
"OutboundSubscriptionDetail") : 0;
 
 
 4571    astman_send_listack(s, m, 
"A listing of resource lists follows, presented as ResourceListDetail events",
 
 
 4581#define AMI_SHOW_SUBSCRIPTIONS_INBOUND "PJSIPShowSubscriptionsInbound" 
 4582#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND "PJSIPShowSubscriptionsOutbound" 
 4584#define MAX_REGEX_ERROR_LEN 128 
 4610    if (!sub_tree->
dlg) {
 
 4614    callid = &sub_tree->
dlg->call_id->id;
 
 4615    if (
cli->wordlen <= pj_strlen(callid)
 
 4616        && !strncasecmp(
cli->a->word, pj_strbuf(callid), 
cli->wordlen)
 
 4617        && (++
cli->which > 
cli->a->n)) {
 
 
 4648    if (!strcasecmp(
a->argv[3], 
"inbound")) {
 
 4650    } 
else if (!strcasecmp(
a->argv[3], 
"outbound")) {
 
 4660    cli.wordlen = strlen(
a->word);
 
 
 4683    const char *
callid = (
const char *) 
cli->buf;
 
 4684    pj_str_t *sub_callid;
 
 4692    int key_filler_width;
 
 4695    if (!sub_tree->
dlg) {
 
 4698    sub_callid = &sub_tree->
dlg->call_id->id;
 
 4699    if (pj_strcmp2(sub_callid, callid)) {
 
 4710        "===========================================================================\n",
 
 4711        "ParameterName", 
"ParameterValue");
 
 4738        value = strchr(key, 
':');
 
 4742        value_end = strchr(
value, 
'\n');
 
 4748        key_len = 
value - key;
 
 4749        key_filler_width = 20 - key_len;
 
 4750        if (key_filler_width < 0) {
 
 4751            key_filler_width = 0;
 
 4753        value_len = value_end - 
value;
 
 4756            key_len, key, key_filler_width, 
"",
 
 4759        key = value_end + 1;
 
 
 4787        e->
command = 
"pjsip show subscription {inbound|outbound}";
 
 4789                   "   pjsip show subscription inbound <call-id>\n" 
 4790                   "   pjsip show subscription outbound <call-id>\n" 
 4791                   "      Show active subscription with the dialog call-id\n";
 
 4801    if (!strcasecmp(
a->argv[3], 
"inbound")) {
 
 4803    } 
else if (!strcasecmp(
a->argv[3], 
"outbound")) {
 
 4814    cli.buf = (
void *) 
a->argv[4];
 
 
 4820#define CLI_SHOW_SUB_FORMAT_HEADER \ 
 4821    "Endpoint: <Endpoint/Caller-ID.............................................>\n" \ 
 4822    "Resource: <Resource/Event.................................................>\n" \ 
 4823    "  Expiry: <Expiry>  <Call-id..............................................>\n" \ 
 4824    "===========================================================================\n\n" 
 
 4825#define CLI_SHOW_SUB_FORMAT_ENTRY  \ 
 4826    "Endpoint: %s/%s\n" \ 
 4827    "Resource: %s/%s\n" \ 
 4828    "  Expiry: %8d  %s\n\n" 
 
 4832    char caller_id[256];
 
 4843    if (sub_tree->
dlg) {
 
 
 4888        e->
command = 
"pjsip show subscriptions {inbound|outbound} [like]";
 
 4890                   "   pjsip show subscriptions inbound [like <regex>]\n" 
 4891                   "      Show active inbound subscriptions\n" 
 4892                   "   pjsip show subscriptions outbound [like <regex>]\n" 
 4893                   "      Show active outbound subscriptions\n" 
 4895                   "   The regex selects a subscriptions output that matches.\n" 
 4896                   "   i.e.,  All output lines for a subscription are checked\n" 
 4897                   "   as a block by the regex.\n";
 
 4903    if (
a->argc != 4 && 
a->argc != 6) {
 
 4906    if (!strcasecmp(
a->argv[3], 
"inbound")) {
 
 4908    } 
else if (!strcasecmp(
a->argv[3], 
"outbound")) {
 
 4918        if (strcasecmp(
a->argv[4], 
"like")) {
 
 4926        rc = regcomp(
cli.like, 
regex, REG_EXTENDED | REG_NOSUB);
 
 4931            ast_cli(
a->fd, 
"Regular expression '%s' failed to compile: %s\n",
 
 4953    ast_cli(
a->fd, 
"%d active subscriptions%s%s%s\n",
 
 4955        regex ? 
" matched \"" : 
"",
 
 
 4967#define CLI_LIST_SUB_FORMAT_HEADER "%-30.30s %-30.30s %6.6s %s\n" 
 4968#define CLI_LIST_SUB_FORMAT_ENTRY  "%-30.30s %-30.30s %6d %s\n" 
 4972    char ep_cid_buf[50];
 
 4973    char res_evt_buf[50];
 
 4977    snprintf(ep_cid_buf, 
sizeof(ep_cid_buf), 
"%s/%s",
 
 4984    snprintf(res_evt_buf, 
sizeof(res_evt_buf), 
"%s/%s",
 
 4989    if (sub_tree->
dlg) {
 
 
 5035        e->
command = 
"pjsip list subscriptions {inbound|outbound} [like]";
 
 5037                   "   pjsip list subscriptions inbound [like <regex>]\n" 
 5038                   "      List active inbound subscriptions\n" 
 5039                   "   pjsip list subscriptions outbound [like <regex>]\n" 
 5040                   "      List active outbound subscriptions\n" 
 5042                   "   The regex selects output lines that match.\n";
 
 5048    if (
a->argc != 4 && 
a->argc != 6) {
 
 5051    if (!strcasecmp(
a->argv[3], 
"inbound")) {
 
 5053    } 
else if (!strcasecmp(
a->argv[3], 
"outbound")) {
 
 5063        if (strcasecmp(
a->argv[4], 
"like")) {
 
 5071        rc = regcomp(
cli.like, 
regex, REG_EXTENDED | REG_NOSUB);
 
 5076            ast_cli(
a->fd, 
"Regular expression '%s' failed to compile: %s\n",
 
 5097        "Endpoint/CLI", 
"Resource/Event", 
"Expiry", 
"Call-id");
 
 5099    ast_cli(
a->fd, 
"\n%d active subscriptions%s%s%s\n",
 
 5101        regex ? 
" matched \"" : 
"",
 
 
 5200#define RESOURCE_LIST_INIT_SIZE 4 
 5310            "pjsip.conf,criteria=type=resource_list");
 
 
 5334#ifdef TEST_FRAMEWORK 
 5341const char *bad_resources[] = {
 
 5353static int test_new_subscribe(
struct ast_sip_endpoint *endpoint, 
const char *resource)
 
 5357    for (i = 0; i < 
ARRAY_LEN(bad_resources); ++i) {
 
 5358        if (!strcmp(resource, bad_resources[i])) {
 
 5382    .notifier = &test_notifier,
 
 5401    for (i = 0; i < num_resources; ++i) {
 
 5415static void cleanup_resource_list(
struct resource_list *list)
 
 5437        const char *list_name, 
const char *
event, 
const char **
resources, 
size_t num_resources)
 
 5455        cleanup_resource_list(list);
 
 5476        const char **
resources, 
size_t num_resources)
 
 5486    for (i = 0; i < num_resources; ++i) {
 
 5500static void test_resource_tree_destroy(
struct resource_tree *tree)
 
 5506static int ineligible_configuration(
void)
 
 5523    if (strcasecmp(
value, 
"memory") && strcasecmp(
value, 
"astdb")) {
 
 5544        info->name = 
"resource_tree";
 
 5545        info->category = 
"/res/res_pjsip_pubsub/";
 
 5546        info->summary = 
"Basic resource tree integrity check";
 
 5548            "Create a resource list and ensure that our attempt to build a tree works as expected.";
 
 5554    if (ineligible_configuration()) {
 
 5556                "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
 
 5589    const char *resources_1[] = {
 
 5595    const char *resources_2[] = {
 
 5609        info->name = 
"complex_resource_tree";
 
 5610        info->category = 
"/res/res_pjsip_pubsub/";
 
 5611        info->summary = 
"Complex resource tree integrity check";
 
 5613            "Create a complex resource list and ensure that our attempt to build a tree works as expected.";
 
 5619    if (ineligible_configuration()) {
 
 5621                "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
 
 5625    list_1 = create_resource_list(
test, 
"foo", 
"test", resources_1, 
ARRAY_LEN(resources_1));
 
 5630    list_2 = create_resource_list(
test, 
"dwarves", 
"test", resources_2, 
ARRAY_LEN(resources_2));
 
 5675        info->name = 
"bad_resource";
 
 5676        info->category = 
"/res/res_pjsip_pubsub/";
 
 5677        info->summary = 
"Ensure bad resources do not end up in the tree";
 
 5679            "Create a resource list with a single bad resource. Ensure the bad resource does not end up in the tree.";
 
 5685    if (ineligible_configuration()) {
 
 5687                "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
 
 5722    const char *resources_1[] = {
 
 5729    const char *resources_2[] = {
 
 5739        info->name = 
"bad_branch";
 
 5740        info->category = 
"/res/res_pjsip_pubsub/";
 
 5741        info->summary = 
"Ensure bad branches are pruned from the tree";
 
 5743            "Create a resource list that makes a tree with an entire branch of bad resources.\n" 
 5744            "Ensure the bad branch is pruned from the tree.";
 
 5750    if (ineligible_configuration()) {
 
 5752                "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
 
 5756    list_1 = create_resource_list(
test, 
"foo", 
"test", resources_1, 
ARRAY_LEN(resources_1));
 
 5760    list_2 = create_resource_list(
test, 
"gross", 
"test", resources_2, 
ARRAY_LEN(resources_2));
 
 5780    if (check_node(
test, tree->root, resources_1, 
ARRAY_LEN(resources_1) - 1)) {
 
 5793    const char *resources_1[] = {
 
 5799    const char *resources_2[] = {
 
 5812        info->name = 
"duplicate_resource";
 
 5813        info->category = 
"/res/res_pjsip_pubsub/";
 
 5814        info->summary = 
"Ensure duplicated resources do not end up in the tree";
 
 5816            "Create a resource list with a single duplicated resource. Ensure the duplicated resource does not end up in the tree.";
 
 5822    if (ineligible_configuration()) {
 
 5824                "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
 
 5828    list_1 = create_resource_list(
test, 
"foo", 
"test", resources_1, 
ARRAY_LEN(resources_1));
 
 5833    list_2 = create_resource_list(
test, 
"ducks", 
"test", resources_2, 
ARRAY_LEN(resources_2));
 
 5874    const char *resources_1[] = {
 
 5877    const char *resources_2[] = {
 
 5884        info->name = 
"loop";
 
 5885        info->category = 
"/res/res_pjsip_pubsub/";
 
 5886        info->summary = 
"Test that loops are properly detected.";
 
 5888            "Create two resource lists that refer to each other. Ensure that attempting to build a tree\n" 
 5889            "results in an empty tree.";
 
 5895    if (ineligible_configuration()) {
 
 5897                "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
 
 5901    list_1 = create_resource_list(
test, 
"herp", 
"test", resources_1, 
ARRAY_LEN(resources_1));
 
 5905    list_2 = create_resource_list(
test, 
"derp", 
"test", resources_2, 
ARRAY_LEN(resources_2));
 
 5933        info->name = 
"bad_event";
 
 5934        info->category = 
"/res/res_pjsip_pubsub/";
 
 5935        info->summary = 
"Ensure that list with wrong event specified is not retrieved";
 
 5937            "Create a simple resource list for event 'tsetse'. Ensure that trying to retrieve the list for event 'test' fails.";
 
 5943    if (ineligible_configuration()) {
 
 5945                "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
 
 5969    if (strcmp(tree->root->resource, 
"foo")) {
 
 5993    const char *
event = 
var->name + 6;
 
 
 6015    static const pj_str_t str_PUBLISH = { 
"PUBLISH", 7 };
 
 6021        ast_log(
LOG_ERROR, 
"Could not create scheduler for publication expiration\n");
 
 6026        ast_log(
LOG_ERROR, 
"Could not start scheduler thread for publication expiration\n");
 
 6035        ast_log(
LOG_ERROR, 
"Could not register subscription persistence object support\n");
 
 6074        ast_log(
LOG_ERROR, 
"Could not register subscription persistence object support\n");
 
 
 6166    .
requires = 
"res_pjsip",
 
void ast_cli_unregister_multiple(void)
static struct ast_generator gen
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
int ast_shutdown_final(void)
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
#define ast_strdup(str)
A wrapper for strdup()
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
#define ast_calloc(num, len)
A wrapper for calloc()
#define ast_malloc(len)
A wrapper for malloc()
#define ao2_link(container, obj)
Add an object to a container.
@ AO2_ALLOC_OPT_LOCK_MUTEX
#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_unlink(container, obj)
Remove an object from a container.
#define ao2_find(container, arg, flags)
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the 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.
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
static void destroy_subscriptions(void)
Destroy the active Stasis subscriptions.
static const char config[]
#define AST_MAX_EXTENSION
Standard Command Line Interface.
#define AST_CLI_DEFINE(fn, txt,...)
void ast_cli(int fd, const char *fmt,...)
#define ast_cli_register_multiple(e, len)
Register multiple commands.
static struct ast_cli_entry cli[]
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define CHARFLDSET(type, field)
A helper macro to pass the appropriate arguments to aco_option_register for OPT_CHAR_ARRAY_T.
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ OPT_NOOP_T
Type for a default handler that should do nothing.
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_CHAR_ARRAY_T
Type for default option handler for character array strings.
@ OPT_YESNO_T
Type for default option handler for bools (ast_true/ast_false)
Asterisk datastore objects.
void ast_datastores_remove(struct ao2_container *datastores, const char *name)
Remove a data store from a container.
struct ao2_container * ast_datastores_alloc(void)
Allocate a specialized data stores container.
int ast_datastores_add(struct ao2_container *datastores, struct ast_datastore *datastore)
Add a data store to a container.
struct ast_datastore * ast_datastores_find(struct ao2_container *datastores, const char *name)
Find a data store in a container.
struct ast_datastore * ast_datastores_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Allocate a datastore for use with the datastores container.
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
void astman_append(struct mansession *s, const char *fmt,...)
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
struct ast_taskprocessor * ast_sip_get_distributor_serializer(pjsip_rx_data *rdata)
Determine the distributor serializer for the SIP message.
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
struct ast_sip_sched_task * ast_sip_schedule_task(struct ast_taskprocessor *serializer, int interval, ast_sip_task sip_task, const char *name, void *task_data, enum ast_sip_scheduler_task_flags flags)
Schedule a task to run in the res_pjsip thread pool.
void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
Set an endpoint on a SIP dialog so in-dialog requests do not undergo endpoint lookup.
int ast_sip_sched_task_cancel(struct ast_sip_sched_task *schtd)
Cancels the next invocation of a task.
int ast_sip_sched_task_get_name(struct ast_sip_sched_task *schtd, char *name, size_t maxlen)
Gets the task name.
void ast_sip_dialog_set_serializer(pjsip_dialog *dlg, struct ast_taskprocessor *serializer)
Set a serializer on a SIP dialog so requests and responses are automatically serialized.
int ast_sip_push_task_wait_servant(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
int ast_sip_push_task_wait_serializer(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to the serializer and wait for it to complete.
@ AST_SIP_SCHED_TASK_FIXED
@ AST_SIP_SCHED_TASK_DATA_AO2
#define ast_config_load(filename, flags)
Load a config file.
#define ast_variable_new(name, value, filename)
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
#define ast_debug(level,...)
Log a DEBUG message.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
void ast_json_free(void *p)
Asterisk's custom JSON allocator. Exposed for use by unit tests.
struct ast_json * ast_json_object_create(void)
Create a new JSON object.
#define ast_json_dump_string(root)
Encode a JSON value to a compact string.
struct ast_json * ast_json_load_string(const char *input, struct ast_json_error *error)
Parse null terminated string into a JSON object or array.
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
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.
A set of macros to manage forward-linked lists.
#define AST_RWLIST_REMOVE_CURRENT
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_RWLIST_TRAVERSE_SAFE_END
#define AST_RWLIST_TRAVERSE
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
#define AST_RWLIST_INSERT_TAIL
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define EVENT_FLAG_SYSTEM
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
struct stasis_message_type * ast_manager_get_generic_type(void)
Get the stasis_message_type for generic messages.
Asterisk module definitions.
@ AST_MODFLAG_GLOBAL_SYMBOLS
#define ast_module_unref(mod)
Release a reference to the module.
#define ast_module_ref(mod)
Hold a reference to the module.
#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.
#define ast_publish_mwi_state(mailbox, context, new_msgs, old_msgs)
Publish a MWI state update via stasis.
static struct ast_sorcery * sorcery
static struct stasis_subscription * sub
Statsd channel stats. Exmaple of how to subscribe to Stasis events.
int ast_sip_will_uri_survive_restart(pjsip_sip_uri *uri, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
const pj_str_t * ast_sip_pjsip_uri_get_username(pjsip_uri *uri)
Get the user portion of the pjsip_uri.
void ast_sip_unregister_service(pjsip_module *module)
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.
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
pjsip_dialog * ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, const char *aor_name, const char *request_user)
General purpose method for creating a UAC dialog with an endpoint.
enum ast_transport_monitor_reg ast_sip_transport_monitor_register_key(const char *transport_key, ast_transport_monitor_shutdown_cb cb, void *ao2_data)
Register a reliable transport shutdown monitor callback.
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
#define AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(_transport, _dest)
Fill a buffer with a pjsip transport's remote ip address and port.
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
struct ast_sip_endpoint * ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
Get the looked-up endpoint on an out-of dialog request or response.
int ast_sip_is_uri_sip_sips(pjsip_uri *uri)
Check whether a pjsip_uri is SIP/SIPS or not.
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a transport shutdown monitor from all reliable transports.
pjsip_dialog * ast_sip_create_dialog_uas_locked(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status)
General purpose method for creating a UAS dialog with an endpoint.
#define ast_sip_mod_data_set(pool, mod_data, id, key, val)
Utilizing a mod_data array for a given id, set the value associated with the given key.
#define IP6ADDR_COLON_PORT_BUFLEN
#define ast_sip_mod_data_get(mod_data, id, key)
Using the dictionary stored in mod_data array at a given id, retrieve the value associated with the g...
int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
Converts a sorcery object to a string of object properties.
struct ast_str * ast_sip_create_ami_event(const char *event, struct ast_sip_ami *ami)
Creates a string to store AMI event data in.
#define PJSIP_EXPIRES_NOT_SPECIFIED
int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
Add a header to an outbound SIP message.
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
int ast_sip_is_content_type(pjsip_media_type *content_type, char *type, char *subtype)
Checks if the given content type matches type/subtype.
void ast_sip_transport_monitor_unregister_key(const char *transport_key, ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a reliable transport shutdown monitor.
int ast_sip_create_rdata_with_contact(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port, char *transport_type, const char *local_name, int local_port, const char *contact_uri)
General purpose method for creating an rdata structure using specific information.
void ast_sip_sanitize_xml(const char *input, char *output, size_t len)
Replace offensive XML characters with XML entities.
#define AST_PJSIP_XML_PROLOG_LEN
Length of the XML prolog when printing presence or other XML in PJSIP.
pj_xml_node * ast_sip_presence_xml_create_node(pj_pool_t *pool, pj_xml_node *parent, const char *name)
Create XML node.
pj_xml_attr * ast_sip_presence_xml_create_attr(pj_pool_t *pool, pj_xml_node *node, const char *name, const char *value)
Create XML attribute.
#define CLI_SHOW_SUB_FORMAT_ENTRY
static void subscription_tree_destructor(void *obj)
static int cli_show_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
struct ast_sip_endpoint * ast_sip_subscription_get_endpoint(struct ast_sip_subscription *sub)
Get the endpoint that is associated with this subscription.
int(* on_subscription_t)(struct sip_subscription_tree *sub, void *arg)
void ast_sip_subscription_get_remote_uri(struct ast_sip_subscription *sub, char *buf, size_t size)
Retrive the remote URI for this subscription.
static int subscription_persistence_recreate(void *obj, void *arg, int flags)
Callback function to perform the actual recreation of a subscription.
static int subscription_persistence_load(void *data)
Function which loads and recreates persisted subscriptions upon startup when the system is fully boot...
static struct subscription_persistence * subscription_persistence_create(struct sip_subscription_tree *sub_tree)
Function which creates initial persistence information of a subscription in sorcery.
int ast_sip_register_publish_handler(struct ast_sip_publish_handler *handler)
Register a publish handler.
static struct sip_subscription_tree * create_subscription_tree(const struct ast_sip_subscription_handler *handler, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource, struct ast_sip_pubsub_body_generator *generator, struct resource_tree *tree, pj_status_t *dlg_status, struct subscription_persistence *persistence)
Create a subscription tree based on a resource tree.
static int cli_show_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg)
static int cli_complete_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_complete_parms *cli)
void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler *handler)
Unregister a subscription handler.
static pjsip_generic_string_hdr * generate_content_id_hdr(pj_pool_t *pool, const struct ast_sip_subscription *sub)
Create a Content-ID header.
static struct ast_cli_entry cli_commands[]
const char * ast_sip_subscription_get_body_type(struct ast_sip_subscription *sub)
Get the body type used for this subscription.
static int generate_initial_notify(struct ast_sip_subscription *sub)
static int allocate_tdata_buffer(pjsip_tx_data *tdata)
Pre-allocate a buffer for the transmission.
static int sip_publication_respond(struct ast_sip_publication *pub, int status_code, pjsip_rx_data *rdata)
static struct ast_sip_subscription_handler * find_sub_handler_for_event_name(const char *event_name)
static int ami_show_resource_lists(struct mansession *s, const struct message *m)
void ast_sip_pubsub_unregister_body_generator(struct ast_sip_pubsub_body_generator *generator)
Unregister a body generator with the pubsub core.
static unsigned int cli_subscription_expiry(struct sip_subscription_tree *sub_tree)
int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *handler)
Register a subscription handler.
static void pubsub_on_client_refresh(pjsip_evsub *sub)
static int publication_hash_fn(const void *obj, const int flags)
static int resource_list_apply_handler(const struct ast_sorcery *sorcery, void *obj)
void ast_sip_pubsub_unregister_body_supplement(struct ast_sip_pubsub_body_supplement *supplement)
Unregister a body generator with the pubsub core.
static int sub_tree_subscription_terminate_cb(void *data)
#define CLI_SHOW_SUB_FORMAT_HEADER
static void build_body_part(pj_pool_t *pool, struct ast_sip_subscription *sub, struct body_part_list *parts, unsigned int use_full_state)
Create a multipart body part for a subscribed resource.
static int build_resource_tree(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler, const char *resource, struct resource_tree *tree, int has_eventlist_support, pjsip_rx_data *rdata)
Build a resource tree.
static int schedule_notification(struct sip_subscription_tree *sub_tree)
static int pubsub_on_refresh_timeout(void *userdata)
static int publication_cmp_fn(void *obj, void *arg, int flags)
static struct ast_sched_context * sched
Scheduler used for automatically expiring publications.
sip_persistence_update_type
@ SUBSCRIPTION_PERSISTENCE_CREATED
@ SUBSCRIPTION_PERSISTENCE_SEND_REQUEST
@ SUBSCRIPTION_PERSISTENCE_REFRESHED
@ SUBSCRIPTION_PERSISTENCE_RECREATED
static int exceptional_accept(const pj_str_t *accept)
Is the Accept header from the SUBSCRIBE in the list of exceptions?
static void pubsub_on_server_timeout(pjsip_evsub *sub)
sip_subscription_tree_state
The state of the subscription tree.
@ SIP_SUB_TREE_TERMINATE_PENDING
@ SIP_SUB_TREE_TERMINATED
@ SIP_SUB_TREE_TERMINATE_IN_PROGRESS
static int resource_event_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int cli_complete_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg)
void ast_sip_subscription_destroy(struct ast_sip_subscription *sub)
Alert the pubsub core that the subscription is ready for destruction.
static int serialized_pubsub_on_refresh_timeout(void *userdata)
void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name)
Remove a subscription datastore from the subscription.
static int serialized_send_notify(void *userdata)
static void clean_sub_tree(pjsip_evsub *evsub)
Callback sequence for subscription terminate:
sip_publish_type
The types of PUBLISH messages defined in RFC 3903.
@ SIP_PUBLISH_REMOVE
Remove.
@ SIP_PUBLISH_REFRESH
Refresh.
@ SIP_PUBLISH_UNKNOWN
Unknown.
@ SIP_PUBLISH_MODIFY
Modify.
@ SIP_PUBLISH_INITIAL
Initial.
static void * subscription_persistence_alloc(const char *name)
Allocator for subscription persistence.
static int serialized_pubsub_on_client_refresh(void *userdata)
static int sub_persistence_recreate(void *obj)
const struct ast_json * ast_sip_subscription_get_persistence_data(const struct ast_sip_subscription *subscription)
Retrieve persistence data for a subscription.
#define MAX_REGEX_ERROR_LEN
static int cli_list_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
static int esc_etag_counter
static char * cli_complete_subscription_callid(struct ast_cli_args *a)
static struct ast_sip_subscription * create_virtual_subscriptions(const struct ast_sip_subscription_handler *handler, const char *resource, struct ast_sip_pubsub_body_generator *generator, struct sip_subscription_tree *tree, struct tree_node *current)
Create a tree of virtual subscriptions based on a resource tree node.
struct ast_datastore * ast_sip_subscription_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Alternative for ast_datastore_alloc()
static const pj_str_t str_event_name
static int format_ami_resource_lists(void *obj, void *arg, int flags)
#define DEFAULT_PUBLISH_EXPIRES
Default expiration time for PUBLISH if one is not specified.
static pj_bool_t pubsub_on_rx_publish_request(pjsip_rx_data *rdata)
static void shutdown_subscriptions(struct ast_sip_subscription *sub)
static void * rlmi_clone_data(pj_pool_t *pool, const void *data, unsigned len)
static int ami_show_subscriptions_outbound(struct mansession *s, const struct message *m)
static int cli_show_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg)
static void remove_subscription(struct sip_subscription_tree *obj)
static int persistence_endpoint_struct2str(const void *obj, const intptr_t *args, char **buf)
struct ast_taskprocessor * ast_sip_subscription_get_serializer(struct ast_sip_subscription *sub)
Get the serializer for the subscription.
static pjsip_require_hdr * create_require_eventlist(pj_pool_t *pool)
Shortcut method to create a Require: eventlist header.
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_pubsub_register_body_supplement(struct ast_sip_pubsub_body_supplement *supplement)
Register a body generator with the pubsub core.
void ast_sip_publication_remove_datastore(struct ast_sip_publication *publication, const char *name)
Remove a publication datastore from the publication.
static void * publication_resource_alloc(const char *name)
Allocator for publication resource.
static int resource_endpoint_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
void ast_sip_unregister_publish_handler(struct ast_sip_publish_handler *handler)
Unregister a publish handler.
static int cli_show_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg)
static int ami_show_subscriptions_inbound(struct mansession *s, const struct message *m)
static int cli_list_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg)
int ast_sip_subscription_add_datastore(struct ast_sip_subscription *subscription, struct ast_datastore *datastore)
Add a datastore to a SIP subscription.
static int parse_simple_message_summary(char *body, struct simple_message_summary *summary)
static struct ast_sip_pubsub_body_generator * subscription_get_generator_from_rdata(pjsip_rx_data *rdata, const struct ast_sip_subscription_handler *handler)
Retrieve a body generator using the Accept header of an rdata message.
static char * sub_tree_state_description[]
#define AMI_SHOW_SUBSCRIPTIONS_INBOUND
#define NEW_SUBSCRIBE(notifier, endpoint, resource, rdata)
const char * ast_sip_subscription_get_body_subtype(struct ast_sip_subscription *sub)
Get the body subtype used for this subscription.
#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND
const char * ast_sip_subscription_get_resource_name(struct ast_sip_subscription *sub)
Get the name of the subscribed resource.
static int rlmi_print_body(struct pjsip_msg_body *msg_body, char *buf, pj_size_t size)
static struct ast_sip_subscription * allocate_subscription(const struct ast_sip_subscription_handler *handler, const char *resource, const char *display_name, struct sip_subscription_tree *tree)
#define PUBLICATIONS_BUCKETS
Number of buckets for publications (on a per handler)
static int have_visited(const char *resource, struct resources *visited)
Determine if this resource has been visited already.
static pjsip_evsub_user pubsub_cb
static int sched_cb(const void *data)
#define RESOURCE_LIST_INIT_SIZE
static struct pjsip_module pubsub_module
static void sub_add_handler(struct ast_sip_subscription_handler *handler)
pjsip_sip_uri * ast_sip_subscription_get_sip_uri(struct ast_sip_subscription *sub)
Retrieve the local sip uri for this subscription.
void ast_sip_subscription_set_persistence_data(struct ast_sip_subscription *subscription, struct ast_json *persistence_data)
Set persistence data for a subscription.
static char * cli_show_subscriptions_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
const char * ast_sip_publication_get_event_configuration(const struct ast_sip_publication *pub)
Given a publication, get the configuration name for the event type in use.
static pjsip_msg_body * generate_list_body(pj_pool_t *pool, struct ast_sip_subscription *sub, unsigned int force_full_state)
Create a resource list body for NOTIFY requests.
static int cli_show_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg)
static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state)
Send a NOTIFY request to a subscriber.
int ast_sip_pubsub_register_body_generator(struct ast_sip_pubsub_body_generator *generator)
Register a body generator with the pubsub core.
static void build_node_children(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler, struct resource_list *list, struct tree_node *parent, struct resources *visited, pjsip_rx_data *rdata)
Build child nodes for a given parent.
static int persistence_generator_data_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
static pj_bool_t pubsub_on_rx_request(pjsip_rx_data *rdata)
Opaque structure representing an RFC 3265 SIP subscription.
static void add_subscription(struct sip_subscription_tree *obj)
static void pubsub_on_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
Called whenever an in-dialog SUBSCRIBE is received.
static void free_body_parts(struct body_part_list *parts)
Destroy a list of body parts.
static int subscription_unreference_dialog(void *obj)
static struct ast_sip_pubsub_body_generator * find_body_generator_type_subtype_nolock(const char *type, const char *subtype)
static int ami_subscription_detail_inbound(struct sip_subscription_tree *sub_tree, void *arg)
static int publish_expire(const void *data)
static int persistence_expires_struct2str(const void *obj, const intptr_t *args, char **buf)
static pjsip_msg_body * create_multipart_body(pj_pool_t *pool)
Create and initialize the PJSIP multipart body structure for a resource list subscription.
static int ami_subscription_detail(struct sip_subscription_tree *sub_tree, struct ast_sip_ami *ami, const char *event)
static pj_bool_t pubsub_on_rx_mwi_notify_request(pjsip_rx_data *rdata)
static int apply_list_configuration(struct ast_sorcery *sorcery)
static void pubsub_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
PJSIP callback when underlying SIP subscription changes state.
pjsip_dialog * ast_sip_subscription_get_dialog(struct ast_sip_subscription *sub)
Get the pjsip dialog that is associated with this subscription.
static int list_item_to_str(const void *obj, const intptr_t *args, char **buf)
static int list_item_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int persistence_endpoint_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
int ast_sip_pubsub_generate_body_content(const char *type, const char *subtype, struct ast_sip_body_data *data, struct ast_str **str)
Generate body content for a PUBLISH or NOTIFY.
static struct ast_sip_pubsub_body_generator * find_body_generator(char accept[AST_SIP_MAX_ACCEPT][64], size_t num_accept, const char *body_type)
static int ast_sip_pubsub_has_eventlist_support(pjsip_rx_data *rdata)
Check if the rdata has a Supported header containing 'eventlist'.
static struct ast_sip_publish_handler * find_pub_handler(const char *event)
static void tree_node_destroy(struct tree_node *node)
Destructor for a tree node.
static int persistence_tag_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
struct ast_datastore * ast_sip_publication_get_datastore(struct ast_sip_publication *publication, const char *name)
Retrieve a publication datastore.
static void subscription_persistence_remove(struct sip_subscription_tree *sub_tree)
Function which removes persistence of a subscription from sorcery.
static int persistence_expires_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int publish_expire_callback(void *data)
static void resource_list_destructor(void *obj)
static int cmp_strings(char *s1, char *s2)
Compare strings for equality checking for NULL.
static void subscription_persistence_update(struct sip_subscription_tree *sub_tree, pjsip_rx_data *rdata, enum sip_persistence_update_type type)
Function which updates persistence information of a subscription in sorcery.
struct ast_sip_endpoint * ast_sip_publication_get_endpoint(struct ast_sip_publication *pub)
Given a publication, get the associated endpoint.
static pj_bool_t pubsub_on_rx_notify_request(pjsip_rx_data *rdata)
static int item_in_vector(const struct resource_list *list, const char *item)
static void destroy_subscription(struct ast_sip_subscription *sub)
static pjsip_msg_body * generate_notify_body(pj_pool_t *pool, struct ast_sip_subscription *root, unsigned int force_full_state)
Create the body for a NOTIFY request.
#define CLI_LIST_SUB_FORMAT_HEADER
static void sub_tree_transport_cb(void *data)
int ast_sip_pubsub_is_body_generator_registered(const char *type, const char *subtype)
Is a body generator registered for the given type/subtype.
static int load_module(void)
static int persistence_tag_struct2str(const void *obj, const intptr_t *args, char **buf)
static void subscription_persistence_event_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Event callback which fires subscription persistence recreation when the system is fully booted.
static int for_each_subscription(on_subscription_t on_subscription, void *arg)
static void add_rlmi_resource(pj_pool_t *pool, pj_xml_node *rlmi, const pjsip_generic_string_hdr *cid, const char *resource_name, const pjsip_sip_uri *resource_uri, pjsip_evsub_state state)
Add a resource XML element to an RLMI body.
static void pubsub_on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
static void resource_tree_destroy(struct resource_tree *tree)
Destroy a resource tree.
static int initial_notify_task(void *obj)
static void subscription_setup_dialog(struct sip_subscription_tree *sub_tree, pjsip_dialog *dlg)
static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
static int sip_subscription_accept(struct sip_subscription_tree *sub_tree, pjsip_rx_data *rdata, int response)
static int cli_show_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
static struct ast_sip_pubsub_body_generator * find_body_generator_accept(const char *accept)
static int unload_module(void)
static void * resource_list_alloc(const char *name)
static int cmp_subscription_childrens(struct ast_sip_subscription *s1, struct ast_sip_subscription *s2)
compares the childrens of two ast_sip_subscription s1 and s2
static int persistence_generator_data_struct2str(const void *obj, const intptr_t *args, char **buf)
static char * cli_list_subscriptions_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void publication_resource_destroy(void *obj)
Destructor for publication resource.
static struct ast_sip_pubsub_body_generator * find_body_generator_type_subtype(const char *type, const char *subtype)
static enum sip_publish_type determine_sip_publish_type(pjsip_rx_data *rdata, pjsip_generic_string_hdr *etag_hdr, unsigned int *expires, int *entity_id)
static char * cli_show_subscription_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
const pjsip_method pjsip_publish_method
Defined method for PUBLISH.
static void set_state_terminated(struct ast_sip_subscription *sub)
#define MOD_DATA_PERSISTENCE
const char * ast_sip_publication_get_resource(const struct ast_sip_publication *pub)
Given a publication, get the resource the publication is to.
struct ao2_container * ast_sip_publication_get_datastores(const struct ast_sip_publication *publication)
Get the datastores container for a publication.
static int cli_list_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg)
static void publish_add_handler(struct ast_sip_publish_handler *handler)
static struct ast_sip_publication * publish_request_initial(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, struct ast_sip_publish_handler *handler)
static int ami_subscription_detail_outbound(struct sip_subscription_tree *sub_tree, void *arg)
static void sip_subscription_to_ami(struct sip_subscription_tree *sub_tree, struct ast_str **buf)
struct ast_sip_subscription * ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler, struct ast_sip_endpoint *endpoint, const char *resource)
Create a new ast_sip_subscription structure.
static struct tree_node * tree_node_alloc(const char *resource, struct resources *visited, unsigned int full_state, const char *display_name)
Allocate a tree node.
#define CLI_LIST_SUB_FORMAT_ENTRY
static int sip_subscription_send_request(struct sip_subscription_tree *sub_tree, pjsip_tx_data *tdata)
static pjsip_media_type rlmi_media_type
static void subscription_persistence_destroy(void *obj)
Destructor for subscription persistence.
int ast_sip_subscription_is_terminated(const struct ast_sip_subscription *sub)
Get whether the subscription has been terminated or not.
static pjsip_multipart_part * build_rlmi_body(pj_pool_t *pool, struct ast_sip_subscription *sub, struct body_part_list *body_parts, unsigned int full_state)
Create an RLMI body part for a multipart resource list body.
void ast_sip_subscription_get_local_uri(struct ast_sip_subscription *sub, char *buf, size_t size)
Retrieve the local URI for this subscription.
static int cli_complete_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg)
void * ast_sip_subscription_get_header(const struct ast_sip_subscription *sub, const char *header)
Get a header value for a subscription.
int ast_sip_publication_add_datastore(struct ast_sip_publication *publication, struct ast_datastore *datastore)
Add a datastore to a SIP publication.
static const char * sip_subscription_roles_map[]
static struct body_part * allocate_body_part(pj_pool_t *pool, const struct ast_sip_subscription *sub)
Allocate and initialize a body part structure.
static struct ast_sip_publication * sip_create_publication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource, const char *event_configuration_name)
static struct resource_list * retrieve_resource_list(const char *resource, const char *event)
Helper function for retrieving a resource list for a given event.
const char * accept_exceptions[]
Accept headers that are exceptions to the rule.
static void publication_destroy_fn(void *obj)
Internal destructor for publications.
static struct sip_subscription_tree * allocate_subscription_tree(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
static struct ast_sip_subscription_handler * subscription_get_handler_from_rdata(pjsip_rx_data *rdata, const char *endpoint)
Retrieve a handler using the Event header of an rdata message.
#define DEFAULT_EXPIRES
Default expiration for subscriptions.
static int destroy_subscriptions_task(void *obj)
struct ao2_container * ast_sip_subscription_get_datastores(const struct ast_sip_subscription *subscription)
Get the datastores container for a subscription.
struct ast_datastore * ast_sip_subscription_get_datastore(struct ast_sip_subscription *subscription, const char *name)
Retrieve a subscription datastore.
@ AST_SIP_PUBLISH_STATE_ACTIVE
@ AST_SIP_PUBLISH_STATE_TERMINATED
@ AST_SIP_PUBLISH_STATE_INITIALIZED
#define AST_SIP_MAX_ACCEPT
#define AST_SIP_DEVICE_FEATURE_SYNC_DATA
ast_sip_subscription_role
Role for the subscription that is being created.
Scheduler Routines (derived from cheops)
#define AST_SCHED_DEL_UNREF(sched, id, refcall)
schedule task to get deleted and call unref function
#define AST_SCHED_REPLACE_UNREF(id, sched, when, callback, data, unrefcall, addfailcall, refcall)
int ast_sched_add(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result
Adds a scheduled event.
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
int ast_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *type, const char *regex, aco_option_handler config_handler, sorcery_fields_handler sorcery_handler)
Register a regex for multiple fields within an object.
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
Create and potentially persist an object using an available wizard.
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 ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
#define ast_sorcery_object_field_register_custom(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags,...)
Register a field within an object with custom handlers.
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
#define ast_sorcery_apply_config(sorcery, name)
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
Update an object.
#define ast_sorcery_apply_default(sorcery, type, name, data)
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.
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
@ 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.
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
static force_inline char * ast_str_to_lower(char *str)
Convert a string to all lower-case.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
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.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
char * ast_read_line_from_buffer(char **buffer)
Read lines from a string buffer.
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
char * ast_generate_random_string(char *buf, size_t size)
Create a pseudo-random string of a fixed length.
int ast_get_timeval(const char *src, struct timeval *tv, struct timeval _default, int *consumed)
Parse a time (float) string.
descriptor for a cli entry.
Structure for a data store type.
Structure for a data store object.
const struct ast_datastore_info * info
Structure used to handle boolean flags.
JSON parsing error information.
Abstract JSON element (object, array, string, int, ...).
struct ast_party_name name
Subscriber name.
struct ast_party_number number
Subscriber phone number.
unsigned char valid
TRUE if the name information is valid/present.
char * str
Subscriber name (Malloced)
unsigned char valid
TRUE if the number information is valid/present.
char * str
Subscriber phone number (Malloced)
Data used to create bodies for NOTIFY/PUBLISH requests.
Party identification options for endpoints.
An entity with which Asterisk communicates.
struct ast_sip_endpoint_id_configuration id
const ast_string_field aors
int(* new_subscribe)(struct ast_sip_endpoint *endpoint, const char *resource)
Called when a SUBSCRIBE arrives attempting to establish a new subscription.
int(* refresh_subscribe)(struct ast_sip_subscription *sub, pjsip_rx_data *rdata)
Called when a SUBSCRIBE arrives for an already active subscription.
int(* notify_created)(struct ast_sip_subscription *sub, pjsip_tx_data *tdata)
Optional callback to execute before sending outgoing NOTIFY requests. Because res_pjsip_pubsub create...
Structure representing a publication resource.
SORCERY_OBJECT(details)
Sorcery object details.
char * endpoint
Optional name of an endpoint that is only allowed to publish to this resource.
struct ast_variable * events
Mapping for event types to configuration.
Structure representing a SIP publication.
unsigned int expires
Expiration time of the publication.
struct ast_sip_publish_handler * handler
Handler for this publication.
struct ast_sip_endpoint * endpoint
The endpoint with which the subscription is communicating.
int sched_id
Scheduled item for expiration of publication.
char * event_configuration_name
The name of the event type configuration.
char data[0]
Data containing the above.
struct ao2_container * datastores
char * resource
The resource the publication is to.
int entity_tag
Entity tag for the publication.
Callbacks that publication handlers will define.
struct ast_sip_publish_handler * next
struct ao2_container * publications
Publications.
const char * event_name
The name of the event this handler deals with.
int(* publication_state_change)(struct ast_sip_publication *pub, pjsip_msg_body *body, enum ast_sip_publish_state state)
Published resource has changed states.
void(* to_string)(void *body, struct ast_str **str)
Convert the body to a string.
struct ast_sip_pubsub_body_generator::@280 list
void(* destroy_body)(void *body)
Deallocate resources created for the body.
const char * type
Content type In "plain/text", "plain" is the type.
const char * subtype
Content subtype In "plain/text", "text" is the subtype.
void *(* allocate_body)(void *data)
allocate body structure.
int(* generate_body_content)(void *body, void *data)
Add content to the body of a SIP request.
int(* supplement_body)(void *body, void *data)
Add additional content to a SIP request body.
const char * type
Content type In "plain/text", "plain" is the type.
struct ast_sip_pubsub_body_supplement::@281 list
const char * subtype
Content subtype In "plain/text", "text" is the subtype.
struct ast_sip_notifier * notifier
void(* to_ami)(struct ast_sip_subscription *sub, struct ast_str **buf)
Converts the subscriber to AMI.
struct ast_sip_subscription_handler * next
const char * accept[AST_SIP_MAX_ACCEPT]
Structure representing a "virtual" SIP subscription.
struct ast_sip_subscription::@501 children
struct sip_subscription_tree * tree
struct ast_sip_pubsub_body_generator * body_generator
const struct ast_sip_subscription_handler * handler
struct ast_json * persistence_data
struct ast_str * body_text
struct ao2_container * datastores
pjsip_evsub_state subscription_state
Full structure for sorcery.
Support for dynamic strings.
A ast_taskprocessor structure is a singleton by name.
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Type declaration for container of body part structures.
A multipart body part and meta-information.
const char * display_name
pjsip_generic_string_hdr * cid
pjsip_multipart_part * part
struct sip_subscription_tree * sub_tree
In case you didn't read that giant block of text above the mansession_session struct,...
struct subscription_persistence * persistence
Resource list configuration item.
unsigned int notification_batch_interval
unsigned int resource_display_name
unsigned int notification_batch_interval
A vector of strings commonly used throughout this module.
struct sched_id * sched_id
int voice_messages_urgent_old
char message_account[PJSIP_MAX_URL_SIZE]
int voice_messages_urgent_new
A tree of SIP subscriptions.
struct subscription_persistence * persistence
struct ast_sip_endpoint * endpoint
char transport_key[IP6ADDR_COLON_PORT_BUFLEN]
enum ast_sip_subscription_role role
struct sip_subscription_tree * next
unsigned int send_scheduled_notify
enum sip_subscription_tree_state state
unsigned int generate_initial_notify
struct ast_sip_subscription * root
struct ast_taskprocessor * serializer
unsigned int notification_batch_interval
struct ast_sip_sched_task * expiration_task
Structure used for persisting an inbound subscription.
struct ast_json * generator_data
char src_name[PJ_INET6_ADDRSTRLEN]
char contact_uri[PJSIP_MAX_URL_SIZE]
char packet[PJSIP_MAX_PKT_LEN]
char local_name[PJ_INET6_ADDRSTRLEN]
A node for a resource tree.
struct tree_node::@502 children
structure to hold users read from phoneprov_users.conf
An API for managing task processing threads that can be shared across modules.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
#define AST_TEST_REGISTER(cb)
#define ast_test_status_update(a, b, c...)
#define AST_TEST_UNREGISTER(cb)
#define ast_test_suite_event_notify(s, f,...)
#define AST_TEST_DEFINE(hdr)
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
static struct aco_type item
static void test_handler(void *data, const char *app_name, struct ast_json *message)
int ast_time_t_to_string(time_t time, char *buf, size_t length)
Converts to a string representation of a time_t as decimal seconds since the epoch....
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
int error(const char *format,...)
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Universally unique identifier support.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
#define AST_VECTOR(name, type)
Define a vector structure.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.