/** 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; }
/** 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; }
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); } }
/** 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; }
/** 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; }
/** 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; }
/** 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; }
/**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; }
/** 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; }
/** 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; }
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); } } }
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); }
/** 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; }
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; }
/**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); }