/**Create a client request. * * @retval 0 if request is pending * @retval > 0 if error event has been sent * @retval < 0 upon an error */ int nua_client_create(nua_handle_t *nh, int event, nua_client_methods_t const *methods, tagi_t const * const tags) { su_home_t *home = nh->nh_home; nua_client_request_t *cr; sip_method_t method; char const *name; method = methods->crm_method, name = methods->crm_method_name; if (!name) { tagi_t const *t = tl_find_last(tags, nutag_method); if (t) name = (char const *)t->t_value; } cr = su_zalloc(home, sizeof *cr + methods->crm_extra); if (!cr) { return nua_stack_event(nh->nh_nua, nh, NULL, (enum nua_event_e)event, NUA_ERROR_AT(__FILE__, __LINE__), NULL); } cr->cr_methods = methods; cr->cr_event = event; cr->cr_method = method; cr->cr_method_name = name; cr->cr_contactize = methods->crm_flags.target_refresh; cr->cr_dialog = methods->crm_flags.create_dialog; cr->cr_auto = 1; if (su_msg_is_non_null(nh->nh_nua->nua_signal)) { nua_event_data_t *e = su_msg_data(nh->nh_nua->nua_signal)->ee_data; if (tags == e->e_tags && event == e->e_event) { cr->cr_auto = 0; if (tags) { nua_move_signal(cr->cr_signal, nh->nh_nua->nua_signal); if (cr->cr_signal) { /* Steal reference from signal */ cr->cr_owner = e->e_nh, e->e_nh = NULL; cr->cr_tags = tags; } } } } if (cr->cr_owner == NULL) cr->cr_owner = nua_handle_ref(nh); if (tags && cr->cr_tags == NULL) cr->cr_tags = tl_tlist(nh->nh_home, TAG_NEXT(tags)); #if HAVE_MEMLEAK_LOG SU_DEBUG_0(("%p %s() for %s\n", cr, __func__, cr->cr_methods->crm_method_name)); #endif if (nua_client_request_queue(cr)) return 0; return nua_client_init_request(cr); }
static int nua_notify_client_init(nua_client_request_t *cr, msg_t *msg, sip_t *sip, tagi_t const *tags) { nua_handle_t *nh = cr->cr_owner; nua_dialog_usage_t *du; struct notifier_usage *nu; sip_event_t const *o = sip->sip_event; sip_subscription_state_t *ss = sip->sip_subscription_state; sip_time_t now = sip_now(); if (o == NULL && nh->nh_ds->ds_has_notifys == 1) o = NONE; du = nua_dialog_usage_get(nh->nh_ds, nua_notify_usage, o); if (!du) { tagi_t const *newsub = tl_find_last(tags, nutag_newsub); if (!newsub || !newsub->t_value) return 0; /* Rejected eventually by nua_notify_client_request() */ /* Create new notifier */ du = nua_dialog_usage_add(nh, nh->nh_ds, nua_notify_usage, o); if (du == NULL) return -1; nu = nua_dialog_usage_private(du); nu->nu_expires = now; } else nu = nua_dialog_usage_private(du); if (nu->nu_substate == nua_substate_terminated) { /*Xyzzy*/; } else if (ss != NULL) { /* SIPTAG_SUBSCRIPTION_STATE() overrides NUTAG_SUBSTATE() */ nu->nu_substate = nua_substate_make(ss->ss_substate); if (ss->ss_expires) { unsigned long expires = strtoul(ss->ss_expires, NULL, 10); if (now + expires < now) expires = SIP_TIME_MAX - now - 1; /* We can change the lifetime of unsolicited subscription at will */ if (nu->nu_requested == 0) nu->nu_expires = nu->nu_requested = now + expires; /* Notifier can only shorten the subscribed time */ else if (nu->nu_requested >= now + expires) nu->nu_expires = nu->nu_requested = now + expires; } else { if (nu->nu_requested >= nu->nu_expires) nu->nu_expires = nu->nu_requested; } } else { enum nua_substate substate = nu->nu_substate; if (nu->nu_requested >= nu->nu_expires) nu->nu_expires = nu->nu_requested; if (nu->nu_expires > now) { tagi_t const *t = tl_find_last(tags, nutag_substate); if (t) substate = (enum nua_substate)t->t_value; } else substate = nua_substate_terminated; switch (substate) { case nua_substate_embryonic: /*FALLTHROUGH*/ case nua_substate_pending: nu->nu_substate = nua_substate_pending; break; case nua_substate_active: default: nu->nu_substate = nua_substate_active; break; case nua_substate_terminated: nu->nu_substate = nua_substate_terminated; break; } } cr->cr_usage = du; return nua_notify_client_init_etag(cr, msg, sip, tags); }