Пример #1
0
/** Filter an element in tag list */
tagi_t *t_filter(tagi_t *dst,
                 tagi_t const filter[],
                 tagi_t const *src,
                 void **bb)
{
    tag_type_t tt = TAG_TYPE_OF(src);
    tagi_t const *f;

    if (dst) {
        for (f = filter; f; f = t_next(f)) {
            if (TAG_TYPE_OF(f)->tt_filter)
                dst = TAG_TYPE_OF(f)->tt_filter(dst, f, src, bb);
            else if (f->t_tag == tt)
                dst = t_dup(dst, src, bb);
        }
    }
    else {
        size_t d = 0;

        for (f = filter; f; f = t_next(f)) {
            if (TAG_TYPE_OF(f)->tt_filter)
                d += (size_t)TAG_TYPE_OF(f)->tt_filter(NULL, f, src, bb);
            else if (tt == f->t_tag) {
                d += t_len(src);
                *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
            }
        }

        dst = (tagi_t *)d;
    }

    return dst;
}
Пример #2
0
/** Make filtered copy of a tag list @a src with @a filter to @a dst.
 *
 * Each tag in @a src is checked against tags in list @a filter. If the tag
 * is in the @a filter list, or there is a special filter tag in the list
 * which matches with the tag in @a src, the tag is duplicated to @a dst using
 * memory buffer in @a b.
 *
 * When @a dst is NULL, this function calculates the size of the filtered list.
 *
 * @sa tl_afilter(), tl_tfilter(), tl_filtered_tlist(),
 * TAG_FILTER(), TAG_ANY(), #ns_tag_class
 */
tagi_t *tl_filter(tagi_t dst[],
                  tagi_t const filter[],
                  tagi_t const src[],
                  void **b)
{
    tagi_t const *s;
    tagi_t *d;

    if (dst) {
        for (s = src, d = dst; s; s = t_next(s))
            d = t_filter(d, filter, s, b);
    }
    else {
        size_t rv = 0;

        for (s = src, d = dst; s; s = t_next(s)) {
            d = t_filter(NULL, filter, s, b);
            rv += (char *)d - (char *)NULL;
        }

        d = (tagi_t *)rv;
    }

    return d;
}
Пример #3
0
static void
printrans(ACISM const*psp, STATE s, char const *charv,
            FILE *out, MEMREF const *pattv)
{
    (void)pattv;
    TRAN x = psp->tranv[s];
    if (!x) {
        fprintf(out, "(empty)\n");
        return;
    }

    SYMBOL sym = t_sym(psp,x);
    char c = charv[sym];

    if (sym)
	    fprintf(out, "--");
    else
        fprintf(out, "%02X ", c);

    putc("M-"[!(x & IS_MATCH)], out);
    putc("S-"[!(x & IS_SUFFIX)], out);

    STATE next = t_next(psp, x);
    if (t_isleaf(psp, x)) {
        fprintf(out, " => %d\n", t_strno(psp, x));
    } else {
        fprintf(out, " %7"FX"d", next);
        if (x & IS_MATCH) {
            int i;
            for (i = p_hash(psp, s); psp->hashv[i].state != s; ++i);
            fprintf(out, " #> %"FX"d", psp->hashv[i].strno);
        }
        putc('\n', out);
    }
}
Пример #4
0
/** Find tags from given list.
 *
 * Copies values of argument tag list into the reference tags in the tag
 * list @a lst.
 *
 * @sa tl_gets()
 */
int tl_tgets(tagi_t lst[], tag_type_t tag, tag_value_t value, ...)
{
    int n = 0;
    tagi_t *t;

    ta_list ta;
    ta_start(ta, tag, value);

    for (t = lst; t; t = (tagi_t *)t_next(t)) {
        tag_type_t tt = t->t_tag;

        if (!tt)
            continue;

        if (tt->tt_class == ref_tag_class) {
            assert(((tag_type_t)tt->tt_magic)->tt_class->tc_ref_set);
            n += tl_get(tt, (void *)t->t_value, ta_args(ta));
        }
#if !defined(NDEBUG)
        else if (tt->tt_class->tc_ref_set) {
            fprintf(stderr, "WARNING: tag %s::%s used in tl_tgets(lst)\n",
                    tt->tt_ns, tt->tt_name);
            assert(tt->tt_class == ref_tag_class);
        }
#endif
    }

    ta_end(ta);

    return n;
}
Пример #5
0
/** Duplicate a tag list.
 *
 * Deep copy the tag list @a src to the buffer @a dst. Memory areas
 * associated with @a src are copied to buffer at @a **bb.
 *
 * This is a rather low-level function. See tl_adup() for a more convenient
 * functionality.
 *
 * The size of the @a dst buffer must be at least @c tl_len(src) bytes.  The
 * size of buffer @a **bb must be at least @c tl_dup_xtra(src) bytes.
 *
 * @param[out] dst pointer to the destination buffer
 * @param[in] src tag list to be duplicated
 * @param[in,out] bb  pointer to pointer to buffer
 *
 * @return
 * A pointer to the @a dst list after last
 * duplicated taglist element.
 *
 * The pointer at @a *bb is updated to the byte after last duplicated memory
 * area.
 */
