Commit 6600b56e authored by Pekka Pessi's avatar Pekka Pessi

msg_parser_util.c: added msg_header_join_items().

Now parser updates header when it adds items to a list header.

darcs-hash:20061213030544-65a35-7174c52b4e09440844d5657cc125a757175c62a3.gz
parent 8fdb23ec
......@@ -1190,9 +1190,8 @@ msg_header_t *error_header_parse(msg_t *msg, msg_pub_t *mo,
/** Complete this header field and parse next header field.
*
* This function completes parsing a multi-field header like @Accept,
* @Contact, @Via or @Warning. It updates the shortcuts to header parameters
* (see msg_header_update_params()) and then scans for the next header field.
* If one is found, it calls the parsing function recursively.
* @Contact, @Via or @Warning. It scans for the next header field and
* if one is found, it calls the parsing function recursively.
*
* @param home memory home used ot allocate
* new header structures and parameter lists
......@@ -1214,38 +1213,26 @@ issize_t msg_parse_next_field(su_home_t *home, msg_header_t *prev,
msg_header_t *h;
char *end = s + slen;
if (hc->hc_update && hc->hc_params) {
/* Update shortcuts to parameters */
msg_param_t p, v, *params;
params = *(msg_param_t **)((char *)prev + hc->hc_params);
if (params) {
for (p = *params; p; p = *++params) {
size_t n = strcspn(p, "=");
v = p + n + (p[n] == '=');
if (hc->hc_update(prev->sh_common, p, n, v) < 0)
return -1;
}
}
}
if (*s && *s != ',')
return -1;
if (msg_header_update_params(prev->sh_common, 0) < 0)
return -1;
while (*s == ',') /* Skip comma and following whitespace */
*s = '\0', s += span_lws(s + 1) + 1;
if (*s == 0)
return 0;
h = msg_header_alloc(home, prev->sh_class, 0);
h = msg_header_alloc(home, hc, 0);
if (!h)
return -1;
prev->sh_succ = h, h->sh_prev = &prev->sh_succ;
prev->sh_next = h;
return prev->sh_class->hc_parse(home, h, s, end - s);
return hc->hc_parse(home, h, s, end - s);
}
/** Decode a message header. */
......@@ -2524,6 +2511,10 @@ append_parsed(msg_t *msg, msg_pub_t *mo, msg_href_t const *hr, msg_header_t *h,
*hh = h;
}
static int _msg_header_add_list_items(msg_t *msg,
msg_header_t **hh,
msg_header_t const *src);
/**Duplicate and add a (list of) header(s) to the message.
*
* The function @c msg_header_add_dup() duplicates and adds a (list of)
......@@ -2588,24 +2579,8 @@ int msg_header_add_dup(msg_t *msg,
hh = &h->sh_next;
}
else {
/* Add list items */
msg_header_t *h = *hh;
msg_param_t **d, **s;
d = msg_header_params(h->sh_common); assert(d);
s = msg_header_params(src->sh_common);
if (!s || !*s)
return 0;
msg_fragment_clear(h->sh_common);
/* Remove empty headers */
for (hh = &h->sh_next; *hh; *hh = (*hh)->sh_next)
msg_chain_remove(msg, *hh);
if (msg_params_join(msg_home(msg), d, *s, 2 /* prune case */, 1) < 0)
return -1;
if (_msg_header_add_list_items(msg, hh, src) < 0)
break;
}
}
......@@ -2661,25 +2636,8 @@ int _msg_header_add_dup_as(msg_t *msg,
if (hh == NULL)
return -1;
if (*hh && hc->hc_kind == msg_kind_list) {
/* Add list items */
msg_header_t *h = *hh;
msg_param_t **d, **s;
d = msg_header_params(h->sh_common); assert(d);
s = msg_header_params(src->sh_common);
if (!s || !*s)
return 0;
msg_fragment_clear(h->sh_common);
/* Remove empty headers */
for (hh = &h->sh_next; *hh; *hh = (*hh)->sh_next)
msg_chain_remove(msg, *hh);
return msg_params_join(msg_home(msg), d, *s, 2 /* prune case */, 1);
}
if (*hh && hc->hc_kind == msg_kind_list)
return _msg_header_add_list_items(msg, hh, src);
if (!(h = msg_header_dup_as(msg_home(msg), hc, src)))
return -1;
......@@ -2687,6 +2645,30 @@ int _msg_header_add_dup_as(msg_t *msg,
return msg_header_add(msg, pub, hh, h);
}
/* Add list items */
static int _msg_header_add_list_items(msg_t *msg,
msg_header_t **hh,
msg_header_t const *src)
{
msg_header_t *h = *hh;
msg_param_t **s = msg_header_params(src->sh_common);
if (!s || !*s)
return 0;
msg_fragment_clear(h->sh_common);
/* Remove empty headers */
for (hh = &h->sh_next; *hh; *hh = (*hh)->sh_next)
msg_chain_remove(msg, *hh);
if (msg_header_join_items(msg_home(msg), h->sh_common, src->sh_common)
< 0)
return -1;
return 0;
}
/** Parse a string as a given header field and add result to the message. */
int msg_header_add_make(msg_t *msg,
msg_pub_t *pub,
......
......@@ -1055,22 +1055,26 @@ int msg_header_remove_param(msg_common_t *h, char const *name)
*/
int msg_header_update_params(msg_common_t *h, int clear)
{
msg_hclass_t *hc;
unsigned char offset;
msg_update_f *update;
int retval;
msg_param_t const *params;
size_t n;
char const *p, *v;
if (h == NULL)
return errno = EFAULT, -1;
if (h->h_class->hc_params == 0 ||
h->h_class->hc_update == NULL)
hc = h->h_class; offset = hc->hc_params; update = hc->hc_update;
if (offset == 0 || update == NULL)
return 0;
if (clear)
h->h_class->hc_update(h, NULL, 0, NULL);
update(h, NULL, 0, NULL);
params = *(msg_param_t **)((char *)h + h->h_class->hc_params);
params = *(msg_param_t **)((char *)h + offset);
if (params == NULL)
return 0;
......@@ -1079,7 +1083,7 @@ int msg_header_update_params(msg_common_t *h, int clear)
for (p = *params; p; p = *++params) {
n = strcspn(p, "=");
v = p + n + (p[n] == '=');
if (h->h_class->hc_update(h, p, n, v) < 0)
if (update(h, p, n, v) < 0)
retval = -1;
}
......@@ -1503,6 +1507,105 @@ issize_t msg_params_join(su_home_t *home,
return 0;
}
/**Join header item lists.
*
* Add a item list to a header. Do not add entries already in list.
* Do duplicate items.
*
* @param home memory home
* @param h destination header
* @param src parameters to add to the list
*
* @return
* @retval >= 0 when successful
* @retval -1 upon an error
*/
int msg_header_join_items(su_home_t *home,
msg_common_t *h,
msg_common_t const *src_h)
{
size_t n, n0, m, i, n_before, n_after, pruned, total;
char *dup;
msg_param_t *d, **dd, *src;
msg_update_f *update = NULL;
if (h == NULL || src_h == NULL)
return -1;
if (h->h_class->hc_params == 0 ||
src_h->h_class->hc_params == 0)
return -1;
update = h->h_class->hc_update;
dd = (msg_param_t **)((char *)h + h->h_class->hc_params);
d = *dd;
src = *(msg_param_t **)((char *)src_h + src_h->h_class->hc_params);
/* Count number of parameters */
for (n = 0; d && d[n]; n++)
;
for (m = 0, pruned = 0; src[m]; m++) {
for (i = 0; i < n; i++) {
if (strcmp(d[i], src[m]) == 0) {
pruned++;
break;
}
}
total += strlen(src[m]) + 1;
}
if (total == 0)
return 0;
dup = su_alloc(home, total); if (!dup) return -1;
n0 = n;
n_before = MSG_PARAMS_NUM(n + 1);
n_after = MSG_PARAMS_NUM(n + m - pruned + 1);
if (n_before != n_after || !d) {
d = su_alloc(home, n_after * sizeof(*d));
if (!d)
return (void)su_free(home, dup), -1;
if (n)
memcpy(d, *dd, n * sizeof(*d));
*dd = d;
}
for (m = 0; src[m]; m++) {
size_t len = strlen(src[m]) + 1;
if (pruned > 0) {
for (i = 0; i < n; i++)
if (memcmp(d[i], src[m], len) == 0)
break;
if (i < n) {
if (i < n0)
pruned--;
continue;
}
}
d[n] = memcpy(dup, src[m], len); dup += len;
if (update) {
char const *p = src[m];
size_t n = strcspn(p, "=");
char const *v = p + n + (p[n] == '=');
update(h, p, n, v);
}
n++;
}
d[n] = NULL;
return 0;
}
/**Compare parameter lists.
*
* Compares parameter lists.
......
......@@ -233,6 +233,10 @@ SOFIAPUBFUN int msg_header_replace_item(su_home_t *, msg_common_t *h,
char const *item);
SOFIAPUBFUN int msg_header_remove_item(msg_common_t *h, char const *name);
SOFIAPUBFUN int msg_header_join_items(su_home_t *home,
msg_common_t *h,
msg_common_t const *src_h);
/** Append a list of constant items to a list. */
SOFIAPUBFUN int msg_list_append_items(su_home_t *home, msg_list_t *k,
msg_param_t const items[]);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment