static int nua_subscribe_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;
  sip_event_t *o = sip->sip_event;

  du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, o);

  if (du == NULL && o == NULL)
    du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, NONE);

  if (du) {
    if (du->du_event && o == NULL)
      /* Add Event header */
      sip_add_dup(msg, sip, (sip_header_t *)du->du_event);
  }
  else if (cr->cr_event == nua_r_subscribe) {
    /* Create dialog usage */
    du = nua_dialog_usage_add(nh, nh->nh_ds, nua_subscribe_usage, o);
    /* Note that we allow SUBSCRIBE without event */
  }

  cr->cr_usage = du;

  return 0;
}
示例#2
0
static int nua_publish_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 publish_usage *pu;

  if (cr->cr_event == nua_r_publish) {
    du = nua_dialog_usage_add(nh, nh->nh_ds, nua_publish_usage, NULL);
    if (!du)
      return -1;
    pu = nua_dialog_usage_private(du);
    pu->pu_published = 0;
    if (sip->sip_if_match) {
      pu->pu_etag = sip_etag_dup(nh->nh_home, sip->sip_if_match);
      if (!pu->pu_etag)
	return -1;
      sip_header_remove(msg, sip, (sip_header_t *)sip->sip_if_match);
    }
  }
  else
    du = nua_dialog_usage_get(nh->nh_ds, nua_publish_usage, NULL);

  cr->cr_usage = du;

  return 0;
}
示例#3
0
int nua_subscribe_server_preprocess(nua_server_request_t *sr)
{
  nua_handle_t *nh = sr->sr_owner;
  nua_dialog_state_t *ds = nh->nh_ds;
  nua_dialog_usage_t *du;
  struct notifier_usage *nu;
  sip_t const *sip = sr->sr_request.sip;
  sip_event_t *o = sip->sip_event;
  char const *event = o ? o->o_type : NULL;
  /* Maximum expiration time */
  unsigned long expires = sip->sip_expires ? sip->sip_expires->ex_delta : 3600;
  sip_time_t now = sip_now();
  sip_allow_events_t *appl_event = NH_PGET(nh, appl_event);

  assert(nh && nh->nh_nua->nua_dhandle != nh);

  du = nua_dialog_usage_get(ds, nua_notify_usage, o);

  if (du == NULL) {
    /* Create a new subscription */
    du = nua_dialog_usage_add(nh, ds, nua_notify_usage, o);
    if (du == NULL)
      return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
  }
  else if (!msg_header_find_param((void *)appl_event, event)) {
    unsigned max_expires;

    /* Refresh existing subscription */
    if (su_strmatch(event, "refer"))
      max_expires = NH_PGET(nh, refer_expires);
    else
      max_expires = NH_PGET(nh, sub_expires);

    if (expires >= max_expires)
      expires = max_expires;

    SR_STATUS1(sr, SIP_200_OK);
  }

  nu = nua_dialog_usage_private(du);

  if (now + expires >= now)
    nu->nu_requested = now + expires;
  else
    nu->nu_requested = SIP_TIME_MAX - 1;

#if SU_HAVE_EXPERIMENTAL
  nu->nu_etags =
    sip_suppress_body_if_match(sip) ||
    sip_suppress_notify_if_match(sip) ||
    sip_has_feature(sr->sr_request.sip->sip_supported, "etags");
#endif

  sr->sr_usage = du;

  return sr->sr_status <= 100 ? 0 : sr->sr_status;
}
示例#4
0
static int nua_publish_client_template(nua_client_request_t *cr,
				       msg_t **return_msg,
				       tagi_t const *tags)
{
  nua_dialog_usage_t *du;

  if (cr->cr_event == nua_r_publish)
    return 0;

  du = nua_dialog_usage_get(cr->cr_owner->nh_ds, nua_publish_usage, NULL);
  if (du && du->du_cr) {
    if (nua_client_set_target(cr, du->du_cr->cr_target) < 0)
      return -1;
    *return_msg = msg_copy(du->du_cr->cr_msg);
    return 1;
  }

  return 0;
}
示例#5
0
int nua_subscribe_server_init(nua_server_request_t *sr)
{
  nua_handle_t *nh = sr->sr_owner;
  nua_dialog_state_t *ds = nh->nh_ds;
  sip_allow_events_t const *allow_events = NH_PGET(nh, allow_events);
  sip_t const *sip = sr->sr_request.sip;
  sip_event_t *o = sip->sip_event;
  char const *event = o ? o->o_type : NULL;

  if (sr->sr_initial || !nua_dialog_usage_get(ds, nua_notify_usage, o)) {
    if (su_strmatch(event, "refer"))
      /* refer event subscription should be initiated with REFER */
      return SR_STATUS1(sr, SIP_403_FORBIDDEN);

    /* XXX - event is case-sensitive, should use msg_header_find_item() */
    if (!event || !msg_header_find_param(allow_events->k_common, event))
      return SR_STATUS1(sr, SIP_489_BAD_EVENT);
  }

  return 0;
}
int nua_notify_server_preprocess(nua_server_request_t *sr)
{
  nua_dialog_state_t *ds = sr->sr_owner->nh_ds;
  nua_dialog_usage_t *du;
  struct event_usage *eu;
  sip_t const *sip = sr->sr_request.sip;
  sip_event_t *o = sip->sip_event;
  enum nua_substate substate = nua_substate_terminated;
  sip_subscription_state_t *subs = sip->sip_subscription_state;
  char const *what = "", *reason = NULL;
  int solicited = 1;

  du = nua_dialog_usage_get(ds, nua_subscribe_usage, o);

  if (du == NULL) {
    if (!sip_is_allowed(NH_PGET(sr->sr_owner, appl_method), SIP_METHOD_NOTIFY))
      return SR_STATUS(sr, 481, "Subscription Does Not Exist");

    solicited = 0;    /* Let application to handle unsolicited NOTIFY */
    du = nua_dialog_usage_add(sr->sr_owner, ds, nua_subscribe_usage, o);
    if (!du)
      return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
  }

  sr->sr_usage = du;
  eu = nua_dialog_usage_private(du); assert(eu);
  eu->eu_notified++;
  if (!o || !o->o_id)
    eu->eu_no_id = 1;

  if (subs == NULL) {
    /* Compatibility */
    unsigned long delta = eu->eu_delta;
    if (sip->sip_expires)
      delta = sip->sip_expires->ex_delta;

    if (delta == 0)
      substate = nua_substate_terminated, what = "terminated";
    else
      substate = nua_substate_active, what = "active";
  }
  else if (su_casematch(subs->ss_substate, what = "terminated")) {
    substate = nua_substate_terminated;
    reason = subs->ss_reason;

    if (su_casematch(reason, "deactivated") ||
	su_casematch(reason, "probation"))
      substate = nua_substate_embryonic;
  }
  else if (su_casematch(subs->ss_substate, what = "pending")) {
    substate = nua_substate_pending;
  }
  else /* if (su_casematch(subs->ss_substate, what = "active")) */ {
    /* Any extended state is considered as active */
    what = subs->ss_substate;
    substate = nua_substate_active;
  }

  eu->eu_substate = substate;
  if (!solicited)
    eu->eu_unsolicited = 1;

  SU_DEBUG_5(("nua(%p): %s: %s (%s)\n",
	      (void *)sr->sr_owner, "nua_notify_server_preprocess",
	      what, reason ? reason : ""));

  if (solicited)
    return SR_STATUS1(sr, SIP_200_OK);

  return 0;
}
示例#7
0
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);
}