📄 msg_mime.c
字号:
msg_fragment_clear(pl->pl_common); pl->pl_len = all->mp_data - (char *)pl->pl_data; su_home_move(home, msg_home(msg)); su_home_deinit(msg_home(msg)); return all;}/**Add all missing parts to the multipart. * * Add missing components such as boundaries between body parts, separators * between body-part headers and data, and close-delimiter after last * body-part to the multipart message. * * @param[in,out] home home for allocating structures * @param[in,out] c content-type header for multipart * @param[in,out] mp pointer to first multipart structure * * @retval 0 when successful * @retval -1 upon an error * * @ERRORS * @ERROR EBADMSG * The @b Content-Type header @a c is malformed, or multipart message * contains a malformed @b Content-Type header. * @ERROR ENOMEM * A memory allocation failed. * @ERROR EINVAL * The function msg_multipart_complete() was given invalid arguments. */int msg_multipart_complete(su_home_t *home, msg_content_type_t *c, msg_multipart_t *mp){ char *boundary; char const *b; size_t blen, m; if (c == NULL || mp == NULL) return (errno = EINVAL), -1; if (!(b = msg_header_find_param(c->c_common, "boundary="))) { /* Generate boundary */ enum { tlen = 16 * 4 / 3 }; char token[sizeof("boundary=") + tlen + 1]; if (mp->mp_data) { b = mp->mp_data; m = mp->mp_len; if (strncmp(b, CR LF "--", 4) == 0) b += 4, m -= 4; else if (strncmp(b, "--", 2) == 0) b += 2, m -= 2; else return (errno = EBADMSG), -1; /* XXX - quoting? */ b = su_sprintf(home, "boundary=\"%.*s\"", (int)m, b); } else { strcpy(token, "boundary="); msg_random_token(token + strlen("boundary="), (size_t)tlen, NULL, 0); b = su_strdup(home, token); } if (!b) return -1; msg_params_replace(home, (msg_param_t **)&c->c_params, b); b += strlen("boundary="); } if (!(boundary = msg_multipart_boundary(home, b))) return -1; blen = strlen(boundary); m = blen - 2; for (; mp; mp = mp->mp_next) { if (mp->mp_data == NULL) { mp->mp_data = boundary, mp->mp_len = blen; } else { if (mp->mp_len < 3) return -1; if (mp->mp_data[0] == '\r' && mp->mp_data[1] == '\n') { if (mp->mp_len < m || memcmp(mp->mp_data + 2, boundary + 2, m - 2)) return -1; } else if (mp->mp_data[0] == '\n') { if (mp->mp_len < m - 1 || memcmp(mp->mp_data + 1, boundary + 2, m - 2)) return -1; } else { if (mp->mp_len < m - 2 || memcmp(mp->mp_data, boundary + 2, m - 2)) return -1; } } if (mp->mp_next == NULL) { if (!mp->mp_close_delim) mp->mp_close_delim = msg_payload_format(home, "%.*s--" CR LF, (int)m, boundary); if (!mp->mp_close_delim) return -1; } else if (mp->mp_close_delim) { msg_payload_t *e = mp->mp_close_delim; mp->mp_close_delim = NULL; if (e->pl_common->h_prev) *e->pl_common->h_prev = e->pl_common->h_succ; if (e->pl_common->h_succ) e->pl_common->h_succ->sh_prev = e->pl_common->h_prev; } mp->mp_common->h_data = mp->mp_data; mp->mp_common->h_len = mp->mp_len; if (!mp->mp_separator) if (!(mp->mp_separator = msg_separator_make(home, CR LF))) return -1; if (mp->mp_multipart) { c = mp->mp_content_type; if (c == NULL) return (errno = EBADMSG), -1; if (msg_multipart_complete(home, c, mp->mp_multipart) < 0) return -1; } if (!mp->mp_payload) if (!(mp->mp_payload = msg_payload_create(home, NULL, 0))) return -1; } return 0;}/** Serialize a multipart message. * */msg_header_t *msg_multipart_serialize(msg_header_t **head0, msg_multipart_t *mp){ msg_header_t *h_succ_all = NULL; msg_header_t *h, **head, **hh, *h0, *h_succ; void *hend;#define is_in_chain(h) ((h) && ((msg_frg_t*)(h))->h_prev != NULL)#define insert(head, h) \ ((h)->sh_succ = *(head), *(head) = (h), \ (h)->sh_prev = (head), (head) = &(h)->sh_succ) if (mp == NULL || head0 == NULL) return NULL; h_succ_all = *head0; head = head0; for (; mp; mp = mp->mp_next) { h0 = (msg_header_t *)mp; assert(mp->mp_separator); assert(mp->mp_payload); assert(mp->mp_next || mp->mp_close_delim); if (!mp->mp_separator || !mp->mp_payload || (!mp->mp_next && !mp->mp_close_delim)) return NULL; if ((void *)mp == h_succ_all) h_succ_all = NULL; *head0 = h0; h0->sh_prev = head; if (is_in_chain(mp->mp_separator)) hend = mp->mp_separator; else if (is_in_chain(mp->mp_payload)) hend = mp->mp_payload; else if (is_in_chain(mp->mp_multipart)) hend = mp->mp_multipart; else if (is_in_chain(mp->mp_close_delim)) hend = mp->mp_close_delim; else if (is_in_chain(mp->mp_next)) hend = mp->mp_next; else hend = NULL; /* Search latest header in chain */ for (head = &mp->mp_common->h_succ; *head && *head != hend; head = &(*head)->sh_succ) ; h_succ = *head; /* Serialize headers */ for (hh = &((msg_pub_t*)mp)->msg_request; (char *)hh < (char *)&mp->mp_separator; hh++) { h = *hh; if (!h) continue; for (h = *hh; h; h = h->sh_next) { if (h == h_succ || !is_in_chain(h)) { *head = h; h->sh_prev = head; head = &h->sh_succ; while (*head && *head != hend) head = &(*head)->sh_succ; if (h == h_succ) h_succ = *head; } else { /* XXX Check that h is between head and hend */ } } } if (!is_in_chain(mp->mp_separator)) { insert(head, (msg_header_t *)mp->mp_separator); } else { assert(h_succ == (msg_header_t *)mp->mp_separator); mp->mp_separator->sep_common->h_prev = head; *head = (msg_header_t *)mp->mp_separator; head = &mp->mp_separator->sep_common->h_succ; h_succ = *head; } if (!is_in_chain(mp->mp_payload)) { insert(head, (msg_header_t *)mp->mp_payload); } else { assert(h_succ == (msg_header_t *)mp->mp_payload); mp->mp_payload->pl_common->h_prev = head; *head = (msg_header_t *)mp->mp_payload; head = &mp->mp_payload->pl_common->h_succ; h_succ = *head; } if (mp->mp_multipart) { if ((*head = h_succ)) h_succ->sh_prev = head; if (!(h = msg_multipart_serialize(head, mp->mp_multipart))) return NULL; head = &h->sh_succ; h_succ = *head; } if (mp->mp_close_delim) { if (!is_in_chain(mp->mp_close_delim)) { insert(head, (msg_header_t*)mp->mp_close_delim); } else { assert(h_succ == (msg_header_t *)mp->mp_close_delim); mp->mp_close_delim->pl_common->h_prev = head; *head = (msg_header_t *)mp->mp_close_delim; head = &mp->mp_close_delim->pl_common->h_succ; } if (h_succ_all) *head = h_succ_all, h_succ_all->sh_prev = head; return (msg_header_t *)mp->mp_close_delim; } *head = h_succ; head0 = head; } assert(!mp); return NULL;}/** Encode a multipart. * * @return The size of multipart in bytes, or -1 upon an error. */issize_t msg_multipart_prepare(msg_t *msg, msg_multipart_t *mp, int flags){ if (!mp || !mp->mp_data) return -1; if (!mp->mp_common->h_data || mp->mp_common->h_len != mp->mp_len - 2 || memcmp(mp->mp_common->h_data, mp->mp_data + 2, mp->mp_len - 2)) { mp->mp_common->h_data = mp->mp_data + 2; mp->mp_common->h_len = mp->mp_len - 2; } return msg_headers_prepare(msg, (msg_header_t *)mp, flags);}/** Decode a multipart. */issize_t msg_multipart_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen){ su_home_t tmphome[1] = { SU_HOME_INIT(tmphome) }; msg_payload_t pl[1]; msg_multipart_t *mp, *result; assert(h && msg_is_multipart(h)); msg_payload_init(pl); result = (msg_multipart_t *)h; pl->pl_data = s; pl->pl_len = slen; mp = msg_multipart_parse(tmphome, NULL, pl); if (mp) { *result = *mp; if (result->mp_common->h_succ->sh_prev) result->mp_common->h_succ->sh_prev = &result->mp_common->h_succ; su_free(tmphome, mp); su_home_move(home, tmphome); } su_home_deinit(tmphome); return mp ? 0 : -1;}/** Encode a multipart. * * Please note that here we just encode a element, the msg_multipart_t * itself. */issize_t msg_multipart_e(char b[], isize_t bsiz, msg_header_t const *h, int flags){ return msg_payload_e(b, bsiz, h, flags);}/** Calculate extra size of a multipart */isize_t msg_multipart_dup_xtra(msg_header_t const *h, isize_t offset){ msg_multipart_t const *mp = (msg_multipart_t *)h; msg_header_t const * const *hh; offset = msg_payload_dup_xtra(h, offset); for (hh = (msg_header_t const **)&((msg_pub_t *)mp)->msg_request; (char *)hh <= (char *)&mp->mp_close_delim; hh++) { for (h = *hh; h; h = h->sh_next) { MSG_STRUCT_SIZE_ALIGN(offset); offset = h->sh_class->hc_dxtra(h, offset + h->sh_class->hc_size); } } return offset;}/** Duplicate one msg_multipart_t object */char *msg_multipart_dup_one(msg_header_t *dst, msg_header_t const *src, char *b, isize_t xtra){ msg_multipart_t const *mp = (msg_multipart_t *)src; msg_header_t *h, **hh; char *end = b + xtra; b = msg_payload_dup_one(dst, src, b, xtra); for (hh = &((msg_pub_t*)mp)->msg_request; (char *)hh <= (char *)&mp->mp_close_delim; hh++) { for (h = *hh; h; h = h->sh_next) { MSG_STRUCT_ALIGN(b); dst = (msg_header_t *)b; memset(dst, 0, sizeof dst->sh_common); dst->sh_class = h->sh_class; b = h->sh_class->hc_dup_one(dst, h, b + h->sh_class->hc_size, end - b); if (h->sh_class->hc_update) msg_header_update_params(h->sh_common, 0); assert(b <= end); } } return b;}#if 0msg_hclass_t msg_multipart_class[] =MSG_HEADER_CLASS(msg_, multipart, NULL, "", mp_common, append, msg_multipart);#endif/**Calculate Q value. * * The function msg_q_value() converts q-value string @a q to numeric value * in range (0..1000). Q values are used, for instance, to describe * relative priorities of registered contacts. * * @param q q-value string ("1" | "." 1,3DIGIT) * * @return * The function msg_q_value() returns an integer in range 0 .. 1000. */unsigned msg_q_value(char const *q){ unsigned value = 0; if (!q) return 500; if (q[0] != '0' && q[0] != '.' && q[0] != '1') return 500; while (q[0] == '0') q++; if (q[0] >= '1' && q[0] <= '9') return 1000; if (q[0] == '\0') return 0; if (q[0] != '.') /* Garbage... */ return 500; if (q[1] >= '0' && q[1] <= '9') { value = (q[1] - '0') * 100; if (q[2] >= '0' && q[2] <= '9') { value += (q[2] - '0') * 10; if (q[3] >= '0' && q[3] <= '9') { value += (q[3] - '0'); if (q[4] > '5' && q[4] <= '9') /* Round upwards */ value += 1; else if (q[4] == '5') value += value & 1; /* Round to even */ } } } return value;}/** Parse media type (type/subtype). * * The function msg_mediatype_d() parses a mediatype string. * * @param[in,out] ss string to be parsed * @param[out] type value result for media type * * @retval 0 when successful, * @retval -1 upon an error. */issize_t msg_mediatype_d(char **ss, char const **type){ char *s = *ss; char const *result = s; size_t l1 = 0, l2 = 0, n; /* Media type consists of two tokens, separated by / */ l1 = span_token(s); for (n = l1; IS_LWS(s[n]); n++); if (s[n] == '/') { for (n++; IS_LWS(s[n]); n++); l2 = span_token(s + n); n += l2; } if (l1 == 0 || l2 == 0) return -1; /* If there is extra ws between tokens, compact version */ if (n > l1 + 1 + l2) { s[l1] = '/'; memmove(s + l1 + 1, s + n - l2, l2); s[l1 + 1 + l2] = 0; } s += n; while (IS_WS(*s)) *s++ = '\0'; *ss = s; if (type) *type = result; return 0;}/* ====================================================================== *//**@ingroup msg_mime * @defgroup msg_accept Accept Header * * The @b Accept request-header field can be used to specify certain media * types which are acceptable for the response. Its syntax is defined in * [H14.1, S20.1] as follows: * * @code * Accept = "Accept" ":" #( media-range [ accept-params ] ) * * media-range = ( "*" "/" "*" * | ( type "/" "*" ) * | ( type "/" subtype ) ) *( ";" parameter ) * * accept-params = ";" "q" "=" qvalue *( accept-extension ) * * accept-extension = ";" token [ "=" ( token | quoted-string ) ] * @endcode * *//**@ingroup msg_accept * @typedef typedef struct msg_accept_s msg_accept_t; * * The structure msg_accept_t contains representation of an @b Accept * header. * * The msg_accept_t is defined as follows: * @code * typedef struct msg_accept_s { * msg_common_t ac_common[1]; // Common fragment info * msg_accept_t *ac_next; // Pointer to next Accept header * char const *ac_type; // Pointer to type/subtype * char const *ac_subtype; // Points after first slash in type * msg_param_t const *ac_params; // List of parameters * msg_param_t ac_q; // Value of q parameter * } msg_accept_t; * @endcode */msg_hclass_t msg_accept_class[] =MSG_HEADER_CLASS(msg_, accept, "Accept", "", ac_params, apndlist, msg_accept, msg_accept);issize_t msg_accept_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen){ msg_accept_t *ac = (msg_accept_t *)h; while (*s == ',') /* Ignore empty entries (comma-whitespace) */ *s = '\0', s += span_lws(s + 1) + 1; if (*s == '\0') { /* Empty Accept list is not an error */ ac->ac_type = ac->ac_subtype = ""; return 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -