📄 msg_mime.c
字号:
while (p[0] == ' ') p++; p += p[0] == '\r' ? 1 + (p[1] == '\n') : (p[0] == '\n'); len = end - p; if (len < blen) break; next = memmem(p, len, boundary + 1, m = blen); if (!next) break; /* error */ if (next != p && next[-1] == '\r') next--, m++; mp = (msg_multipart_t *)msg_header_alloc(msg_home(msg), msg_multipart_class, 0); if (mp == NULL) break; /* error */ *mmp = mp; mmp = &mp->mp_next; /* Put delimiter transport-padding CRLF here */ mp->mp_common->h_data = b; mp->mp_common->h_len = p - b; /* .. and body-part here */ mp->mp_data = p; mp->mp_len = next - p; if (next[m] == '-' && next[m + 1] == '-') { /* We found close-delimiter */ assert(mp); if (!mp) break; /* error */ mp->mp_close_delim = (msg_payload_t *) msg_header_alloc(msg_home(msg), msg_payload_class, 0); if (!mp->mp_close_delim) break; /* error */ /* Include also transport-padding and epilogue in the close-delimiter */ mp->mp_close_delim->pl_data = next; mp->mp_close_delim->pl_len = p + len - next; break; } b = next; p = next + m; } if (!mp || !mp->mp_close_delim) { su_home_deinit(msg_home(msg)); /* Delimiter error */ return NULL; } /* Parse each part */ for (mp = all; mp; mp = mp->mp_next) { msg->m_object = (msg_pub_t *)mp; p = mp->mp_data; next = p + mp->mp_len; if (msg->m_tail) mp->mp_common->h_prev = msg->m_tail, *msg->m_tail = (msg_header_t *)mp; msg->m_chain = (msg_header_t *)mp; msg->m_tail = &mp->mp_common->h_succ; save = *next; *next = '\0'; /* NUL-terminate this part */ for (len = next - p; len > 0; len -= m, p += m) { if (IS_CRLF(p[0])) { m = msg_extract_separator(msg, (msg_pub_t*)mp, p, len, 1); assert(m > 0); p += m; len -= m; if (len > 0) { m = msg_extract_payload(msg, (msg_pub_t*)mp, NULL, len, p, len, 1); assert(m > 0); assert(len == m); } break; } m = msg_extract_header(msg, (msg_pub_t*)mp, p, len, 1); if (m <= 0) { assert(m > 0); /* Xyzzy */ } } *next = save; /* XXX - Should we leave the payload NUL-terminated? */ } /* Postprocess */ blen = strlen(boundary); for (mp = all; mp; mp = mp->mp_next) { mp->mp_data = boundary; mp->mp_len = blen; assert(mp->mp_payload || mp->mp_separator); if (mp->mp_close_delim) { msg_header_t **tail; if (mp->mp_payload) tail = &mp->mp_payload->pl_common->h_succ; else tail = &mp->mp_separator->sep_common->h_succ; assert(msg->m_chain == (msg_header_t *)mp); assert(*tail == NULL); mp->mp_close_delim->pl_common->h_prev = tail; *tail = (msg_header_t *)mp->mp_close_delim; } } 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. * * The function msg_multipart_complete() adds missing components to the * multipart message. The missing components may include boundaries between * body parts, separators between body-part headers and data, and * close-delimiter after last body-part. * * @param home home for allocating structures [IN/OUT] * @param c content-type header for multipart [IN/OUT] * @param mp pointer to first multipart structure [IN/OUT] * * @return * The function msg_multipart_complete() returns 0 when successful, * -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; int 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\"", m, b); } else { strcpy(token, "boundary="); msg_random_token(token + strlen("boundary="), 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, 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_header_t **)&mp->mp_content_type; hh < (msg_header_t **)&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. */int 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. */int msg_multipart_d(su_home_t *home, msg_header_t *h, char *s, int 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. */int msg_multipart_e(char b[], int bsiz, msg_header_t const *h, int flags){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -