/** Create transports for client engine */
static
int he_create_tports(nth_engine_t * he, tagi_t *tags)
{
  he->he_tports = tport_tcreate(he, http_client_class, he->he_root, TAG_END());

  if (!he->he_tports)
    return -1;

  if (tport_tbind(he->he_tports, he_name, he_tports,
		  TPTAG_SERVER(0), TAG_NEXT(tags)) >= 0)
    return 0;

  return tport_tbind(he->he_tports, he_name, he_no_tls_tports,
		     TPTAG_SERVER(0), TAG_NEXT(tags));
}
int luasofia_nua_handle_create(lua_State *L, nua_t *nua)
{
    luasofia_nua_handle_t *lnh = NULL;
    nua_handle_t *nh = NULL;
    su_home_t *home = su_home_create();
    tagi_t *tags = luasofia_tags_table_to_taglist(L, 2, home);

    /* create a nua_handle object */
    lnh = (luasofia_nua_handle_t*)lua_newuserdata(L, sizeof(luasofia_nua_handle_t));

    /* create the nua_handle_t */
    nh = nua_handle(nua, lnh, TAG_NEXT(tags));
    if (!nh)
        luaL_error(L, "nua_handle failed!");

    /* set Lua state */
    lnh->L = L;
    lnh->nh = nh;

    /* set its metatable */
    luaL_getmetatable(L, NUA_HANDLE_MTABLE);
    lua_setmetatable(L, -2);

    /* store nua handle at luasofia userdata table */
    luasofia_userdata_table_set(L, nh);

    su_home_unref(home);
    return 1;
}
Exemple #3
0
void
nua_stack_authenticate(nua_t *nua, nua_handle_t *nh, nua_event_t e,
		       tagi_t const *tags)
{
  nua_client_request_t *cr = nh->nh_ds->ds_cr;
  int status = nh_authorize(nh, TAG_NEXT(tags));

  if (status > 0) {
    if (cr && cr->cr_wait_for_cred) {
      cr->cr_waiting = cr->cr_wait_for_cred = 0;
      nua_client_restart_request(cr, cr->cr_terminating, tags);
    }
    else {
      nua_stack_event(nua, nh, NULL, e,
		      202, "No operation to restart",
		      NULL);
    }
  }
  else if (cr && cr->cr_wait_for_cred) {
    cr->cr_waiting = cr->cr_wait_for_cred = 0;

    if (status < 0)
      nua_client_response(cr, 900, "Operation cannot add credentials", NULL);
    else
      nua_client_response(cr, 904, "Operation has no matching challenge ", NULL);
  }
  else if (status < 0) {
    nua_stack_event(nua, nh, NULL, e, 900, "Cannot add credentials", NULL);
  }
  else {
    nua_stack_event(nua, nh, NULL, e, 904, "No matching challenge", NULL);
  }
}
Exemple #4
0
/** Send request.
 *
 * @retval 0 success
 * @retval -1 if error occurred, but event has not been sent,
 *            and caller has to destroy request message @ msg
 * @retval -2 if error occurred, event has not been sent
 * @retval >=1 if error event has been sent
 */