tagi_t *tl_dup(tagi_t dst[], tagi_t const src[], void **bb)
{
    do {
        dst = t_dup(dst, src, bb);
    } while ((src = t_next(src)));

    return dst;
}
Пример #6
0
/** Find last tag item with type @a tt from list. */
tagi_t *tl_find_last(tagi_t const lst[], tag_type_t tt)
{
    tagi_t const *last, *next;

    for (next = last = t_find(tt, lst); next; next = t_find(tt, t_next(last)))
        last = next;

    return (tagi_t *)last;
}
Пример #7
0
/** Calculate the size of extra memory areas associated with tag list. */
size_t tl_xtra(tagi_t const lst[], size_t offset)
{
    size_t xtra = offset;

    for (; lst; lst = t_next(lst))
        xtra += t_xtra(lst, xtra);

    return xtra - offset;
}
Пример #8
0
/**Move a tag list.
 *
 * The function tl_move() copies the tag list @a src to the buffer @a
 * dst. The size of the @a dst list must be at least @c tl_len(src) bytes.
 *
 * @param dst pointer to the destination buffer
 * @param src tag list to be moved
 *
 * @return
 * The function tl_move() returns a pointer to the @a dst list after last
 * moved element.
 */
tagi_t *tl_move(tagi_t *dst, tagi_t const src[])
{
    do {
        dst = t_move(dst, src);
    }
    while ((src = t_next(src)));

    return dst;
}
Пример #9
0
/** Calculate effective length of a tag list as bytes. */
size_t tl_len(tagi_t const lst[])
{
    size_t len = 0;

    do {
        len += t_len(lst);
    }
    while ((lst = t_next(lst)));

    return len;
}
Пример #10
0
/** Get next tag item from list.
 */
