* please see the file GPL in the top level source directory.
*/
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
#include <stdio.h>
#include <lib-lib/mem.h>
#include <lib-crypt/crypt.h>
-#include "enter.h"
#include "recvattach.h"
#include "mx.h"
#include "url.h"
-#include "lib/rx.h"
#include "lib/debug.h"
#include "mime.h"
* 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)
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) {
mutt_get_first_charset (AssumedCharset),
&ct->parameter);
}
-
}
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);
}
}
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);
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;
{
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;
* 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) {
}
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 != ':') {