int nua_base_client_request(nua_client_request_t *cr, msg_t *msg, sip_t *sip,
			    tagi_t const *tags)
{
  nua_handle_t *nh = cr->cr_owner;
  int proxy_is_set = NH_PISSET(nh, proxy);
  url_string_t * proxy = NH_PGET(nh, proxy);

  if (nh->nh_auth) {
    if (cr->cr_challenged ||
	NH_PGET(nh, auth_cache) == nua_auth_cache_dialog) {
      if (auc_authorize(&nh->nh_auth, msg, sip) < 0)
	return nua_client_return(cr, 900, "Cannot add credentials", msg);
    }
  }

  cr->cr_seq = sip->sip_cseq->cs_seq; /* Save last sequence number */

  assert(cr->cr_orq == NULL);

  cr->cr_orq = nta_outgoing_mcreate(nh->nh_nua->nua_nta,
				    nua_client_orq_response,
				    nua_client_request_ref(cr),
				    NULL,
				    msg,
				    TAG_IF(proxy_is_set,
					   NTATAG_DEFAULT_PROXY(proxy)),
				    TAG_NEXT(tags));

  if (cr->cr_orq == NULL) {
    nua_client_request_unref(cr);
    return -1;
  }

  return 0;
}
static
int nua_publish_client_request(nua_client_request_t *cr,
			       msg_t *msg, sip_t *sip,
			       tagi_t const *tags)
{
  nua_dialog_usage_t *du = cr->cr_usage;
  int un, done;
  sip_etag_t const *etag = NULL;

  un = cr->cr_terminating ||
    cr->cr_event != nua_r_publish ||
    (du && du->du_shutdown) ||
    (sip->sip_expires && sip->sip_expires->ex_delta == 0);
  nua_client_set_terminating(cr, un);
  done = un;

  if (du) {
    struct publish_usage *pu = nua_dialog_usage_private(du);

    if (nua_client_bind(cr, du) < 0)
      return -1;
    if (pu->pu_published)
      done = 1;
    etag = pu->pu_etag;
  }

  return nua_base_client_trequest(cr, msg, sip,
				  SIPTAG_IF_MATCH(etag),
				  TAG_IF(done, SIPTAG_PAYLOAD(NONE)),
				  TAG_IF(done, SIPTAG_CONTENT_TYPE(NONE)),
				  TAG_IF(un, SIPTAG_EXPIRES_STR("0")),
				  TAG_NEXT(tags));
}
static int nua_notify_client_report(nua_client_request_t *cr,
				    int status, char const *phrase,
				    sip_t const *sip,
				    nta_outgoing_t *orq,
				    tagi_t const *tags)
{
  nua_handle_t *nh = cr->cr_owner;
  nua_dialog_usage_t *du = cr->cr_usage;
  struct notifier_usage *nu = nua_dialog_usage_private(du);
  enum nua_substate substate = nua_substate_terminated;

  if (nu && !cr->cr_terminated)
    substate = nu->nu_substate;

  nua_stack_tevent(nh->nh_nua, nh,
		   nta_outgoing_getresponse(orq),
		   (enum nua_event_e)cr->cr_event,
		   status, phrase,
		   NUTAG_SUBSTATE(substate),
		   SIPTAG_EVENT(du ? du->du_event : NULL),
		   TAG_NEXT(tags));

  if (du && du->du_cr == cr && !cr->cr_terminated) {
    if (nu->nu_requested) {
      /* Re-SUBSCRIBEd while NOTIFY was in progress, resend NOTIFY */
      nua_client_resend_request(cr, 0);
    }
    else if (nu->nu_expires) {
      nua_dialog_usage_set_refresh_at(du, nu->nu_expires);
    }
  }

  return 0;
}
Exemple #7
0
static int luasofia_nua_create(lua_State *L)
{
    luasofia_su_root_t *lroot = NULL;
    luasofia_nua_t *lnua = NULL;
    nua_t *nua = NULL;
    tagi_t *tags = NULL;
    su_home_t *home = su_home_create();

    /* get and check first argument (should be a root_t) */
    lroot = (luasofia_su_root_t*)luaL_checkudata(L, 1, SU_ROOT_MTABLE);

    /* check the callback table */
    if (!lua_isnoneornil(L, 2))
        luaL_checktype(L, 2, LUA_TTABLE);

    tags = luasofia_tags_table_to_taglist(L, 4, home);

    /* create a nua object */
    lnua = (luasofia_nua_t*) lua_newuserdata(L, sizeof(luasofia_nua_t));

    /* create the nua_t */
    nua = nua_create(lroot->root, nua_event_callback, L, TAG_NEXT(tags));
    if (!nua) {
        luaL_error(L, "nua_create failed!");
    }
    /* save nua object */
    lnua->nua = nua;

    /* set its metatable */
    luaL_getmetatable(L, NUA_MTABLE);
    lua_setmetatable(L, -2);

    /* store nua at luasofia userdata table */
    luasofia_userdata_table_set(L, nua);

    /* create env table */
    lua_createtable(L, 2, 0);

    /* save second argument (callbacks) on env table */
    if (!lua_isnoneornil(L, 2)) {
        lua_pushvalue(L, 2);
        lua_rawseti(L, -2, ENV_CALLBACK_INDEX);
    }

    /* save third argument (magic) on env table */
    if (!lua_isnoneornil(L, 3)) {
        lua_pushvalue(L, 3);
        lua_rawseti(L, -2, ENV_MAGIC_INDEX);
    }

    /* set env table as environment for udata */
    lua_setfenv(L, -2);

    su_home_unref(home);
    return 1;
}
Exemple #8
0
static int luasofia_nua_get_params(lua_State *L)
{
    /* get and check first argument (should be a luasofia_nua_t) */
    su_home_t *home = su_home_create();
    luasofia_nua_t *lnua = (luasofia_nua_t*)luaL_checkudata(L, 1, NUA_MTABLE);
    tagi_t *tags = luasofia_tags_table_to_taglist(L, 2, home);

    nua_get_params(lnua->nua, TAG_NEXT(tags));
    su_home_unref(home);
    return 0;
}
static int luasofia_nua_handle_invite(lua_State *L)
{
    /* get and check first argument (should be a luasofia_nua_handle_t) */
    luasofia_nua_handle_t *lnh = (luasofia_nua_handle_t*)luaL_checkudata(L, 1, NUA_HANDLE_MTABLE);
    if (lnh->nh) {
        su_home_t *home = su_home_create();
        tagi_t *tags = luasofia_tags_table_to_taglist(L, 2, home);
        nua_invite(lnh->nh, TAG_NEXT(tags));
        su_home_unref(home);
    }
    return 0;
}
Exemple #10
0
int luasofia_nta_agent_create(lua_State * L)
{
    luasofia_su_root_t *lroot = NULL;
    url_string_t * contact = NULL;
    luasofia_nta_agent_t* u_nta_agent = NULL;
    su_home_t *home = su_home_create();
    tagi_t *tags = NULL;

    /* get and check first argument (should be a root_t) */
    lroot = (luasofia_su_root_t*)luaL_checkudata(L, -4, SU_ROOT_MTABLE);

    if(lua_isuserdata (L, -3)) {
        //Since there is no metatable for url_t or url_string_t we cant perform a checkudata here.
        contact = (url_string_t *) lua_touserdata (L, -3);
    } else {
        contact = URL_STRING_MAKE(luaL_checkstring (L, -3));
    }

    /* check the callback function */
    if(!lua_isfunction(L, -2))
        luaL_error(L, "nta_agent_create failed!, expected a callback function !");

    /* check if there is tags */
    tags = luasofia_tags_table_to_taglist(L, -1, home);

    u_nta_agent           = (luasofia_nta_agent_t *) lua_newuserdata(L, sizeof(luasofia_nta_agent_t));
    u_nta_agent->L        = L;
    u_nta_agent->agent    = nta_agent_create (lroot->root,
                                              (url_string_t const *)contact,
                                              nta_agent_message_callback,
                                              (nta_agent_magic_t *)u_nta_agent,
                                              TAG_NEXT(tags));

    // lets hold the ref to the lua callback function.
    lua_pushvalue(L, -3);
    u_nta_agent->callback_ref = luaL_ref(L, LUA_REGISTRYINDEX);

    if (!u_nta_agent->agent)
        luaL_error(L, "nta_agent_create failed!");

    /* set its metatable */
    luaL_getmetatable(L, NTA_AGENT_MTABLE);
    lua_setmetatable(L, -2);

    /* store nta_agent at luasofia userdata table 
       userdata_table[nta_agent_lightudata] = nta_agent_fulludata */
    luasofia_userdata_table_set(L, u_nta_agent->agent);

    su_home_unref(home);
    return 1;
}
/** @internal Terminate notifier. */
void nua_stack_terminate(nua_t *nua,
			 nua_handle_t *nh,
			 nua_event_t e,
			 tagi_t const *tags)
{
  sip_event_t const *event = NULL;
  sip_content_type_t const *ct = NULL;
  sip_payload_t const *pl = NULL;
  char const *event_s = NULL, *ct_s = NULL, *pl_s = NULL;
  nea_event_t *nev = NULL;

  if (nh->nh_notifier == NULL) {
    UA_EVENT2(e, 900, "No event server to terminate");
    return;
  }

  tl_gets(tags,
	  SIPTAG_EVENT_REF(event),
	  SIPTAG_EVENT_STR_REF(event_s),
	  SIPTAG_CONTENT_TYPE_REF(ct),
	  SIPTAG_CONTENT_TYPE_STR_REF(ct_s),
	  SIPTAG_PAYLOAD_REF(pl),
	  SIPTAG_PAYLOAD_STR_REF(pl_s),
	  TAG_END());

  nev = nea_event_get(nh->nh_notifier,
		      event ? event->o_type : event_s);

  if (nev && (pl || pl_s) && (ct || ct_s)) {
    nea_server_update(nh->nh_notifier, nev, TAG_NEXT(tags));
  }

  nh_notifier_shutdown(nh, NULL,
		       NEATAG_REASON("noresource"),
		       TAG_NEXT(tags));

  nua_stack_event(nua, nh, NULL, e, SIP_200_OK, NULL);
}
void nua_stack_authorize(nua_t *nua,
			 nua_handle_t *nh,
			 nua_event_t e,
			 tagi_t const *tags)
{
  nea_sub_t *sub = NULL;
  int state = nea_extended;

  tl_gets(tags,
	  NEATAG_SUB_REF(sub),
	  NUTAG_SUBSTATE_REF(state),
	  TAG_END());

  if (sub && state > 0) {
    nea_sub_auth(sub, (nea_state_t)state, TAG_NEXT(tags));
    nua_stack_event(nua, nh, NULL, e, SIP_200_OK, NULL);
  }
  else {
    nua_stack_event(nua, nh, NULL, e, NUA_ERROR_AT(__FILE__, __LINE__), NULL);
  }
}
Exemple #13
0
/**@internal
 * Save handle parameters and initial authentication info.
 *
 * @retval -1 upon an error
 * @retval 0 when successful
 */
