static pjsip_sub_state_hdr* pjsip_sub_state_hdr_clone(pj_pool_t *pool, const pjsip_sub_state_hdr *rhs) { pjsip_sub_state_hdr *hdr = pjsip_sub_state_hdr_create(pool); pj_strdup(pool, &hdr->sub_state, &rhs->sub_state); pj_strdup(pool, &hdr->reason_param, &rhs->reason_param); hdr->retry_after = rhs->retry_after; hdr->expires_param = rhs->expires_param; pjsip_param_clone(pool, &hdr->other_param, &rhs->other_param); return hdr; }
static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flags) { struct unsolicited_mwi_data *mwi_data = arg; struct mwi_subscription *sub = mwi_data->sub; struct ast_sip_endpoint *endpoint = mwi_data->endpoint; pjsip_evsub_state state = mwi_data->state; const struct ast_sip_body *body = mwi_data->body; struct ast_sip_contact *contact = obj; const char *state_name; pjsip_tx_data *tdata; pjsip_sub_state_hdr *sub_state; pjsip_event_hdr *event; const pjsip_hdr *allow_events = pjsip_evsub_get_allow_events_hdr(NULL); if (ast_sip_create_request("NOTIFY", NULL, endpoint, NULL, contact, &tdata)) { ast_log(LOG_WARNING, "Unable to create unsolicited NOTIFY request to endpoint %s URI %s\n", sub->id, contact->uri); return 0; } if (!ast_strlen_zero(endpoint->subscription.mwi.fromuser)) { pjsip_fromto_hdr *from = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, NULL); pjsip_name_addr *from_name_addr = (pjsip_name_addr *) from->uri; pjsip_sip_uri *from_uri = pjsip_uri_get_uri(from_name_addr->uri); pj_strdup2(tdata->pool, &from_uri->user, endpoint->subscription.mwi.fromuser); } switch (state) { case PJSIP_EVSUB_STATE_ACTIVE: state_name = "active"; break; case PJSIP_EVSUB_STATE_TERMINATED: default: state_name = "terminated"; break; } sub_state = pjsip_sub_state_hdr_create(tdata->pool); pj_cstr(&sub_state->sub_state, state_name); pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) sub_state); event = pjsip_event_hdr_create(tdata->pool); pj_cstr(&event->event_type, "message-summary"); pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) event); pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, allow_events)); ast_sip_add_body(tdata, body); ast_sip_send_request(tdata, NULL, endpoint, NULL, NULL); return 0; }
/* * Parse Subscription-State header. */ static pjsip_hdr* parse_hdr_sub_state( pjsip_parse_ctx *ctx ) { pjsip_sub_state_hdr *hdr = pjsip_sub_state_hdr_create(ctx->pool); const pj_str_t reason = { "reason", 6 }, expires = { "expires", 7 }, retry_after = { "retry-after", 11 }; const pjsip_parser_const_t *pc = pjsip_parser_const(); pj_scan_get(ctx->scanner, &pc->pjsip_TOKEN_SPEC, &hdr->sub_state); while (*ctx->scanner->curptr == ';') { pj_str_t pname, pvalue; pj_scan_get_char(ctx->scanner); pjsip_parse_param_imp(ctx->scanner, ctx->pool, &pname, &pvalue, 0); if (pj_stricmp(&pname, &reason) == 0) { hdr->reason_param = pvalue; } else if (pj_stricmp(&pname, &expires) == 0) { hdr->expires_param = pj_strtoul(&pvalue); } else if (pj_stricmp(&pname, &retry_after) == 0) { hdr->retry_after = pj_strtoul(&pvalue); } else { pjsip_param *param = PJ_POOL_ALLOC_T(ctx->pool, pjsip_param); param->name = pname; param->value = pvalue; pj_list_push_back(&hdr->other_param, param); } } pjsip_parse_end_hdr_imp( ctx->scanner ); return (pjsip_hdr*)hdr; }
/* * Send notify. */ PJ_DEF(pj_status_t) pjsip_event_sub_notify(pjsip_event_sub *sub, pjsip_event_sub_state new_state, const pj_str_t *reason, pjsip_msg_body *body) { pjsip_tx_data *tdata; pjsip_sub_state_hdr *ss_hdr; const pjsip_route_hdr *route; pj_time_val now; pj_status_t status; pjsip_event_sub_state old_state = sub->state; pj_gettimeofday(&now); pj_assert(sub->role == PJSIP_ROLE_UAS); if (sub->role != PJSIP_ROLE_UAS) return -1; PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): sending NOTIFY", sub, state[new_state].ptr)); /* Lock subscription. */ pj_mutex_lock(sub->mutex); /* Can not send NOTIFY if current state is NULL. We can accept TERMINATED. */ if (sub->state==PJSIP_EVENT_SUB_STATE_NULL) { pj_assert(0); pj_mutex_unlock(sub->mutex); return -1; } /* Update state no matter what. */ sub_set_state(sub, new_state); /* Create transmit data. */ tdata = pjsip_endpt_create_request_from_hdr( sub->endpt, &NOTIFY, sub->to->uri, sub->from, sub->to, sub->contact, sub->call_id, sub->cseq++, NULL); if (!tdata) { pj_mutex_unlock(sub->mutex); return -1; } /* Add Event header. */ pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, sub->event)); /* Add Subscription-State header. */ ss_hdr = pjsip_sub_state_hdr_create(tdata->pool); ss_hdr->sub_state = state[new_state]; ss_hdr->expires_param = sub->expiry_time.sec - now.sec; if (ss_hdr->expires_param < 0) ss_hdr->expires_param = 0; if (reason) pj_strdup(tdata->pool, &ss_hdr->reason_param, reason); pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)ss_hdr); /* Add Allow-Events header. */ pjsip_msg_add_hdr( tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events)); /* Add authentication */ pjsip_auth_init_req( sub->pool, tdata, &sub->auth_sess, sub->cred_cnt, sub->cred_info); /* Route set. */ route = sub->route_set.next; while (route != &sub->route_set) { pj_list_insert_before( &tdata->msg->hdr, pjsip_hdr_shallow_clone(tdata->pool, route)); route = route->next; } /* Attach body. */ tdata->msg->body = body; /* That's it, send! */ status = pjsip_endpt_send_request( sub->endpt, tdata, -1, sub, &on_notify_response); if (status == 0) sub->pending_tsx++; /* If terminated notify application. */ if (new_state!=old_state && new_state==PJSIP_EVENT_SUB_STATE_TERMINATED) { if (sub->cb.on_sub_terminated) { sub->pending_tsx++; (*sub->cb.on_sub_terminated)(sub, reason); sub->pending_tsx--; } } /* Unlock subscription. */ pj_mutex_unlock(sub->mutex); if (status != 0) { PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): failed to send NOTIFY", sub, state[sub->state].ptr)); } if (sub->delete_flag && sub->pending_tsx <= 0) { pjsip_event_sub_destroy(sub); } return status; }