tagi_t *tl_next(tagi_t const *t)
{
    tag_type_t tt;

    t = t_next(t);

    for (tt = TAG_TYPE_OF(t); t && tt->tt_next; tt = TAG_TYPE_OF(t)) {
        t = tt->tt_next(t);
    }

    return (tagi_t *)t;
}
Пример #11
0
static void
printree(ACISM const*psp, int state, int depth, char *str,
            char const *charv, FILE*out, MEMREF const*pattv)
{
    SYMBOL sym;
    TRAN x;

    if (depth > (int)psp->maxlen) {
        fputs("oops\n", out);
        return;
    }

    x = psp->tranv[state];
    fprintf(out, "%5d:%.*s", state, depth, str);
    if (t_valid(psp,x) && t_next(psp,x))
        fprintf(out, " b=%"FX"d%s", t_next(psp,x), x & T_FLAGS ? " BAD" : "");
    fprintf(out, "\n");

    for (sym = 1; sym < psp->nsyms; ++sym) {
        x = p_tran(psp, state, sym);
        if (t_valid(psp, x)) {
            str[depth] = charv[sym];
            fprintf(out, "%*s%c %c%c",
                    depth+6, "", charv[sym],
                    x & IS_MATCH ? 'M' : '-',
                    x & IS_SUFFIX ? 'S' : '-');
            if (x & IS_MATCH && pattv && t_isleaf(psp, x))
                fprintf(out, " %.0d -> %.*s", PSTR(psp, t_strno(psp,x), pattv));
            if (x & IS_SUFFIX)
                fprintf(out, " ->S %"FX"d", t_next(psp, psp->tranv[state]));
            fprintf(out, "\n");
            if (!t_isleaf(psp, x))
                printree(psp, t_next(psp, x), depth+1, str, charv, out, pattv);
        }
    }
}
Пример #12
0
static int tl_get(tag_type_t tt, void *p, tagi_t const lst[])
{
    tagi_t const *t, *latest = NULL;

    assert(tt);

    if (tt == NULL || p == NULL)
        return 0;

    if (tt->tt_class == ref_tag_class)
        tt = (tag_type_t)tt->tt_magic;

    for (t = t_find(tt, lst); t; t = t_find(tt, t_next(t)))
        latest = t;

    return t_ref_set(tt, p, latest);
}
Пример #13
0
/** Remove listed tags from the list @a lst. */
int tl_tremove(tagi_t lst[], tag_type_t tag, tag_value_t value, ...)
{
    tagi_t *l, *l_next;
    int retval = 0;
    ta_list ta;

    ta_start(ta, tag, value);

    for (l = lst; l; l = l_next) {
        if ((l_next = (tagi_t *)t_next(l))) {
            if (tl_find(ta_args(ta), l->t_tag))
                l->t_tag = tag_skip;
            else
                retval++;
        }
    }

    ta_end(ta);

    return retval;
}
Пример #14
0
int
acism_lookup(ac_trie_t const *psp, const char *text, size_t len,
           ACISM_ACTION *cb, void *context, int *statep, bool caseless)
{
    ac_trie_t const ps = *psp;
    char const *cp = text, *endp = cp + len;
    uint8_t s;
    STATE state = *statep;
    int ret = 0;

    while (cp < endp) {
    	s = caseless ? g_ascii_tolower (*cp++) : *cp++;
        _SYMBOL sym = ps.symv[s];
        if (!sym) {
            // Input byte is not in any pattern string.
            state = ROOT;
            continue;
        }

        // Search for a valid transition from this (state, sym),
        //  following the backref chain.

        TRAN next;
        while (!t_valid(&ps, next = p_tran(&ps, state, sym)) && state != ROOT) {
            TRAN back = p_tran(&ps, state, BACK);
            state = t_valid(&ps, back) ? t_next(&ps, back) : ROOT;
        }

        if (!t_valid(&ps, next))
            continue;

        if (!(next & (IS_MATCH | IS_SUFFIX))) {
            // No complete match yet; keep going.
            state = t_next(&ps, next);
            continue;
        }

        // At this point, one or more patterns have matched.
        // Find all matches by following the backref chain.
        // A valid node for (sym) with no SUFFIX flag marks the
        //  end of the suffix chain.
        // In the same backref traversal, find a new (state),
        //  if the original transition is to a leaf.

        STATE s = state;

        // Initially state is ROOT. The chain search saves the
        //  first state from which the next char has a transition.
        state = t_isleaf(&ps, next) ? 0 : t_next(&ps, next);

        while (1) {

            if (t_valid(&ps, next)) {

                if (next & IS_MATCH) {
                    unsigned strno, ss = s + sym, i;
                    if (t_isleaf(&ps, ps.tranv[ss])) {
                        strno = t_strno(&ps, ps.tranv[ss]);
                    } else {
                        for (i = p_hash(&ps, ss); ps.hashv[i].state != ss; ++i);
                        strno = ps.hashv[i].strno;
                    }

                    if ((ret = cb(strno, cp - text, context)))
                        goto EXIT;
                }

                if (!state && !t_isleaf(&ps, next))
                    state = t_next(&ps, next);
                if ( state && !(next & IS_SUFFIX))
                    break;
            }

            if (s == ROOT)
                break;

            TRAN b = p_tran(&ps, s, BACK);
            s = t_valid(&ps, b) ? t_next(&ps, b) : ROOT;
            next = p_tran(&ps, s, sym);
        }
    }
EXIT:
	*statep = state;
    return ret;
}
Пример #15
0
/**Initialize client request for sending.
 *
 * This function is called when the request is taken from queue and sent.
 *
 * @retval 0 if request is pending
 * @retval >=1 if error event has been sent
 */