int nua_stack_init_handle(nua_t *nua, nua_handle_t *nh, tagi_t const *tags)
{
  int retval = 0;

  if (nh == NULL)
    return -1;

  assert(nh != nua->nua_dhandle);

  if (nua_stack_set_params(nua, nh, nua_i_error, tags) < 0)
    retval = -1;

  if (retval || nh->nh_init) /* Already initialized? */
    return retval;

  if (nh->nh_tags)
    nh_authorize(nh, TAG_NEXT(nh->nh_tags));

  nh->nh_init = 1;

  return 0;
}
static int luasofia_nua_handle_respond(lua_State *L)
{
    /* get and check first argument (should be a luasofia_nua_handle_t) */
    luasofia_nua_handle_t *lnh = (luasofia_nua_handle_t*) luaL_checkudata(L, 1, NUA_HANDLE_MTABLE);
    if (lnh->nh) {
        char const* phrase = NULL;
        su_home_t *home = su_home_create();
        /* get and check second argument (should be a int) */
        int status = luaL_checkinteger(L, 2);
      
        /* get and check fourth argument (should be a tag table) */
        tagi_t *tags = luasofia_tags_table_to_taglist(L, 4, home);

        /* get and check third argument (should be a string) */
        if (!lua_isnoneornil(L, 3))
            phrase = luaL_checkstring (L, 3);

        nua_respond(lnh->nh, status, phrase, TAG_NEXT(tags));
        su_home_unref(home);
    }
    return 0;
}
Exemple #15
0
static tagi_t *soa_static_get_paramlist(soa_session_t const *ss,
					tag_type_t tag, tag_value_t value,
					...)
{
  soa_static_session_t *sss = (soa_static_session_t *)ss;

  ta_list ta;
  tagi_t *tl;

  ta_start(ta, tag, value);

  tl = soa_base_get_paramlist(ss,
			      TAG_IF(sss->sss_audio_aux,
				     SOATAG_AUDIO_AUX(sss->sss_audio_aux)),
			      TAG_IF(sss->sss_ordered_user,
				     SOATAG_ORDERED_USER(1)),
			      TAG_IF(sss->sss_reuse_rejected,
				     SOATAG_REUSE_REJECTED(1)),
			      TAG_NEXT(ta_args(ta)));

  ta_end(ta);

  return tl;
}
Exemple #16
0
int nua_stack_init(su_root_t *root, nua_t *nua)
{
  su_home_t *home;
  nua_handle_t *dnh;

  static int initialized_logs = 0;

  enter;

  if (!initialized_logs) {
    extern su_log_t tport_log[];
    extern su_log_t nta_log[];
    extern su_log_t nea_log[];
    extern su_log_t iptsec_log[];

    su_log_init(tport_log);
    su_log_init(nta_log);
    su_log_init(nea_log);
    su_log_init(iptsec_log);

    initialized_logs = 1;
  }

  nua->nua_root = root;

  home = nua->nua_home;
  nua->nua_handles_tail = &nua->nua_handles;
  sip_from_init(nua->nua_from);

  dnh = su_home_clone(nua->nua_home, sizeof (*dnh) + sizeof(*dnh->nh_prefs));
  if (!dnh)
    return -1;

  dnh->nh_prefs = (void *)(dnh + 1);
  dnh->nh_valid = nua_valid_handle_cookie;
  dnh->nh_nua = nua;
  nua_handle_ref(dnh); dnh->nh_ref_by_stack = 1;
  nua_handle_ref(dnh); dnh->nh_ref_by_user = 1;
  nh_append(nua, dnh);
  dnh->nh_identity = dnh;
  dnh->nh_ds->ds_local = nua->nua_from;
  dnh->nh_ds->ds_remote = nua->nua_from;

  if (nua_stack_set_defaults(dnh, dnh->nh_prefs) < 0)
    return -1;

  if (nua_stack_set_params(nua, dnh, nua_i_none, nua->nua_args) < 0)
    return -1;

  /* XXX - soa should know what it supports */
  nua->nua_invite_accept = sip_accept_make(home, SDP_MIME_TYPE);

  nua->nua_accept_multipart = sip_accept_format(home, "%s, %s",
						SDP_MIME_TYPE,
						"multipart/*");

  nua->nua_nta = nta_agent_create(root, NONE, NULL, NULL,
				  NTATAG_MERGE_482(1),
				  NTATAG_CLIENT_RPORT(1),
				  NTATAG_UA(1),
#if HAVE_SOFIA_SMIME
				  NTATAG_SMIME(nua->sm),
#endif
				  TPTAG_STUN_SERVER(1),
				  TAG_NEXT(nua->nua_args));

  dnh->nh_ds->ds_leg = nta_leg_tcreate(nua->nua_nta,
				       nua_stack_process_request, dnh,
				       NTATAG_NO_DIALOG(1),
				       TAG_END());

  if (nua->nua_nta == NULL ||
      dnh->nh_ds->ds_leg == NULL ||
      nta_agent_set_params(nua->nua_nta, NTATAG_UA(1), TAG_END()) < 0 ||
      nua_stack_init_transport(nua, nua->nua_args) < 0) {
    SU_DEBUG_1(("nua: initializing SIP stack failed\n"));
    return -1;
  }

  if (nua_stack_set_from(nua, 1, nua->nua_args) < 0)
    return -1;

  if (nua->nua_prefs->ngp_detect_network_updates)
    nua_stack_launch_network_change_detector(nua);

  return 0;
}
};

