X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=lib-mime%2Frfc822parse.c;h=3fd26109dcdd3c2a9be213ef16f7f8a7ee0f89b0;hp=e9b171a6a7833e0af333eec7330937f6fb584dfc;hb=8bca9860d0edd96e0087b3e47be2814474425654;hpb=63694769caa96f36675293e45a01e91cbe3175b4 diff --git a/lib-mime/rfc822parse.c b/lib-mime/rfc822parse.c index e9b171a..3fd2610 100644 --- a/lib-mime/rfc822parse.c +++ b/lib-mime/rfc822parse.c @@ -39,10 +39,7 @@ #include #include -#include - #include "recvattach.h" -#include "mx.h" #include "url.h" #include "lib/debug.h" @@ -275,96 +272,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 +379,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 +477,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 +503,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 +511,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_strncpy(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: @@ -700,172 +668,123 @@ static struct tz_t { * This routine assumes that `h' has been initialized to 0. the `timezone' * field is optional, defaulting to +0000 if missing. */ -time_t mutt_parse_date (const char *s, HEADER * h) +time_t mutt_parse_date(const char *s, HEADER *h) { - int count = 0; - char *t; - int hour, min, sec; - struct tm tm; - int i; - int tz_offset = 0; - int zhours = 0; - int zminutes = 0; - int zoccident = 0; - const char *ptz; - char tzstr[SHORT_STRING]; - char scratch[SHORT_STRING]; - - /* Don't modify our argument. Fixed-size buffer is ok here since - * the date format imposes a natural limit. - */ - - m_strcpy(scratch, sizeof(scratch), s); - - /* kill the day of the week, if it exists. */ - if ((t = strchr (scratch, ','))) - t++; - else - t = scratch; - t = vskipspaces(t); - - p_clear(&tm, 1); - - while ((t = strtok (t, " \t")) != NULL) { - switch (count) { - case 0: /* day of the month */ - if (!isdigit ((unsigned char) *t)) - return (-1); - tm.tm_mday = atoi (t); - if (tm.tm_mday > 31) - return (-1); - break; - - case 1: /* month of the year */ - if ((i = mutt_check_month (t)) < 0) - return (-1); - tm.tm_mon = i; - break; - - case 2: /* year */ - tm.tm_year = atoi (t); - if (tm.tm_year < 50) - tm.tm_year += 100; - else if (tm.tm_year >= 1900) - tm.tm_year -= 1900; - break; - - case 3: /* time of day */ - if (sscanf (t, "%d:%d:%d", &hour, &min, &sec) == 3); - else if (sscanf (t, "%d:%d", &hour, &min) == 2) - sec = 0; - else { - debug_print (1, ("could not process time format: %s\n", t)); - return (-1); - } - tm.tm_hour = hour; - tm.tm_min = min; - tm.tm_sec = sec; - break; - - case 4: /* timezone */ - /* sometimes we see things like (MST) or (-0700) so attempt to - * compensate by uncommenting the string if non-RFC822 compliant - */ - ptz = uncomment_timezone (tzstr, sizeof (tzstr), t); - - if (*ptz == '+' || *ptz == '-') { - if (ptz[1] && ptz[2] && ptz[3] && ptz[4] - && isdigit ((unsigned char) ptz[1]) - && isdigit ((unsigned char) ptz[2]) - && isdigit ((unsigned char) ptz[3]) - && isdigit ((unsigned char) ptz[4])) { - zhours = (ptz[1] - '0') * 10 + (ptz[2] - '0'); - zminutes = (ptz[3] - '0') * 10 + (ptz[4] - '0'); - - if (ptz[0] == '-') - zoccident = 1; - } - } - else { - struct tz_t *tz; - - tz = bsearch (ptz, TimeZones, sizeof TimeZones / sizeof (struct tz_t), - sizeof (struct tz_t), - (int (*)(const void *, const void *)) ascii_strcasecmp - /* This is safe to do: A pointer to a struct equals - * a pointer to its first element*/ ); - - if (tz) { - zhours = tz->zhours; - zminutes = tz->zminutes; - zoccident = tz->zoccident; - } - - /* ad hoc support for the European MET (now officially CET) TZ */ - if (ascii_strcasecmp (t, "MET") == 0) { - if ((t = strtok (NULL, " \t")) != NULL) { - if (!ascii_strcasecmp (t, "DST")) - zhours++; - } - } - } - tz_offset = zhours * 3600 + zminutes * 60; - if (!zoccident) - tz_offset = -tz_offset; - break; - } - count++; - t = 0; - } - - if (count < 4) { /* don't check for missing timezone */ - debug_print (1, ("error parsing date format, using received time\n")); - return (-1); - } - - if (h) { - h->zhours = zhours; - h->zminutes = zminutes; - h->zoccident = zoccident; - } + int zhours = 0, zminutes = 0, zoccident = 0; + char scratch[SHORT_STRING]; + struct tm tm; + int count = 0; + char *p; + + /* Don't modify our argument. Fixed-size buffer is ok here since + the date format imposes a natural limit. */ + + m_strcpy(scratch, sizeof(scratch), s); + + /* kill the day of the week, if it exists. */ + p = strchr(scratch, ','); + p = vskipspaces(p ? p + 1 : scratch); + + p_clear(&tm, 1); + + while ((p = strtok (p, " \t")) != NULL) { + char tzstr[SHORT_STRING]; + const char *ptz; + + switch (count) { + case 0: /* day of the month */ + if (!isdigit((unsigned char)*p)) + return -1; + tm.tm_mday = atoi(p); + if (tm.tm_mday > 31) + return -1; + break; - return (mutt_mktime (&tm, 0) + tz_offset); -} + case 1: /* month of the year */ + tm.tm_mon = mutt_check_month(p); + if (tm.tm_mon < 0) + return -1; + break; -/* extract the first substring that looks like a message-id */ -static char *extract_message_id(const char *s) -{ - const char *p; + case 2: /* year */ + tm.tm_year = atoi(p); + if (tm.tm_year < 50) + tm.tm_year += 100; + else if (tm.tm_year >= 1900) + tm.tm_year -= 1900; + break; - if ((s = strchr(s, '<')) == NULL || (p = strchr(s, '>')) == NULL) - return NULL; - return p_dupstr(s, (p - s) + 1); -} + case 3: /* time of day */ + tm.tm_hour = strtol(p, &p, 10); + if (*p++ != ':') + return -1; + tm.tm_min = strtol(p, &p, 10); + if (*p++ == ':') { + tm.tm_sec = strtol(p, &p, 10); + } else { + tm.tm_sec = 0; + } + break; -void mutt_parse_mime_message (CONTEXT * ctx, HEADER * cur) -{ - MESSAGE *msg; - int flags = 0; + case 4: /* timezone */ + /* sometimes we see things like (MST) or (-0700) so attempt to + * compensate by uncommenting the string if non-RFC822 compliant + */ + ptz = uncomment_timezone(tzstr, sizeof(tzstr), p); + + if (*ptz == '+' || *ptz == '-') { + if (isdigit((unsigned char)ptz[1]) + && isdigit((unsigned char)ptz[2]) + && isdigit((unsigned char)ptz[3]) + && isdigit((unsigned char)ptz[4])) + { + zoccident = ptz[0] == '-'; + zhours = (ptz[1] - '0') * 10 + (ptz[2] - '0'); + zminutes = (ptz[3] - '0') * 10 + (ptz[4] - '0'); + } + } else { + struct tz_t *tz; - do { - if (cur->content->type != TYPEMESSAGE - && cur->content->type != TYPEMULTIPART) - break; /* nothing to do */ + /* This is safe to do: A pointer to a struct equals a pointer to its + * first element*/ + tz = bsearch(ptz, TimeZones, countof(TimeZones), sizeof(TimeZones[0]), + (int (*)(const void *, const void *))ascii_strcasecmp); - if (cur->content->parts) - break; /* The message was parsed earlier. */ + if (tz) { + zhours = tz->zhours; + zminutes = tz->zminutes; + zoccident = tz->zoccident; + } - if ((msg = mx_open_message (ctx, cur->msgno))) { - mutt_parse_part (msg->fp, cur->content); + /* ad hoc support for the European MET (now officially CET) TZ */ + if (ascii_strcasecmp(p, "MET") == 0) { + if ((p = strtok (NULL, " \t")) && !ascii_strcasecmp(p, "DST")) { + zhours++; + } + } + } + break; + } + count++; + p = NULL; + } - cur->security = crypt_query (cur->content); + if (count < 4) { /* don't check for missing timezone */ + debug_print (1, ("error parsing date format, using received time\n")); + return -1; + } - mx_close_message (&msg); + if (h) { + h->zhours = zhours; + h->zminutes = zminutes; + h->zoccident = zoccident; } - } while (0); - mutt_count_body_parts (cur, flags | M_PARTS_RECOUNT); + + return mutt_mktime(&tm, 0) + (zoccident ? 1 : -1) * (zhours * 3600 + zminutes * 60); } +/*** XXX: MC READ MARK ***/ + int mutt_parse_rfc822_line (ENVELOPE * e, HEADER * hdr, char *line, char *p, short user_hdrs, short weed, short do_2047, LIST ** lastp) @@ -1024,9 +943,13 @@ int mutt_parse_rfc822_line (ENVELOPE * e, HEADER * hdr, char *line, char *p, matched = 1; } else if (!ascii_strcasecmp (line + 1, "essage-id")) { + const char *beg, *end; + /* We add a new "Message-ID:" when building a message */ p_delete(&e->message_id); - e->message_id = extract_message_id (p); + + if ((beg = strchr(p, '<')) && (end = strchr(beg, '>'))) + e->message_id = p_dupstr(beg, (end - beg) + 1); matched = 1; } else if (!ascii_strncasecmp (line + 1, "ail-", 4)) {