X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=lib-mime%2Frfc822parse.c;h=e0cd6b0a421680cbe09ae8fe8cd1b0aafd332256;hp=3d9211c2c3b888812da1226e846be532da98d740;hb=8352ddc65f822aaef06df65ee6c32423b73d6890;hpb=97c8c97b6199b4b8a0cdf7923e64decbb47e7797 diff --git a/lib-mime/rfc822parse.c b/lib-mime/rfc822parse.c index 3d9211c..e0cd6b0 100644 --- a/lib-mime/rfc822parse.c +++ b/lib-mime/rfc822parse.c @@ -53,347 +53,327 @@ * lines. ``line'' must point to a dynamically allocated string; it is * increased if more space is required to fit the whole line. */ -char *mutt_read_rfc822_line (FILE * f, char *line, size_t * linelen) +ssize_t mutt_read_rfc822_line(FILE *f, char **line, ssize_t *n) { - char *buf = line; - char ch; - size_t offset = 0; - - for (;;) { - if (fgets (buf, *linelen - offset, f) == NULL || /* end of file or */ - (ISSPACE (*line) && !offset)) { /* end of headers */ - *line = 0; - return (line); - } + ssize_t pos = 0; - buf += m_strlen(buf) - 1; - if (*buf == '\n') { - /* we did get a full line. remove trailing space */ - while (ISSPACE (*buf)) - *buf-- = 0; /* we cannot come beyond line's beginning because - * it begins with a non-space */ - - /* check to see if the next line is a continuation line */ - if ((ch = fgetc (f)) != ' ' && ch != '\t') { - ungetc (ch, f); - return (line); /* next line is a separate header field or EOH */ - } + for (;;) { + char *p = *line; - /* eat tabs and spaces from the beginning of the continuation line */ - while ((ch = fgetc (f)) == ' ' || ch == '\t'); - ungetc (ch, f); - *++buf = ' '; /* string is still terminated because we removed - at least one whitespace char above */ - } + /* end of file or end of headers */ + if (!fgets(p + pos, *n - pos, f) || (ISSPACE(*p) && pos == 0)) { + *p = '\0'; + return 0; + } + + pos += m_strlen(p + pos); + if (p[pos - 1] == '\n') { + int c; + + /* remove trailing spaces. safe: p[0] is not a space */ + do { + p[--pos] = '\0'; + } while (ISSPACE(p[pos])); + + /* check to see if the next line is a continuation line */ + c = fgetc(f); + if (c != ' ' && c != '\t') { + /* next line is a separate header field or EOH */ + ungetc(c, f); + return pos; + } - buf++; - offset = buf - line; - if (*linelen < offset + STRING) { - /* grow the buffer */ - *linelen += STRING; - p_realloc(&line, *linelen); - buf = line + offset; + /* eat tabs and spaces from the beginning of the continuation line */ + do { + c = fgetc(f); + } while (c == ' ' || c == '\t'); + ungetc(c, f); + + /* string is still terminated because we removed at least one + whitespace char above */ + p[pos++] = ' '; + } + + if (*n < pos + STRING) { + /* grow the buffer */ + *n += STRING; + p_realloc(line, *n); + } } - } - /* not reached */ } -LIST *mutt_parse_references (char *s, int in_reply_to) +/* TODO: Make that a string list somehow */ +LIST *mutt_parse_references(char *s, int in_reply_to) { - LIST *t, *lst = NULL; - int m, n = 0; - char *o = NULL, *new, *at; + LIST *lst = NULL; + int n = 0; + char *o = NULL; - while ((s = strtok (s, " \t;")) != NULL) { - /* - * some mail clients add other garbage besides message-ids, so do a quick + /* some mail clients add other garbage besides message-ids, so do a quick * check to make sure this looks like a valid message-id * some idiotic clients also break their message-ids between lines, deal * with that too (give up if it's more than two lines, though) */ - t = NULL; - new = NULL; - - if (*s == '<') { - n = m_strlen(s); - if (s[n - 1] != '>') { - o = s; - s = NULL; - continue; - } - new = m_strdup(s); - } - else if (o) { - m = m_strlen(s); - if (s[m - 1] == '>') { - new = p_new(char, n + m + 1); - strcpy (new, o); /* __STRCPY_CHECKED__ */ - strcpy (new + n, s); /* __STRCPY_CHECKED__ */ - } - } - if (new) { - /* make sure that this really does look like a message-id. - * it should have exactly one @, and if we're looking at - * an in-reply-to header, make sure that the part before - * the @ has more than eight characters or it's probably - * an email address - */ - if (!(at = strchr (new, '@')) || strchr (at + 1, '@') - || (in_reply_to && at - new <= 8)) - p_delete(&new); - else { - t = p_new(LIST, 1); - t->data = new; - t->next = lst; - lst = t; - } + for (s = strtok(s, " \t;"); s; s = strtok(NULL, " \t;")) { + char *new = NULL; + + if (*s == '<') { + n = m_strlen(s); + if (s[n - 1] != '>') { + o = s; + continue; + } + + new = m_strdup(s); + } else if (o) { + ssize_t m = m_strlen(s); + + if (s[m - 1] != '>') { + o = NULL; + } else { + new = p_new(char, n + m + 1); + strcpy(new, o); + strcpy(new + n, s); + } + } + + /* make sure that this really does look like a message-id. + * it should have exactly one @, and if we're looking at + * an in-reply-to header, make sure that the part before + * the @ has more than eight characters or it's probably + * an email address + */ + if (new) { + char *at = strchr(new, '@'); + LIST *tmp; + + if (!at || strchr(at + 1, '@') || (in_reply_to && at - new <= 8)) { + p_delete(&new); + continue; + } + + tmp = p_new(LIST, 1); + tmp->data = new; + tmp->next = lst; + lst = tmp; + } } - o = NULL; - s = NULL; - } - return (lst); + return lst; } -int mutt_check_encoding (const char *c) +int mutt_check_encoding(const char *s) { - if (ascii_strncasecmp ("7bit", c, sizeof ("7bit") - 1) == 0) - return (ENC7BIT); - else if (ascii_strncasecmp ("8bit", c, sizeof ("8bit") - 1) == 0) - return (ENC8BIT); - else if (ascii_strncasecmp ("binary", c, sizeof ("binary") - 1) == 0) - return (ENCBINARY); - else - if (ascii_strncasecmp - ("quoted-printable", c, sizeof ("quoted-printable") - 1) == 0) - return (ENCQUOTEDPRINTABLE); - else if (ascii_strncasecmp ("base64", c, sizeof ("base64") - 1) == 0) - return (ENCBASE64); - else if (ascii_strncasecmp ("x-uuencode", c, sizeof ("x-uuencode") - 1) == 0) - return (ENCUUENCODED); - else - return (ENCOTHER); +#define COMPARE(tok, value) \ + if (!ascii_strncasecmp(tok, s, sizeof(tok) - 1)) { \ + return value; \ + } + COMPARE("7bit", ENC7BIT); + COMPARE("8bit", ENC8BIT); + COMPARE("binary", ENCBINARY); + COMPARE("quoted-printable", ENCQUOTEDPRINTABLE); + COMPARE("base64", ENCBASE64); + COMPARE("x-uuencode", ENCUUENCODED); +#undef COMPARE + + return ENCOTHER; } -static PARAMETER *parse_parameters (const char *s) +int mutt_check_mime_type(const char *s) { - PARAMETER *head = 0, *cur = 0, *new; - char buffer[LONG_STRING]; - const char *p; - size_t i; - - debug_print (2, ("`%s'\n", s)); - - while (*s) { - if ((p = strpbrk (s, "=;")) == NULL) { - debug_print (1, ("malformed parameter: %s\n", s)); - goto bail; +#define COMPARE(tok, value) \ + if (!ascii_strncasecmp(tok, s, sizeof(tok) - 1)) { \ + return value; \ } + COMPARE("text", TYPETEXT); + COMPARE("multipart", TYPEMULTIPART); + COMPARE("application", TYPEAPPLICATION); + COMPARE("message", TYPEMESSAGE); + COMPARE("image", TYPEIMAGE); + COMPARE("audio", TYPEAUDIO); + COMPARE("video", TYPEVIDEO); + COMPARE("model", TYPEMODEL); + COMPARE("*", TYPEANY); + COMPARE(".*", TYPEANY); +#undef COMPARE + + return TYPEOTHER; +} - /* if we hit a ; now the parameter has no value, just skip it */ - if (*p != ';') { - i = p - s; +static PARAMETER *parse_parameters(const char *s) +{ + PARAMETER *res = NULL; + PARAMETER **list = &res; - new = mutt_new_parameter (); + while (*s) { + const char *p; + PARAMETER *new; + int i; - new->attribute = p_dupstr(s, i); + s = skipspaces(s); + if (*s == '=') /* parameters are fucked up, go away */ + break; - /* remove whitespace from the end of the attribute name */ - while (ISSPACE (new->attribute[--i])) - new->attribute[i] = 0; + p = strpbrk(s, "=;"); + if (!p) + break; - s = vskipspaces(p + 1); /* skip over the = */ + if (*p == ';') { + /* if we hit a ; now the parameter has no value, just skip it */ + s = p + 1; + continue; + } - if (*s == '"') { - int state_ascii = 1; + i = p - s; + new = parameter_new(); + new->attribute = p_dupstr(s, i); - s++; - for (i = 0; *s && i < sizeof (buffer) - 1; i++, s++) { - if (!option (OPTSTRICTMIME)) { - /* As iso-2022-* has a characer of '"' with non-ascii state, - * ignore it. */ - if (*s == 0x1b && i < sizeof (buffer) - 2) { - if (s[1] == '(' && (s[2] == 'B' || s[2] == 'J')) - state_ascii = 1; - else - state_ascii = 0; - } - } - if (state_ascii && *s == '"') - break; - if (*s == '\\') { - /* Quote the next character */ - buffer[i] = s[1]; - if (!*++s) - break; - } - else - buffer[i] = *s; + while (--i >= 0 && ISSPACE(new->attribute[i])) { + new->attribute[i] = '\0'; } - buffer[i] = 0; - if (*s) - s++; /* skip over the " */ - } - else { - for (i = 0; *s && *s != ' ' && *s != ';' && i < sizeof (buffer) - 1; - i++, s++) - buffer[i] = *s; - buffer[i] = 0; - } + s = skipspaces(p + 1); /* skip over the = */ + + if (*s == '"') { + char buffer[LONG_STRING]; + int state_ascii = 1; + + s++; + for (i = 0; *s && i < ssizeof(buffer) - 1; i++, s++) { + if (!option(OPTSTRICTMIME)) { + /* As iso-2022-* has a characer of '"' with non-ascii state, + * ignore it. */ + if (*s == 0x1b && i < ssizeof(buffer) - 2) { + state_ascii = s[1] == '(' && (s[2] == 'B' || s[2] == 'J'); + } + } + if (state_ascii && *s == '"') + break; + + if (*s == '\\') { + buffer[i] = *++s; + } else { + buffer[i] = *s; + } + } - new->value = m_strdup(buffer); + new->value = p_dupstr(buffer, i); + } else { + for (p = s; *p && *p != ' ' && *p != ';'; p++); + new->value = p_dupstr(s, p - s); + } - debug_print (2, ("`%s' = `%s'\n", new->attribute ? new->attribute : "", - new->value ? new->value : "")); + *list = new; + list = &new->next; - /* Add this parameter to the list */ - if (head) { - cur->next = new; - cur = cur->next; - } - else - head = cur = new; - } - else { - debug_print (1, ("parameter with no value: %s\n", s)); - s = p; + s = strchr(s, ';'); /* Find the next parameter */ + if (!s) + break; /* no more parameters */ } - /* Find the next parameter */ - if (*s != ';' && (s = strchr (s, ';')) == NULL) - break; /* no more parameters */ + rfc2231_decode_parameters(&res); + return res; +} - do { - /* Move past any leading whitespace */ - s = vskipspaces(s + 1); +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'; + 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); } - while (*s == ';'); /* skip empty parameters */ - } -bail: + /* 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); + } - rfc2231_decode_parameters (&head); - return (head); -} + /* Finally, get the major type */ + ct->type = mutt_check_mime_type(s); -int mutt_check_mime_type (const char *s) -{ - if (ascii_strcasecmp ("text", s) == 0) - return TYPETEXT; - else if (ascii_strcasecmp ("multipart", s) == 0) - return TYPEMULTIPART; - else if (ascii_strcasecmp ("application", s) == 0) - return TYPEAPPLICATION; - else if (ascii_strcasecmp ("message", s) == 0) - return TYPEMESSAGE; - else if (ascii_strcasecmp ("image", s) == 0) - return TYPEIMAGE; - else if (ascii_strcasecmp ("audio", s) == 0) - return TYPEAUDIO; - else if (ascii_strcasecmp ("video", s) == 0) - return TYPEVIDEO; - else if (ascii_strcasecmp ("model", s) == 0) - return TYPEMODEL; - else if (ascii_strcasecmp ("*", s) == 0) - return TYPEANY; - else if (ascii_strcasecmp (".*", s) == 0) - return TYPEANY; - else - return TYPEOTHER; -} + if (ct->type == TYPEOTHER) { + ct->xtype = m_strdup(s); + } -void mutt_parse_content_type (char *s, BODY * ct) -{ - char *pc; - char *subtype; - - p_delete(&ct->subtype); - mutt_free_parameter (&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); - } + 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]; - /* 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); - } + case TYPETEXT: + ct->subtype = m_strdup("plain"); + break; - /* Finally, get the major type */ - ct->type = mutt_check_mime_type (s); + case TYPEAUDIO: + ct->subtype = m_strdup("basic"); + break; - if (ct->type == TYPEOTHER) { - ct->xtype = m_strdup(s); - } + case TYPEMESSAGE: + ct->subtype = m_strdup("rfc822"); + break; - 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); - } - else - ct->subtype = m_strdup("x-unknown"); - } + case TYPEOTHER: + ct->type = TYPEAPPLICATION; + snprintf(buffer, sizeof(buffer), "x-%s", s); + ct->subtype = m_strdup(buffer); + break; - /* 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: + ct->subtype = m_strdup("x-unknown"); + break; + } + } + /* 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); - mutt_free_parameter (&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: @@ -402,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); - size_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 (*(line = mutt_read_rfc822_line (fp, line, &linelen)) != 0) { - /* 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 @@ -502,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 = mutt_new_header (); - 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 @@ -530,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) @@ -538,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_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: @@ -1242,18 +1184,18 @@ done: * Used for recall-message. * * Returns: newly allocated envelope structure. You should free it by - * mutt_free_envelope() when envelope stay unneeded. + * envelope_delete() when envelope stay unneeded. */ ENVELOPE *mutt_read_rfc822_header (FILE * f, HEADER * hdr, short user_hdrs, short weed) { - ENVELOPE *e = mutt_new_envelope (); + ENVELOPE *e = envelope_new(); LIST *last = NULL; char *line = p_new(char, LONG_STRING); char *p; off_t loc; int matched; - size_t linelen = LONG_STRING; + ssize_t linelen = LONG_STRING; char buf[LONG_STRING + 1]; if (hdr) { @@ -1272,7 +1214,8 @@ ENVELOPE *mutt_read_rfc822_header (FILE * f, HEADER * hdr, short user_hdrs, } while ((loc = ftello (f)), - *(line = mutt_read_rfc822_line (f, line, &linelen)) != 0) { + mutt_read_rfc822_line (f, &line, &linelen)) + { matched = 0; if ((p = strpbrk (line, ": \t")) == NULL || *p != ':') {