/* ====================================================================== */
/* Internal prototypes */

tagi_t nth_client_tags[] = {
  {nthtag_mclass, 0},
  {nthtag_message, 0},
  {nthtag_mflags, 0},

  {nthtag_proxy, 0},
  {nthtag_error_msg, 0},
  {nthtag_template, 0},
  {nthtag_authentication, 0},

  {TAG_NEXT(tport_tags)}
};

/* ====================================================================== */
/* Internal prototypes */

static int he_create_tports(nth_engine_t * he, tagi_t *tags);
static int he_timer_init(nth_engine_t * he);
static void he_timer(su_root_magic_t *, su_timer_t *, nth_engine_t * he);
static void hc_timer(nth_engine_t * he, nth_client_t * hc, uint32_t now);
static uint32_t he_now(nth_engine_t const *he);
static void he_recv_message(nth_engine_t * he, tport_t * tport,
			    msg_t *msg, void *arg, su_time_t now);
static msg_t *he_msg_create(nth_engine_t * he, int flags,
			    char const data[], usize_t dlen,
			    tport_t const *tport, nth_client_t * hc);
Exemple #18
0
/**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);
}
void
nua_stack_notifier(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
{
  su_home_t home[1] = { SU_HOME_INIT(home) };
  sip_event_t const *event = NULL;
  sip_content_type_t const *ct = NULL;
  sip_payload_t const *pl = NULL;
  url_string_t const *url = NULL;
  char const *event_s = NULL, *ct_s = NULL, *pl_s = NULL;
  nea_event_t *ev;
  int status = 900;
  char const *phrase = nua_internal_error;

  nua_stack_init_handle(nua, nh, tags);

  tl_gets(tags,
	  NUTAG_URL_REF(url),
	  SIPTAG_EVENT_REF(event),
	  SIPTAG_EVENT_STR_REF(event_s),
	  SIPTAG_CONTENT_TYPE_STR_REF(ct_s),
	  SIPTAG_PAYLOAD_REF(pl),
	  SIPTAG_PAYLOAD_STR_REF(pl_s),
	  TAG_END());

  if (!event && !event_s)
    status = 400, phrase = "Missing Event";

  else if (!ct && !ct_s)
    status = 400, phrase = "Missing Content-Type";

  else if (!nh->nh_notifier &&
	   !(nh->nh_notifier =
	     nea_server_create(nua->nua_nta, nua->nua_root,
			       url->us_url,
			       NH_PGET(nh, max_subscriptions),
			       NULL, nh,
			       TAG_NEXT(tags))))
    status = 900, phrase = nua_internal_error;

  else if (!event && !(event = sip_event_make(home, event_s)))
    status = 900, phrase = "Could not create an event header";

  else if (!(ev = nh_notifier_event(nh, home, event, tags)))
    status = 900, phrase = "Could not create an event view";

  else if (nea_server_update(nh->nh_notifier, ev,  TAG_NEXT(tags)) < 0)
    status = 900, phrase = "No content for event";

  else if (nea_server_notify(nh->nh_notifier, ev) < 0)
    status = 900, phrase = "Error when notifying watchers";

  else
    nua_stack_tevent(nua, nh, NULL, e, status = SIP_200_OK,
		     SIPTAG_EVENT(event),
		     SIPTAG_CONTENT_TYPE(ct),
		     TAG_END());

  if (status != 200)
    nua_stack_event(nua, nh, NULL, e, status, phrase, NULL);

  su_home_deinit(home);
}
int nua_notify_server_report(nua_server_request_t *sr, tagi_t const *tags)
{
  nua_handle_t *nh = sr->sr_owner;
  nua_dialog_usage_t *du = sr->sr_usage;
  struct event_usage *eu = nua_dialog_usage_private(du);
  sip_t const *sip = sr->sr_request.sip;
  enum nua_substate substate = nua_substate_terminated;
  sip_time_t delta = SIP_TIME_MAX;
  sip_event_t const *o = sip->sip_event;
  int retry = -1;
  int retval;

  if (eu) {
    sip_subscription_state_t *subs = sip->sip_subscription_state;

    substate = eu->eu_substate;

    if (substate == nua_substate_active || substate == nua_substate_pending) {
      if (subs && subs->ss_expires) {
	sip_time_t now = sip_now();
	sip_time_t delta0 = strtoul(subs->ss_expires, NULL, 10);
	if (now + delta0 <= eu->eu_expires)
	  delta = delta0;
      }
    }
    else if (substate == nua_substate_embryonic) {
      if (subs && subs->ss_reason) {
	if (su_casematch(subs->ss_reason, "deactivated")) {
	  retry = 0;		/* retry immediately */
	}
	else if (su_casematch(subs->ss_reason, "probation")) {
	  retry = 30;
	  if (subs->ss_retry_after)
	    retry = strtoul(subs->ss_retry_after, NULL, 10);
	  if (retry > 3600)
	    retry = 3600;
	}
      }
    }
    else if (substate == nua_substate_terminated) {
      sr->sr_terminating = 1;
    }
  }

  retval = nua_base_server_treport(sr, /* can destroy sr */
				   NUTAG_SUBSTATE(substate),
				   SIPTAG_EVENT(o),
				   TAG_NEXT(tags));

  if (retval != 1 || du == NULL)
    return retval;

  if (eu->eu_unsolicited) {
    /* Xyzzy */;
  }
  else if (retry >= 0) {		/* Try to subscribe again */
    /* XXX - this needs through testing */
    nua_dialog_remove(nh, nh->nh_ds, du); /* tear down */
    nua_dialog_usage_set_refresh_range(du, retry, retry + 5);
  }
  else {
    if (delta < SIP_TIME_MAX) {
      nua_dialog_usage_set_refresh(du, delta);
      eu->eu_expires = du->du_refquested + delta;
    }
  }

  return retval;
}