static
int nua_client_init_request0(nua_client_request_t *cr)
{
  nua_handle_t *nh = cr->cr_owner;
  nua_t *nua = nh->nh_nua;
  nua_dialog_state_t *ds = nh->nh_ds;
  msg_t *msg = NULL;
  sip_t *sip;
  url_string_t const *url = NULL;
  tagi_t const *t;
  int has_contact = 0;
  int error = 0;

  if (!cr->cr_method_name)
    return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), NULL);

  if (cr->cr_msg)
    return nua_client_request_try(cr);

  cr->cr_answer_recv = 0, cr->cr_offer_sent = 0;
  cr->cr_offer_recv = 0, cr->cr_answer_sent = 0;
  cr->cr_terminated = 0, cr->cr_graceful = 0;

  nua_stack_init_handle(nua, nh, cr->cr_tags);

  if (cr->cr_method == sip_method_cancel) {
    if (cr->cr_methods->crm_init) {
      error = cr->cr_methods->crm_init(cr, NULL, NULL, cr->cr_tags);
      if (error)
	return error;
    }

    if (cr->cr_methods->crm_send)
      return cr->cr_methods->crm_send(cr, NULL, NULL, cr->cr_tags);
    else
      return nua_base_client_request(cr, NULL, NULL, cr->cr_tags);
  }

  if (!cr->cr_methods->crm_template ||
      cr->cr_methods->crm_template(cr, &msg, cr->cr_tags) == 0)
    msg = nua_client_request_template(cr);

  sip = sip_object(msg);
  if (!sip)
    return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);

  if (nh->nh_tags) {
    for (t = nh->nh_tags; t; t = t_next(t)) {
      if (t->t_tag == siptag_contact ||
	  t->t_tag == siptag_contact_str)
	has_contact = 1;
      else if (t->t_tag == nutag_url)
	url = (url_string_t const *)t->t_value;
    }
  }

  /**@par Populating SIP Request Message with Tagged Arguments
   *
   * The tagged arguments can be used to pass values for any SIP headers
   * to the stack. When the INVITE message (or any other SIP message) is
   * created, the tagged values saved with nua_handle() are used first,
   * next the tagged values given with the operation (nua_invite()) are
   * added.
   *
   * When multiple tags for the same header are specified, the behaviour
   * depends on the header type. If only a single header field can be
   * included in a SIP message, the latest non-NULL value is used, e.g.,
   * @Subject. However, if the SIP header can consist of multiple lines or
   * header fields separated by comma, e.g., @Accept, all the tagged
   * values are concatenated.
   *
   * However, if a tag value is #SIP_NONE (-1 casted as a void pointer),
   * the values from previous tags are ignored.
   */
  for (t = cr->cr_tags; t; t = t_next(t)) {
    if (t->t_tag == siptag_contact ||
	t->t_tag == siptag_contact_str)
      has_contact = 1;
    else if (t->t_tag == nutag_url)
      url = (url_string_t const *)t->t_value;
    else if (t->t_tag == nutag_dialog) {
      cr->cr_dialog = t->t_value > 1;
      cr->cr_contactize = t->t_value >= 1;
    }
    else if (t->t_tag == nutag_auth && t->t_value) {
      /* XXX ignoring errors */
      if (nh->nh_auth)
	auc_credentials(&nh->nh_auth, nh->nh_home, (char *)t->t_value);
    }
  }

  if (cr->cr_method == sip_method_register && url == NULL)
    url = (url_string_t const *)NH_PGET(nh, registrar);

  if ((t = cr->cr_tags)) {
    if (sip_add_tagis(msg, sip, &t) < 0)
      return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);
  }

  /**
   * Now, the target URI for the request needs to be determined.
   *
   * For initial requests, values from tags are used. If NUTAG_URL() is
   * given, it is used as target URI. Otherwise, if SIPTAG_TO() is given,
   * it is used as target URI. If neither is given, the complete request
   * line already specified using SIPTAG_REQUEST() or SIPTAG_REQUEST_STR()
   * is used. At this point, the target URI is stored in the request line,
   * together with method name and protocol version ("SIP/2.0"). The
   * initial dialog information is also created: @CallID, @CSeq headers
   * are generated, if they do not exist, and a tag is added to the @From
   * header.
   */

  if (!ds->ds_leg) {
    if (ds->ds_remote_tag && ds->ds_remote_tag[0] &&
	sip_to_tag(nh->nh_home, sip->sip_to, ds->ds_remote_tag) < 0)
      return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);

    if (sip->sip_from == NULL &&
	sip_add_dup(msg, sip, (sip_header_t *)nua->nua_from) < 0)
      return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);

    if (sip->sip_to == NULL && cr->cr_method == sip_method_register &&
      sip_add_dup_as(msg, sip, sip_to_class,
		     (sip_header_t *)sip->sip_from) < 0) {
      return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);
    }
  }
  else {
    if (ds->ds_route)
      url = NULL;
  }

  if (url && nua_client_set_target(cr, (url_t *)url) < 0)
    return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);

  cr->cr_has_contact = has_contact;

  if (cr->cr_methods->crm_init) {
    error = cr->cr_methods->crm_init(cr, msg, sip, cr->cr_tags);
    if (error < -1)
      msg = NULL;
    if (error < 0)
      return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);
    if (error != 0)
      return error;
  }

  cr->cr_msg = msg;
  cr->cr_sip = sip;

  return nua_client_request_try(cr);
}