X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=lib-mime%2Frfc822parse.c;h=e9b171a6a7833e0af333eec7330937f6fb584dfc;hp=5078f19411a0bdf9b94758c0627fcd7774db19e4;hb=63694769caa96f36675293e45a01e91cbe3175b4;hpb=d5fc962299f48696697e29f323e78c8bba6ca2d1 diff --git a/lib-mime/rfc822parse.c b/lib-mime/rfc822parse.c index 5078f19..e9b171a 100644 --- a/lib-mime/rfc822parse.c +++ b/lib-mime/rfc822parse.c @@ -26,6 +26,10 @@ * please see the file GPL in the top level source directory. */ +#if HAVE_CONFIG_H +# include "config.h" +#endif + #include #include @@ -37,12 +41,10 @@ #include -#include "enter.h" #include "recvattach.h" #include "mx.h" #include "url.h" -#include "lib/rx.h" #include "lib/debug.h" #include "mime.h" @@ -51,254 +53,226 @@ * 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; + } + + /* eat tabs and spaces from the beginning of the continuation line */ + do { + c = fgetc(f); + } while (c == ' ' || c == '\t'); + ungetc(c, f); - buf++; - offset = buf - line; - if (*linelen < offset + STRING) { - /* grow the buffer */ - *linelen += STRING; - p_realloc(&line, *linelen); - buf = line + offset; + /* 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; - } - } - o = NULL; - s = NULL; - } + for (s = strtok(s, " \t;"); s; s = strtok(NULL, " \t;")) { + char *new = NULL; - return (lst); -} + if (*s == '<') { + n = m_strlen(s); + if (s[n - 1] != '>') { + o = s; + continue; + } -int mutt_check_encoding (const char *c) -{ - 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); -} + new = m_strdup(s); + } else if (o) { + ssize_t m = m_strlen(s); -static PARAMETER *parse_parameters (const char *s) -{ - PARAMETER *head = 0, *cur = 0, *new; - char buffer[LONG_STRING]; - const char *p; - size_t i; + 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; - debug_print (2, ("`%s'\n", s)); + if (!at || strchr(at + 1, '@') || (in_reply_to && at - new <= 8)) { + p_delete(&new); + continue; + } - while (*s) { - if ((p = strpbrk (s, "=;")) == NULL) { - debug_print (1, ("malformed parameter: %s\n", s)); - goto bail; + tmp = p_new(LIST, 1); + tmp->data = new; + tmp->next = lst; + lst = tmp; + } } - /* if we hit a ; now the parameter has no value, just skip it */ - if (*p != ';') { - i = p - s; + return lst; +} - new = mutt_new_parameter (); +int mutt_check_encoding(const char *s) +{ +#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; +} - new->attribute = p_dupstr(s, i); +int mutt_check_mime_type(const char *s) +{ +#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; +} - /* remove whitespace from the end of the attribute name */ - while (ISSPACE (new->attribute[--i])) - new->attribute[i] = 0; +static PARAMETER *parse_parameters(const char *s) +{ + PARAMETER *res = NULL; + PARAMETER **list = &res; - s = vskipspaces(p + 1); /* skip over the = */ + while (*s) { + const char *p; + PARAMETER *new; + int i; - if (*s == '"') { - int state_ascii = 1; + s = skipspaces(s); + if (*s == '=') /* parameters are fucked up, go away */ + break; - 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 == '"') + p = strpbrk(s, "=;"); + if (!p) break; - if (*s == '\\') { - /* Quote the next character */ - buffer[i] = s[1]; - if (!*++s) - break; - } - else - buffer[i] = *s; + + if (*p == ';') { + /* if we hit a ; now the parameter has no value, just skip it */ + s = p + 1; + continue; } - 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; - } - new->value = m_strdup(buffer); + i = p - s; + new = parameter_new(); + new->attribute = p_dupstr(s, i); - debug_print (2, ("`%s' = `%s'\n", new->attribute ? new->attribute : "", - new->value ? new->value : "")); + while (--i >= 0 && ISSPACE(new->attribute[i])) { + new->attribute[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; + } + } - /* 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; - } + new->value = p_dupstr(buffer, i); + } else { + for (p = s; *p && *p != ' ' && *p != ';'; p++); + new->value = p_dupstr(s, p - s); + } - /* Find the next parameter */ - if (*s != ';' && (s = strchr (s, ';')) == NULL) - break; /* no more parameters */ + *list = new; + list = &new->next; - do { - /* Move past any leading whitespace */ - s = vskipspaces(s + 1); + s = strchr(s, ';'); /* Find the next parameter */ + if (!s) + break; /* no more parameters */ } - while (*s == ';'); /* skip empty parameters */ - } - -bail: - rfc2231_decode_parameters (&head); - return (head); -} - -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; + rfc2231_decode_parameters(&res); + return res; } void mutt_parse_content_type (char *s, BODY * ct) @@ -307,7 +281,7 @@ void mutt_parse_content_type (char *s, BODY * ct) char *subtype; p_delete(&ct->subtype); - mutt_free_parameter (&ct->parameter); + parameter_delete(&ct->parameter); /* First extract any existing parameters */ if ((pc = strchr (s, ';')) != NULL) { @@ -368,7 +342,6 @@ void mutt_parse_content_type (char *s, BODY * ct) mutt_get_first_charset (AssumedCharset), &ct->parameter); } - } static void parse_content_disposition (char *s, BODY * ct) @@ -390,7 +363,7 @@ static void parse_content_disposition (char *s, BODY * ct) m_strreplace(&ct->filename, s); if ((s = mutt_get_parameter ("name", parms)) != 0) ct->form_name = m_strdup(s); - mutt_free_parameter (&parms); + parameter_delete(&parms); } } @@ -406,7 +379,7 @@ 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; + ssize_t linelen = LONG_STRING; p->hdr_offset = ftello (fp); @@ -414,7 +387,7 @@ BODY *mutt_read_mime_header (FILE * fp, int digest) p->type = digest ? TYPEMESSAGE : TYPETEXT; p->disposition = DISPINLINE; - while (*(line = mutt_read_rfc822_line (fp, line, &linelen)) != 0) { + while (mutt_read_rfc822_line(fp, &line, &linelen)) { /* Find the value of the current header */ if ((c = strchr (line, ':'))) { *c++ = 0; @@ -505,7 +478,7 @@ BODY *mutt_parse_messageRFC822 (FILE * fp, BODY * parent) { BODY *msg; - parent->hdr = mutt_new_header (); + 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; @@ -1240,18 +1213,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) { @@ -1270,7 +1243,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 != ':') {