X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=lib-mime%2Frfc822parse.c;h=f6d51066ab93b78cd991cf479bd426860efbe643;hp=e9b171a6a7833e0af333eec7330937f6fb584dfc;hb=dded59764065d6d5051f3188cd691cd1a00c185e;hpb=63694769caa96f36675293e45a01e91cbe3175b4;ds=sidebyside diff --git a/lib-mime/rfc822parse.c b/lib-mime/rfc822parse.c index e9b171a..f6d5106 100644 --- a/lib-mime/rfc822parse.c +++ b/lib-mime/rfc822parse.c @@ -275,96 +275,105 @@ static PARAMETER *parse_parameters(const char *s) return res; } -void mutt_parse_content_type (char *s, BODY * ct) +void mutt_parse_content_type(char *s, BODY *ct) { - char *pc; - char *subtype; - - p_delete(&ct->subtype); - parameter_delete(&ct->parameter); - - /* First extract any existing parameters */ - if ((pc = strchr (s, ';')) != NULL) { - *pc++ = 0; - while (*pc && ISSPACE (*pc)) - pc++; - ct->parameter = parse_parameters (pc); - - /* Some pre-RFC1521 gateways still use the "name=filename" convention, - * but if a filename has already been set in the content-disposition, - * let that take precedence, and don't set it here */ - if ((pc = mutt_get_parameter ("name", ct->parameter)) != 0 - && !ct->filename) - ct->filename = m_strdup(pc); - } + char *pc; + char *subtype; + + p_delete(&ct->subtype); + parameter_delete(&ct->parameter); + + /* First extract any existing parameters */ + if ((pc = strchr(s, ';')) != NULL) { + *pc++ = '\0'; + ct->parameter = parse_parameters(vskipspaces(pc)); + + /* Some pre-RFC1521 gateways still use the "name=filename" convention, + * but if a filename has already been set in the content-disposition, + * let that take precedence, and don't set it here */ + pc = mutt_get_parameter("name", ct->parameter); + if (pc && !ct->filename) + ct->filename = m_strdup(pc); + } - /* Now get the subtype */ - if ((subtype = strchr (s, '/'))) { - *subtype++ = '\0'; - for (pc = subtype; *pc && !ISSPACE (*pc) && *pc != ';'; pc++); - *pc = '\0'; - ct->subtype = m_strdup(subtype); - } + /* Now get the subtype */ + if ((subtype = strchr (s, '/'))) { + *subtype++ = '\0'; + for (pc = subtype; *pc && !ISSPACE(*pc) && *pc != ';'; pc++); + ct->subtype = p_dupstr(subtype, pc - subtype); + } - /* Finally, get the major type */ - ct->type = mutt_check_mime_type (s); + /* Finally, get the major type */ + ct->type = mutt_check_mime_type(s); - if (ct->type == TYPEOTHER) { - ct->xtype = m_strdup(s); - } + if (ct->type == TYPEOTHER) { + ct->xtype = m_strdup(s); + } - if (ct->subtype == NULL) { - /* Some older non-MIME mailers (i.e., mailtool, elm) have a content-type - * field, so we can attempt to convert the type to BODY here. - */ - if (ct->type == TYPETEXT) - ct->subtype = m_strdup("plain"); - else if (ct->type == TYPEAUDIO) - ct->subtype = m_strdup("basic"); - else if (ct->type == TYPEMESSAGE) - ct->subtype = m_strdup("rfc822"); - else if (ct->type == TYPEOTHER) { - char buffer[SHORT_STRING]; - - ct->type = TYPEAPPLICATION; - snprintf (buffer, sizeof (buffer), "x-%s", s); - ct->subtype = m_strdup(buffer); + if (!ct->subtype) { + /* Some older non-MIME mailers (i.e., mailtool, elm) have a content-type + * field, so we can attempt to convert the type to BODY here. + */ + switch (ct->type) { + char buffer[SHORT_STRING]; + + case TYPETEXT: + ct->subtype = m_strdup("plain"); + break; + + case TYPEAUDIO: + ct->subtype = m_strdup("basic"); + break; + + case TYPEMESSAGE: + ct->subtype = m_strdup("rfc822"); + break; + + case TYPEOTHER: + ct->type = TYPEAPPLICATION; + snprintf(buffer, sizeof(buffer), "x-%s", s); + ct->subtype = m_strdup(buffer); + break; + + default: + ct->subtype = m_strdup("x-unknown"); + break; + } } - else - ct->subtype = m_strdup("x-unknown"); - } - /* Default character set for text types. */ - if (ct->type == TYPETEXT) { - if (!(pc = mutt_get_parameter ("charset", ct->parameter))) - mutt_set_parameter ("charset", option (OPTSTRICTMIME) ? "us-ascii" : - (const char *) - mutt_get_first_charset (AssumedCharset), - &ct->parameter); - } + /* Default character set for text types. */ + if (ct->type == TYPETEXT) { + pc = mutt_get_parameter("charset", ct->parameter); + if (!pc) { + mutt_set_parameter("charset", + option(OPTSTRICTMIME) ? "us-ascii" : + mutt_get_first_charset(AssumedCharset), + &ct->parameter); + } + } } -static void parse_content_disposition (char *s, BODY * ct) +static void parse_content_disposition(char *s, BODY *ct) { - PARAMETER *parms; + if (!ascii_strncasecmp(s, "inline", 6)) { + ct->disposition = DISPINLINE; + } else if (!ascii_strncasecmp(s, "form-data", 9)) { + ct->disposition = DISPFORMDATA; + } else { + ct->disposition = DISPATTACH; + } - if (!ascii_strncasecmp ("inline", s, 6)) - ct->disposition = DISPINLINE; - else if (!ascii_strncasecmp ("form-data", s, 9)) - ct->disposition = DISPFORMDATA; - else - ct->disposition = DISPATTACH; - - /* Check to see if a default filename was given */ - if ((s = strchr (s, ';')) != NULL) { - s = vskipspaces(s + 1); - if ((s = mutt_get_parameter("filename", - (parms = parse_parameters (s)))) != 0) - m_strreplace(&ct->filename, s); - if ((s = mutt_get_parameter ("name", parms)) != 0) - ct->form_name = m_strdup(s); - parameter_delete(&parms); - } + /* Check to see if a default filename was given */ + if ((s = strchr (s, ';'))) { + PARAMETER *parms = parse_parameters(vskipspaces(s)); + + if ((s = mutt_get_parameter("filename", parms))) + m_strreplace(&ct->filename, s); + if ((s = mutt_get_parameter ("name", parms))) + ct->form_name = m_strdup(s); + + parameter_delete(&parms); + } } /* args: @@ -373,94 +382,92 @@ static void parse_content_disposition (char *s, BODY * ct) * digest 1 if reading subparts of a multipart/digest, 0 * otherwise */ - -BODY *mutt_read_mime_header (FILE * fp, int digest) +BODY *mutt_read_mime_header(FILE *fp, int digest) { - BODY *p = mutt_new_body (); - char *c; - char *line = p_new(char, LONG_STRING); - ssize_t linelen = LONG_STRING; - - p->hdr_offset = ftello (fp); - - p->encoding = ENC7BIT; /* default from RFC1521 */ - p->type = digest ? TYPEMESSAGE : TYPETEXT; - p->disposition = DISPINLINE; + BODY *body = mutt_new_body (); + char *line = p_new(char, LONG_STRING); + ssize_t linelen = LONG_STRING; + char *p; + + body->hdr_offset = ftello(fp); + body->encoding = ENC7BIT; /* default from RFC1521 */ + body->disposition = DISPINLINE; + body->type = digest ? TYPEMESSAGE : TYPETEXT; + + while (mutt_read_rfc822_line(fp, &line, &linelen)) { + /* Find the value of the current header */ + if ((p = strchr(line, ':'))) { + *p++ = '\0'; + p = vskipspaces(p); + if (!*p) + continue; + } else { + debug_print (1, ("bogus MIME header: %s\n", line)); + break; + } - while (mutt_read_rfc822_line(fp, &line, &linelen)) { - /* Find the value of the current header */ - if ((c = strchr (line, ':'))) { - *c++ = 0; - c = vskipspaces(c); - if (!*c) { - debug_print (1, ("skipping empty header field: %s\n", line)); - continue; - } - } - else { - debug_print (1, ("bogus MIME header: %s\n", line)); - break; + if (!ascii_strncasecmp(line, "content-", 8)) { + if (!ascii_strcasecmp("type", line + 8)) + mutt_parse_content_type (p, body); + else if (!ascii_strcasecmp ("transfer-encoding", line + 8)) + body->encoding = mutt_check_encoding (p); + else if (!ascii_strcasecmp ("disposition", line + 8)) + parse_content_disposition(p, body); + else if (!ascii_strcasecmp ("description", line + 8)) { + m_strreplace(&body->description, p); + rfc2047_decode(&body->description); + } + } } - if (!ascii_strncasecmp ("content-", line, 8)) { - if (!ascii_strcasecmp ("type", line + 8)) - mutt_parse_content_type (c, p); - else if (!ascii_strcasecmp ("transfer-encoding", line + 8)) - p->encoding = mutt_check_encoding (c); - else if (!ascii_strcasecmp ("disposition", line + 8)) - parse_content_disposition (c, p); - else if (!ascii_strcasecmp ("description", line + 8)) { - m_strreplace(&p->description, c); - rfc2047_decode (&p->description); - } + body->offset = ftello(fp); /* Mark the start of the real data */ + if (!body->subtype) { + if (body->type == TYPETEXT) + body->subtype = m_strdup("plain"); + if (body->type == TYPEMESSAGE) + body->subtype = m_strdup("rfc822"); } - } - p->offset = ftello (fp); /* Mark the start of the real data */ - if (p->type == TYPETEXT && !p->subtype) - p->subtype = m_strdup("plain"); - else if (p->type == TYPEMESSAGE && !p->subtype) - p->subtype = m_strdup("rfc822"); - - p_delete(&line); - return (p); + p_delete(&line); + return (body); } -void mutt_parse_part (FILE * fp, BODY * b) +void mutt_parse_part(FILE *fp, BODY *b) { - char *bound = 0; - - switch (b->type) { - case TYPEMULTIPART: - bound = mutt_get_parameter ("boundary", b->parameter); - fseeko (fp, b->offset, SEEK_SET); - b->parts = mutt_parse_multipart (fp, bound, - b->offset + b->length, - ascii_strcasecmp ("digest", - b->subtype) == 0); - break; + char *bound = 0; + + switch (b->type) { + case TYPEMULTIPART: + bound = mutt_get_parameter("boundary", b->parameter); + fseeko(fp, b->offset, SEEK_SET); + b->parts = mutt_parse_multipart(fp, bound, b->offset + b->length, + !ascii_strcasecmp("digest", b->subtype)); + break; + + case TYPEMESSAGE: + if (b->subtype) { + fseeko(fp, b->offset, SEEK_SET); + + if (mutt_is_message_type(b->type, b->subtype)) { + b->parts = mutt_parse_messageRFC822(fp, b); + } else + if (!ascii_strcasecmp(b->subtype, "external-body") == 0) { + b->parts = mutt_read_mime_header(fp, 0); + } else { + return; + } + } + break; - case TYPEMESSAGE: - if (b->subtype) { - fseeko (fp, b->offset, SEEK_SET); - if (mutt_is_message_type (b->type, b->subtype)) - b->parts = mutt_parse_messageRFC822 (fp, b); - else if (ascii_strcasecmp (b->subtype, "external-body") == 0) - b->parts = mutt_read_mime_header (fp, 0); - else + default: return; } - break; - default: - return; - } - - /* try to recover from parsing error */ - if (!b->parts) { - b->type = TYPETEXT; - m_strreplace(&b->subtype, "plain"); - } + /* try to recover from parsing error */ + if (!b->parts) { + b->type = TYPETEXT; + m_strreplace(&b->subtype, "plain"); + } } /* parse a MESSAGE/RFC822 body @@ -473,27 +480,25 @@ void mutt_parse_part (FILE * fp, BODY * b) * * NOTE: this assumes that `parent->length' has been set! */ - -BODY *mutt_parse_messageRFC822 (FILE * fp, BODY * parent) +BODY *mutt_parse_messageRFC822(FILE * fp, BODY * parent) { - BODY *msg; + BODY *msg; + + parent->hdr = header_new(); + parent->hdr->offset = ftello(fp); + parent->hdr->env = mutt_read_rfc822_header(fp, parent->hdr, 0, 0); - parent->hdr = header_new(); - parent->hdr->offset = ftello (fp); - parent->hdr->env = mutt_read_rfc822_header (fp, parent->hdr, 0, 0); - msg = parent->hdr->content; + msg = parent->hdr->content; - /* ignore the length given in the content-length since it could be wrong - and we already have the info to calculate the correct length */ - /* if (msg->length == -1) */ - msg->length = parent->length - (msg->offset - parent->offset); + /* ignore the length given in the content-length since it could be wrong + and we already have the info to calculate the correct length */ + /* if (msg->length == -1) */ + /* if body of this message is empty, we can end up with a negative length */ + msg->length = MAX(0, parent->length - (msg->offset - parent->offset)); - /* if body of this message is empty, we can end up with a negative length */ - if (msg->length < 0) - msg->length = 0; + mutt_parse_part(fp, msg); - mutt_parse_part (fp, msg); - return (msg); + return msg; } /* parse a multipart structure @@ -501,7 +506,7 @@ BODY *mutt_parse_messageRFC822 (FILE * fp, BODY * parent) * args: * fp stream to read from * - * boundary body separator + * bound body separator * * end_off length of the multipart body (used when the final * boundary is missing to avoid reading too far) @@ -509,188 +514,154 @@ BODY *mutt_parse_messageRFC822 (FILE * fp, BODY * parent) * digest 1 if reading a multipart/digest, 0 otherwise */ -BODY *mutt_parse_multipart (FILE * fp, const char *boundary, off_t end_off, - int digest) +BODY * +mutt_parse_multipart(FILE *fp, const char *bound, off_t end_off, int digest) { - int blen, len, crlf = 0; - char buffer[LONG_STRING]; - BODY *head = 0, *last = 0, *new = 0; - int i; - int final = 0; /* did we see the ending boundary? */ + char buffer[LONG_STRING]; + BODY *head = NULL; + BODY **last = &head; + int blen = m_strlen(bound); + int final = 0; /* did we see the ending boundary? */ + + if (!blen) { + mutt_error _("multipart message has no boundary parameter!"); + return NULL; + } - if (!boundary) { - mutt_error _("multipart message has no boundary parameter!"); + while (ftello(fp) < end_off && fgets(buffer, sizeof(buffer), fp)) { + int len, crlf, i; - return (NULL); - } + len = m_strlen(buffer); + crlf = len > 1 && buffer[len - 2] == '\r'; - blen = m_strlen(boundary); - while (ftello (fp) < end_off && fgets (buffer, LONG_STRING, fp) != NULL) { - len = m_strlen(buffer); - - crlf = (len > 1 && buffer[len - 2] == '\r') ? 1 : 0; - - if (buffer[0] == '-' && buffer[1] == '-' && - m_strncmp(buffer + 2, boundary, blen) == 0) { - if (last) { - last->length = ftello (fp) - last->offset - len - 1 - crlf; - if (last->parts && last->parts->length == 0) - last->parts->length = - ftello (fp) - last->parts->offset - len - 1 - crlf; - /* if the body is empty, we can end up with a -1 length */ - if (last->length < 0) - last->length = 0; - } + if (buffer[0] == '-' && buffer[1] == '-' + && !m_strncmp(buffer + 2, bound, blen)) + { + if (*last) { + BODY *b = *last; - /* Remove any trailing whitespace, up to the length of the boundary */ - for (i = len - 1; ISSPACE (buffer[i]) && i >= blen + 2; i--) - buffer[i] = 0; + /* if the body is empty, we can end up with a -1 length */ + b->length = MAX(0, ftello(fp) - b->offset - len - 1 - crlf); + if (b->parts && b->parts->length == 0) { + b->parts->length = ftello(fp) - b->parts->offset + - len - 1 - crlf; + } + } - /* Check for the end boundary */ - if (m_strcmp(buffer + blen + 2, "--") == 0) { - final = 1; - break; /* done parsing */ - } - else if (buffer[2 + blen] == 0) { - new = mutt_read_mime_header (fp, digest); + /* Remove any trailing whitespace, up to the length of the boundary */ + for (i = len - 1; ISSPACE(buffer[i]) && i >= blen + 2; i--) + buffer[i] = '\0'; - /* - * Consistency checking - catch - * bad attachment end boundaries - */ + /* Check for the end boundary */ + final = buffer[blen + 3] == '-' && buffer[blen + 4] == '-'; + if (final) + break; - if (new->offset > end_off) { - mutt_free_body (&new); - break; - } - if (head) { - last->next = new; - last = new; + if (buffer[2 + blen] == '\0') { + BODY *new = mutt_read_mime_header(fp, digest); + + /* + * Consistency checking - catch + * bad attachment end boundaries + */ + + if (new->offset > end_off) { + mutt_free_body(&new); + break; + } + + if (*last) + last = &(*last)->next; + *last = new; + } } - else - last = head = new; - } } - } - /* in case of missing end boundary, set the length to something reasonable */ - if (last && last->length == 0 && !final) - last->length = end_off - last->offset; + /* in case of missing end boundary, set the length to something reasonable */ + if (*last && (*last)->length == 0 && !final) + (*last)->length = end_off - (*last)->offset; - /* parse recursive MIME parts */ - for (last = head; last; last = last->next) - mutt_parse_part (fp, last); + /* parse recursive MIME parts */ + { + BODY *b; + for (b = head; b; b = b->next) + mutt_parse_part(fp, b); + } - return (head); + return (head); } -static const char *uncomment_timezone (char *buf, size_t buflen, - const char *tz) +static const char * +uncomment_timezone(char *buf, size_t buflen, const char *tz) { - char *p; - size_t len; - - if (*tz != '(') - return tz; /* no need to do anything */ - tz = vskipspaces(tz + 1); - if ((p = strpbrk (tz, " )")) == NULL) - return tz; - len = p - tz; - if (len > buflen - 1) - len = buflen - 1; - memcpy (buf, tz, len); - buf[len] = 0; - return buf; + char *p; + + if (*tz != '(') + return tz; /* no need to do anything */ + + tz = vskipspaces(tz + 1); + p = strpbrk(tz, " )"); + if (!p) + return tz; + + m_strcpylen(buf, buflen, tz, p - tz); + return buf; } static struct tz_t { - char tzname[5]; - unsigned char zhours; - unsigned char zminutes; - unsigned char zoccident; /* west of UTC? */ + char tzname[5]; + unsigned char zhours; + unsigned char zminutes; + unsigned char zoccident; /* west of UTC? */ } TimeZones[] = { - { - "aat", 1, 0, 1}, /* Atlantic Africa Time */ - { - "adt", 4, 0, 0}, /* Arabia DST */ - { - "ast", 3, 0, 0}, /* Arabia */ + {"aat", 1, 0, 1}, /* Atlantic Africa Time */ + {"adt", 4, 0, 0}, /* Arabia DST */ + {"ast", 3, 0, 0}, /* Arabia */ /*{ "ast", 4, 0, 1 }, *//* Atlantic */ - { - "bst", 1, 0, 0}, /* British DST */ - { - "cat", 1, 0, 0}, /* Central Africa */ - { - "cdt", 5, 0, 1}, { - "cest", 2, 0, 0}, /* Central Europe DST */ - { - "cet", 1, 0, 0}, /* Central Europe */ - { - "cst", 6, 0, 1}, + {"bst", 1, 0, 0}, /* British DST */ + {"cat", 1, 0, 0}, /* Central Africa */ + {"cdt", 5, 0, 1}, + {"cest", 2, 0, 0}, /* Central Europe DST */ + {"cet", 1, 0, 0}, /* Central Europe */ + {"cst", 6, 0, 1}, /*{ "cst", 8, 0, 0 }, *//* China */ /*{ "cst", 9, 30, 0 }, *//* Australian Central Standard Time */ - { - "eat", 3, 0, 0}, /* East Africa */ - { - "edt", 4, 0, 1}, { - "eest", 3, 0, 0}, /* Eastern Europe DST */ - { - "eet", 2, 0, 0}, /* Eastern Europe */ - { - "egst", 0, 0, 0}, /* Eastern Greenland DST */ - { - "egt", 1, 0, 1}, /* Eastern Greenland */ - { - "est", 5, 0, 1}, { - "gmt", 0, 0, 0}, { - "gst", 4, 0, 0}, /* Presian Gulf */ - { - "hkt", 8, 0, 0}, /* Hong Kong */ - { - "ict", 7, 0, 0}, /* Indochina */ - { - "idt", 3, 0, 0}, /* Israel DST */ - { - "ist", 2, 0, 0}, /* Israel */ + {"eat", 3, 0, 0}, /* East Africa */ + {"edt", 4, 0, 1}, + {"eest", 3, 0, 0}, /* Eastern Europe DST */ + {"eet", 2, 0, 0}, /* Eastern Europe */ + {"egst", 0, 0, 0}, /* Eastern Greenland DST */ + {"egt", 1, 0, 1}, /* Eastern Greenland */ + {"est", 5, 0, 1}, + {"gmt", 0, 0, 0}, + {"gst", 4, 0, 0}, /* Presian Gulf */ + {"hkt", 8, 0, 0}, /* Hong Kong */ + {"ict", 7, 0, 0}, /* Indochina */ + {"idt", 3, 0, 0}, /* Israel DST */ + {"ist", 2, 0, 0}, /* Israel */ /*{ "ist", 5, 30, 0 }, *//* India */ - { - "jst", 9, 0, 0}, /* Japan */ - { - "kst", 9, 0, 0}, /* Korea */ - { - "mdt", 6, 0, 1}, { - "met", 1, 0, 0}, /* this is now officially CET */ - { - "msd", 4, 0, 0}, /* Moscow DST */ - { - "msk", 3, 0, 0}, /* Moscow */ - { - "mst", 7, 0, 1}, { - "nzdt", 13, 0, 0}, /* New Zealand DST */ - { - "nzst", 12, 0, 0}, /* New Zealand */ - { - "pdt", 7, 0, 1}, { - "pst", 8, 0, 1}, { - "sat", 2, 0, 0}, /* South Africa */ - { - "smt", 4, 0, 0}, /* Seychelles */ - { - "sst", 11, 0, 1}, /* Samoa */ + {"jst", 9, 0, 0}, /* Japan */ + {"kst", 9, 0, 0}, /* Korea */ + {"mdt", 6, 0, 1}, + {"met", 1, 0, 0}, /* this is now officially CET */ + {"msd", 4, 0, 0}, /* Moscow DST */ + {"msk", 3, 0, 0}, /* Moscow */ + {"mst", 7, 0, 1}, + {"nzdt", 13, 0, 0}, /* New Zealand DST */ + {"nzst", 12, 0, 0}, /* New Zealand */ + {"pdt", 7, 0, 1}, + {"pst", 8, 0, 1}, + {"sat", 2, 0, 0}, /* South Africa */ + {"smt", 4, 0, 0}, /* Seychelles */ + {"sst", 11, 0, 1}, /* Samoa */ /*{ "sst", 8, 0, 0 }, *//* Singapore */ - { - "utc", 0, 0, 0}, { - "wat", 0, 0, 0}, /* West Africa */ - { - "west", 1, 0, 0}, /* Western Europe DST */ - { - "wet", 0, 0, 0}, /* Western Europe */ - { - "wgst", 2, 0, 1}, /* Western Greenland DST */ - { - "wgt", 3, 0, 1}, /* Western Greenland */ - { - "wst", 8, 0, 0}, /* Western Australia */ + {"utc", 0, 0, 0}, + {"wat", 0, 0, 0}, /* West Africa */ + {"west", 1, 0, 0}, /* Western Europe DST */ + {"wet", 0, 0, 0}, /* Western Europe */ + {"wgst", 2, 0, 1}, /* Western Greenland DST */ + {"wgt", 3, 0, 1}, /* Western Greenland */ + {"wst", 8, 0, 0}, /* Western Australia */ }; /* parses a date string in RFC822 format: