move parse to libemail
authorRichard Russon <rich@flatcap.org>
Sat, 14 Jul 2018 13:02:34 +0000 (14:02 +0100)
committerRichard Russon <rich@flatcap.org>
Mon, 16 Jul 2018 22:44:16 +0000 (23:44 +0100)
34 files changed:
Makefile.autosetup
buffy.c
commands.c
compose.c
email/email.h
email/email_globals.c
email/email_globals.h
email/parse.c [moved from parse.c with 85% similarity]
email/parse.h [moved from parse.h with 80% similarity]
globals.h
handler.c
hdrline.c
imap/message.c
init.h
maildir/mh.c
mbox/mbox.c
mutt_attach.c
mutt_header.c
mutt_parse.c [new file with mode: 0644]
mutt_parse.h [new file with mode: 0644]
mutt_url.c
muttlib.c
ncrypt/crypt.c
ncrypt/crypt_gpgme.c
ncrypt/pgp.c
ncrypt/smime.c
nntp/nntp.c
pattern.c
pop/pop.c
postpone.c
recvattach.c
recvattach.h
send.c
sendlib.c

index 00077a7e86526ee2a161c78025bceeb9c51b598e..8ac1d973b2a1d3ae525f78f0b005f7c6ec789e2e 100644 (file)
@@ -67,8 +67,8 @@ NEOMUTTOBJS=  addrbook.o alias.o bcache.o browser.o buffy.o \
                enriched.o enter.o filter.o flags.o group.o handler.o \
                hdrline.o help.o hook.o init.o keymap.o \
                main.o menu.o muttlib.o mutt_account.o mutt_attach.o mutt_body.o mutt_header.o \
-               mutt_history.o mutt_logging.o mutt_signal.o mutt_socket.o mutt_thread.o mutt_url.o mutt_window.o mx.o \
-               pager.o parse.o pattern.o \
+               mutt_history.o mutt_logging.o mutt_parse.o mutt_signal.o mutt_socket.o mutt_thread.o mutt_url.o mutt_window.o mx.o \
+               pager.o pattern.o \
                postpone.o progress.o query.o recvattach.o recvcmd.o resize.o rfc1524.o \
                rfc3676.o safe_asprintf.o score.o send.o \
                sendlib.o sidebar.o smtp.o sort.o state.o status.o system.o \
@@ -91,7 +91,7 @@ ALLOBJS+=     $(NEOMUTTOBJS)
 LIBEMAIL=      libemail.a
 LIBEMAILOBJS=  email/address.o email/attach.o email/body.o email/envelope.o \
                email/from.o email/email_globals.o email/header.o email/idna.o \
-               email/mime.o email/parameter.o email/rfc2047.o email/rfc2231.o email/tags.o \
+               email/mime.o email/parameter.o email/parse.o email/rfc2047.o email/rfc2231.o email/tags.o \
                email/thread.o email/url.o
 CLEANFILES+=   $(LIBEMAIL) $(LIBEMAILOBJS)
 MUTTLIBS+=     $(LIBEMAIL)
diff --git a/buffy.c b/buffy.c
index dae68fe9c4b13580e4162c0a20f9f76e6644a145..6cbfa1a3f58a0d777e96f301b4b4135b4aa1218d 100644 (file)
--- a/buffy.c
+++ b/buffy.c
@@ -42,7 +42,6 @@
 #include "muttlib.h"
 #include "mx.h"
 #include "options.h"
-#include "parse.h"
 #include "protos.h"
 #ifdef USE_SIDEBAR
 #include "sidebar.h"
index dbab43a1ee0dcfd0fe7a55bf26048d0fa490d7e9..d8b37220c60bc315652de7b746730249f2025009 100644 (file)
 #include "menu.h"
 #include "mutt_curses.h"
 #include "mutt_logging.h"
+#include "mutt_parse.h"
 #include "mutt_window.h"
 #include "muttlib.h"
 #include "mx.h"
 #include "ncrypt/ncrypt.h"
 #include "options.h"
 #include "pager.h"
-#include "parse.h"
 #include "protos.h"
 #include "recvattach.h"
 #include "sendlib.h"
index e18e4369e7de5cb890f76eb1d4f9f58fa6e856c5..e6265b82f6cf82cd892a92fa543afde254f6d036 100644 (file)
--- a/compose.c
+++ b/compose.c
@@ -57,7 +57,6 @@
 #include "ncrypt/ncrypt.h"
 #include "opcodes.h"
 #include "options.h"
-#include "parse.h"
 #include "protos.h"
 #include "recvattach.h"
 #include "sendlib.h"
index 8c3fbd7dfcd168b89b30e80a68cff993096e6e7b..456631cf77c14b89430ca446ade61707c9a9cd3e 100644 (file)
@@ -36,6 +36,7 @@
  * | email/idna.c      | @subpage email_idna      |
  * | email/parameter.c | @subpage email_parameter |
  * | email/mime.c      | @subpage email_mime      |
+ * | email/parse.c     | @subpage email_parse     |
  * | email/rfc2047.c   | @subpage email_rfc2047   |
  * | email/rfc2231.c   | @subpage email_rfc2231   |
  * | email/tags.c      | @subpage email_tags      |
@@ -56,6 +57,7 @@
 #include "header.h"
 #include "idna2.h"
 #include "mime.h"
+#include "parse.h"
 #include "parameter.h"
 #include "rfc2047.h"
 #include "rfc2231.h"
index cfb828297d1d2c10e92ef29e0cd01ed007d4785a..6ed965f935dc353e701ef52ee9c8b95c870d3127 100644 (file)
  */
 
 #include "config.h"
+#include <stdbool.h>
+#include "mutt/mutt.h"
 
+/* Config items */
+bool MarkOld;
+struct Regex *ReplyRegex;
 char *SendCharset;
+char *SpamSeparator;
+bool Weed;
+
+/* Global variables */
+struct RegexList *NoSpamList;
+struct ReplaceList *SpamList;
+struct ListHead Ignore = STAILQ_HEAD_INITIALIZER(Ignore);
+struct ListHead UnIgnore = STAILQ_HEAD_INITIALIZER(UnIgnore);
index 1ad38a1c6ef68e0e5d60e17c4c6e400b659f522d..96cfcd455038b19e2d40b914282d6b0ab1a579cd 100644 (file)
 #ifndef _EMAIL_GLOBALS_H
 #define _EMAIL_GLOBALS_H
 
-extern char *SendCharset;
+#include <stdbool.h>
+#include "mutt/mutt.h"
+
+/* Config items */
+extern bool                MarkOld;
+extern struct Regex *      ReplyRegex;
+extern char *              SendCharset;
+extern char *              SpamSeparator;
+extern bool                Weed;
+
+/* Global variables */
+extern struct ListHead     Ignore;
+extern struct RegexList *  NoSpamList;
+extern struct ReplaceList *SpamList;
+extern struct ListHead     UnIgnore;
 
 #endif /* _EMAIL_GLOBALS_H */
similarity index 85%
rename from parse.c
rename to email/parse.c
index 5107ddad99ec79b2388ac5c4b06dfb32cbb9524a..03be5acf68284f514fcee2cd439ca2d631f6c60f 100644 (file)
--- a/parse.c
@@ -3,7 +3,7 @@
  * Miscellaneous email parsing routines
  *
  * @authors
- * Copyright (C) 1996-2000,2012-2013 Michael R. Elkins <me@mutt.org>
+ * Copyright (C) 2018 Richard Russon <rich@flatcap.org>
  *
  * @copyright
  * This program is free software: you can redistribute it and/or modify it under
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+/**
+ * @page email_parse
+ *
+ * Miscellaneous email parsing routines
+ */
+
 #include "config.h"
-#include <ctype.h>
-#include <regex.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <time.h>
 #include "mutt/mutt.h"
-#include "email/email.h"
-#include "mutt.h"
 #include "parse.h"
-#include "globals.h"
-#include "mailbox.h"
-#include "muttlib.h"
-#include "ncrypt/ncrypt.h"
-#include "options.h"
-#include "protos.h"
-#include "recvattach.h"
+#include "address.h"
+#include "body.h"
+#include "email_globals.h"
+#include "envelope.h"
+#include "from.h"
+#include "header.h"
+#include "mime.h"
+#include "rfc2047.h"
+#include "rfc2231.h"
+#include "url.h"
 
-struct Context;
+/**
+ * mutt_matches_ignore - Does the string match the ignore list
+ *
+ * checks Ignore and UnIgnore using mutt_list_match
+ */
+bool mutt_matches_ignore(const char *s)
+{
+  return mutt_list_match(s, &Ignore) && !mutt_list_match(s, &UnIgnore);
+}
 
-/* These Config Variables are only used in parse.c */
-char *SpamSeparator;
+int mutt_check_mime_type(const char *s)
+{
+  if (mutt_str_strcasecmp("text", s) == 0)
+    return TYPETEXT;
+  else if (mutt_str_strcasecmp("multipart", s) == 0)
+    return TYPEMULTIPART;
+#ifdef SUN_ATTACHMENT
+  else if (mutt_str_strcasecmp("x-sun-attachment", s) == 0)
+    return TYPEMULTIPART;
+#endif
+  else if (mutt_str_strcasecmp("application", s) == 0)
+    return TYPEAPPLICATION;
+  else if (mutt_str_strcasecmp("message", s) == 0)
+    return TYPEMESSAGE;
+  else if (mutt_str_strcasecmp("image", s) == 0)
+    return TYPEIMAGE;
+  else if (mutt_str_strcasecmp("audio", s) == 0)
+    return TYPEAUDIO;
+  else if (mutt_str_strcasecmp("video", s) == 0)
+    return TYPEVIDEO;
+  else if (mutt_str_strcasecmp("model", s) == 0)
+    return TYPEMODEL;
+  else if (mutt_str_strcasecmp("*", s) == 0)
+    return TYPEANY;
+  else if (mutt_str_strcasecmp(".*", s) == 0)
+    return TYPEANY;
+  else
+    return TYPEOTHER;
+}
 
 /**
- * mutt_rfc822_read_line - Read a header line from a file
+ * mutt_extract_message_id - Find a message-id
  *
- * Reads an arbitrarily long header field, and looks ahead for continuation
- * lines.  ``line'' must point to a dynamically allocated string; it is
- * increased if more space is required to fit the whole line.
+ * extract the first substring that looks like a message-id.
+ * call back with NULL for more (like strtok).
  */
-char *mutt_rfc822_read_line(FILE *f, char *line, size_t *linelen)
+char *mutt_extract_message_id(const char *s, const char **saveptr)
 {
-  char *buf = line;
-  int ch;
-  size_t offset = 0;
+  const char *o = NULL, *onull = NULL, *p = NULL;
+  char *ret = NULL;
 
-  while (true)
+  if (s)
+    p = s;
+  else if (saveptr)
+    p = *saveptr;
+  else
+    return NULL;
+
+  for (s = NULL, o = NULL, onull = NULL; (p = strpbrk(p, "<> \t;")) != NULL; ++p)
   {
-    if (fgets(buf, *linelen - offset, f) == NULL || /* end of file or */
-        (ISSPACE(*line) && !offset))                /* end of headers */
+    if (*p == '<')
     {
-      *line = 0;
-      return line;
+      s = p;
+      o = onull = NULL;
+      continue;
     }
 
-    const size_t len = mutt_str_strlen(buf);
-    if (!len)
-      return line;
+    if (!s)
+      continue;
 
-    buf += len - 1;
-    if (*buf == '\n')
+    if (*p == '>')
     {
-      /* 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 */
-      ch = fgetc(f);
-      if ((ch != ' ') && (ch != '\t'))
-      {
-        ungetc(ch, f);
-        return line; /* next line is a separate header field or EOH */
-      }
-
-      /* 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 */
+      size_t olen = onull - o, slen = p - s + 1;
+      ret = mutt_mem_malloc(olen + slen + 1);
+      if (o)
+        memcpy(ret, o, olen);
+      memcpy(ret + olen, s, slen);
+      ret[olen + slen] = '\0';
+      if (saveptr)
+        *saveptr = p + 1; /* next call starts after '>' */
+      return ret;
     }
 
-    buf++;
-    offset = buf - line;
-    if (*linelen < offset + STRING)
+    /* some idiotic clients break their message-ids between lines */
+    if (s == p)
     {
-      /* grow the buffer */
-      *linelen += STRING;
-      mutt_mem_realloc(&line, *linelen);
-      buf = line + offset;
+      /* step past another whitespace */
+      s = p + 1;
+    }
+    else if (o)
+    {
+      /* more than two lines, give up */
+      s = o = onull = NULL;
+    }
+    else
+    {
+      /* remember the first line, start looking for the second */
+      o = s;
+      onull = p;
+      s = p + 1;
     }
   }
-  /* not reached */
-}
-
-/**
- * parse_references - Parse references from an email header
- * @param head List to receive the references
- * @param s    String to parse
- */
-static void parse_references(struct ListHead *head, char *s)
-{
-  char *m = NULL;
-  const char *sp = NULL;
 
-  while ((m = mutt_extract_message_id(s, &sp)))
-  {
-    mutt_list_insert_head(head, m);
-    s = NULL;
-  }
+  return NULL;
 }
 
 int mutt_check_encoding(const char *c)
@@ -268,34 +290,63 @@ bail:
   rfc2231_decode_parameters(param);
 }
 
-int mutt_check_mime_type(const char *s)
+static void parse_content_disposition(const char *s, struct Body *ct)
 {
-  if (mutt_str_strcasecmp("text", s) == 0)
-    return TYPETEXT;
-  else if (mutt_str_strcasecmp("multipart", s) == 0)
-    return TYPEMULTIPART;
-#ifdef SUN_ATTACHMENT
-  else if (mutt_str_strcasecmp("x-sun-attachment", s) == 0)
-    return TYPEMULTIPART;
-#endif
-  else if (mutt_str_strcasecmp("application", s) == 0)
-    return TYPEAPPLICATION;
-  else if (mutt_str_strcasecmp("message", s) == 0)
-    return TYPEMESSAGE;
-  else if (mutt_str_strcasecmp("image", s) == 0)
-    return TYPEIMAGE;
-  else if (mutt_str_strcasecmp("audio", s) == 0)
-    return TYPEAUDIO;
-  else if (mutt_str_strcasecmp("video", s) == 0)
-    return TYPEVIDEO;
-  else if (mutt_str_strcasecmp("model", s) == 0)
-    return TYPEMODEL;
-  else if (mutt_str_strcasecmp("*", s) == 0)
-    return TYPEANY;
-  else if (mutt_str_strcasecmp(".*", s) == 0)
-    return TYPEANY;
+  struct ParameterList parms;
+  TAILQ_INIT(&parms);
+
+  if (mutt_str_strncasecmp("inline", s, 6) == 0)
+    ct->disposition = DISPINLINE;
+  else if (mutt_str_strncasecmp("form-data", s, 9) == 0)
+    ct->disposition = DISPFORMDATA;
   else
-    return TYPEOTHER;
+    ct->disposition = DISPATTACH;
+
+  /* Check to see if a default filename was given */
+  s = strchr(s, ';');
+  if (s)
+  {
+    s = mutt_str_skip_email_wsp(s + 1);
+    parse_parameters(&parms, s);
+    s = mutt_param_get(&parms, "filename");
+    if (s)
+      mutt_str_replace(&ct->filename, s);
+    s = mutt_param_get(&parms, "name");
+    if (s)
+      ct->form_name = mutt_str_strdup(s);
+    mutt_param_free(&parms);
+  }
+}
+
+/**
+ * parse_references - Parse references from an email header
+ * @param head List to receive the references
+ * @param s    String to parse
+ */
+static void parse_references(struct ListHead *head, char *s)
+{
+  char *m = NULL;
+  const char *sp = NULL;
+
+  while ((m = mutt_extract_message_id(s, &sp)))
+  {
+    mutt_list_insert_head(head, m);
+    s = NULL;
+  }
+}
+
+/**
+ * mutt_parse_content_language - Read the content's language
+ * @param s  Language string
+ * @param ct Body of the email
+ */
+static void mutt_parse_content_language(char *s, struct Body *ct)
+{
+  if (!s || !ct)
+    return;
+
+  mutt_debug(2, "RFC8255 >> Content-Language set to %s\n", s);
+  ct->language = mutt_str_strdup(s);
 }
 
 void mutt_parse_content_type(char *s, struct Body *ct)
@@ -388,402 +439,10 @@ void mutt_parse_content_type(char *s, struct Body *ct)
   }
 }
 
-/**
- * mutt_parse_content_language - Read the content's language
- * @param s  Language string
- * @param ct Body of the email
- */
-static void mutt_parse_content_language(char *s, struct Body *ct)
-{
-  if (!s || !ct)
-    return;
-
-  mutt_debug(2, "RFC8255 >> Content-Language set to %s\n", s);
-  ct->language = mutt_str_strdup(s);
-}
-
-static void parse_content_disposition(const char *s, struct Body *ct)
+int mutt_rfc822_parse_line(struct Envelope *e, struct Header *hdr, char *line,
+                           char *p, short user_hdrs, short weed, short do_2047)
 {
-  struct ParameterList parms;
-  TAILQ_INIT(&parms);
-
-  if (mutt_str_strncasecmp("inline", s, 6) == 0)
-    ct->disposition = DISPINLINE;
-  else if (mutt_str_strncasecmp("form-data", s, 9) == 0)
-    ct->disposition = DISPFORMDATA;
-  else
-    ct->disposition = DISPATTACH;
-
-  /* Check to see if a default filename was given */
-  s = strchr(s, ';');
-  if (s)
-  {
-    s = mutt_str_skip_email_wsp(s + 1);
-    parse_parameters(&parms, s);
-    s = mutt_param_get(&parms, "filename");
-    if (s)
-      mutt_str_replace(&ct->filename, s);
-    s = mutt_param_get(&parms, "name");
-    if (s)
-      ct->form_name = mutt_str_strdup(s);
-    mutt_param_free(&parms);
-  }
-}
-
-/**
- * mutt_read_mime_header - Parse a MIME header
- * @param fp      stream to read from
- * @param digest  true if reading subparts of a multipart/digest
- * @retval ptr New Body containing parsed structure
- */
-struct Body *mutt_read_mime_header(FILE *fp, bool digest)
-{
-  struct Body *p = mutt_body_new();
-  char *c = NULL;
-  char *line = mutt_mem_malloc(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;
-
-  while (*(line = mutt_rfc822_read_line(fp, line, &linelen)) != 0)
-  {
-    /* Find the value of the current header */
-    c = strchr(line, ':');
-    if (c)
-    {
-      *c = 0;
-      c = mutt_str_skip_email_wsp(c + 1);
-      if (!*c)
-      {
-        mutt_debug(1, "skipping empty header field: %s\n", line);
-        continue;
-      }
-    }
-    else
-    {
-      mutt_debug(1, "bogus MIME header: %s\n", line);
-      break;
-    }
-
-    if (mutt_str_strncasecmp("content-", line, 8) == 0)
-    {
-      if (mutt_str_strcasecmp("type", line + 8) == 0)
-        mutt_parse_content_type(c, p);
-      else if (mutt_str_strcasecmp("language", line + 8) == 0)
-        mutt_parse_content_language(c, p);
-      else if (mutt_str_strcasecmp("transfer-encoding", line + 8) == 0)
-        p->encoding = mutt_check_encoding(c);
-      else if (mutt_str_strcasecmp("disposition", line + 8) == 0)
-        parse_content_disposition(c, p);
-      else if (mutt_str_strcasecmp("description", line + 8) == 0)
-      {
-        mutt_str_replace(&p->description, c);
-        rfc2047_decode(&p->description);
-      }
-    }
-#ifdef SUN_ATTACHMENT
-    else if (mutt_str_strncasecmp("x-sun-", line, 6) == 0)
-    {
-      if (mutt_str_strcasecmp("data-type", line + 6) == 0)
-        mutt_parse_content_type(c, p);
-      else if (mutt_str_strcasecmp("encoding-info", line + 6) == 0)
-        p->encoding = mutt_check_encoding(c);
-      else if (mutt_str_strcasecmp("content-lines", line + 6) == 0)
-        mutt_param_set(&p->parameter, "content-lines", c);
-      else if (mutt_str_strcasecmp("data-description", line + 6) == 0)
-      {
-        mutt_str_replace(&p->description, c);
-        rfc2047_decode(&p->description);
-      }
-    }
-#endif
-  }
-  p->offset = ftello(fp); /* Mark the start of the real data */
-  if (p->type == TYPETEXT && !p->subtype)
-    p->subtype = mutt_str_strdup("plain");
-  else if (p->type == TYPEMESSAGE && !p->subtype)
-    p->subtype = mutt_str_strdup("rfc822");
-
-  FREE(&line);
-
-  return p;
-}
-
-void mutt_parse_part(FILE *fp, struct Body *b)
-{
-  char *bound = NULL;
-
-  switch (b->type)
-  {
-    case TYPEMULTIPART:
-#ifdef SUN_ATTACHMENT
-      if (mutt_str_strcasecmp(b->subtype, "x-sun-attachment") == 0)
-        bound = "--------";
-      else
-#endif
-        bound = mutt_param_get(&b->parameter, "boundary");
-
-      fseeko(fp, b->offset, SEEK_SET);
-      b->parts = mutt_parse_multipart(fp, bound, b->offset + b->length,
-                                      (mutt_str_strcasecmp("digest", b->subtype) == 0));
-      break;
-
-    case TYPEMESSAGE:
-      if (b->subtype)
-      {
-        fseeko(fp, b->offset, SEEK_SET);
-        if (mutt_is_message_type(b->type, b->subtype))
-          b->parts = mutt_rfc822_parse_message(fp, b);
-        else if (mutt_str_strcasecmp(b->subtype, "external-body") == 0)
-          b->parts = mutt_read_mime_header(fp, 0);
-        else
-          return;
-      }
-      break;
-
-    default:
-      return;
-  }
-
-  /* try to recover from parsing error */
-  if (!b->parts)
-  {
-    b->type = TYPETEXT;
-    mutt_str_replace(&b->subtype, "plain");
-  }
-}
-
-/**
- * mutt_rfc822_parse_message - parse a Message/RFC822 body
- * @param fp     stream to read from
- * @param parent info about the message/rfc822 body part
- * @retval ptr New Body containing parsed message
- *
- * NOTE: this assumes that `parent->length' has been set!
- */
-struct Body *mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
-{
-  parent->hdr = mutt_header_new();
-  parent->hdr->offset = ftello(fp);
-  parent->hdr->env = mutt_rfc822_read_header(fp, parent->hdr, 0, 0);
-  struct Body *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);
-
-  /* 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);
-  return msg;
-}
-
-/**
- * mutt_parse_multipart - parse a multipart structure
- * @param fp       stream to read from
- * @param boundary body separator
- * @param end_off  length of the multipart body (used when the final
- *                 boundary is missing to avoid reading too far)
- * @param digest   true if reading a multipart/digest
- * @retval ptr New Body containing parsed structure
- */
-struct Body *mutt_parse_multipart(FILE *fp, const char *boundary, LOFF_T end_off, bool digest)
-{
-  char buffer[LONG_STRING];
-  struct Body *head = NULL, *last = NULL, *new = NULL;
-  bool final = false; /* did we see the ending boundary? */
-
-  if (!boundary)
-  {
-    mutt_error(_("multipart message has no boundary parameter!"));
-    return NULL;
-  }
-
-  const size_t blen = mutt_str_strlen(boundary);
-  while (ftello(fp) < end_off && fgets(buffer, LONG_STRING, fp) != NULL)
-  {
-    const size_t len = mutt_str_strlen(buffer);
-
-    const size_t crlf = (len > 1 && buffer[len - 2] == '\r') ? 1 : 0;
-
-    if (buffer[0] == '-' && buffer[1] == '-' &&
-        (mutt_str_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 (len > 0)
-      {
-        /* Remove any trailing whitespace, up to the length of the boundary */
-        for (size_t i = len - 1; ISSPACE(buffer[i]) && i >= blen + 2; i--)
-          buffer[i] = 0;
-      }
-
-      /* Check for the end boundary */
-      if (mutt_str_strcmp(buffer + blen + 2, "--") == 0)
-      {
-        final = true;
-        break; /* done parsing */
-      }
-      else if (buffer[2 + blen] == 0)
-      {
-        new = mutt_read_mime_header(fp, digest);
-
-#ifdef SUN_ATTACHMENT
-        if (mutt_param_get(&new->parameter, "content-lines"))
-        {
-          int lines;
-          if (mutt_str_atoi(mutt_param_get(&new->parameter, "content-lines"), &lines) < 0)
-            lines = 0;
-          for (; lines; lines--)
-            if (ftello(fp) >= end_off || fgets(buffer, LONG_STRING, fp) == NULL)
-              break;
-        }
-#endif
-
-        /*
-         * Consistency checking - catch
-         * bad attachment end boundaries
-         */
-
-        if (new->offset > end_off)
-        {
-          mutt_body_free(&new);
-          break;
-        }
-        if (head)
-        {
-          last->next = new;
-          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;
-
-  /* parse recursive MIME parts */
-  for (last = head; last; last = last->next)
-    mutt_parse_part(fp, last);
-
-  return head;
-}
-
-/**
- * mutt_extract_message_id - Find a message-id
- *
- * extract the first substring that looks like a message-id.
- * call back with NULL for more (like strtok).
- */
-char *mutt_extract_message_id(const char *s, const char **saveptr)
-{
-  const char *o = NULL, *onull = NULL, *p = NULL;
-  char *ret = NULL;
-
-  if (s)
-    p = s;
-  else if (saveptr)
-    p = *saveptr;
-  else
-    return NULL;
-
-  for (s = NULL, o = NULL, onull = NULL; (p = strpbrk(p, "<> \t;")) != NULL; ++p)
-  {
-    if (*p == '<')
-    {
-      s = p;
-      o = onull = NULL;
-      continue;
-    }
-
-    if (!s)
-      continue;
-
-    if (*p == '>')
-    {
-      size_t olen = onull - o, slen = p - s + 1;
-      ret = mutt_mem_malloc(olen + slen + 1);
-      if (o)
-        memcpy(ret, o, olen);
-      memcpy(ret + olen, s, slen);
-      ret[olen + slen] = '\0';
-      if (saveptr)
-        *saveptr = p + 1; /* next call starts after '>' */
-      return ret;
-    }
-
-    /* some idiotic clients break their message-ids between lines */
-    if (s == p)
-    {
-      /* step past another whitespace */
-      s = p + 1;
-    }
-    else if (o)
-    {
-      /* more than two lines, give up */
-      s = o = onull = NULL;
-    }
-    else
-    {
-      /* remember the first line, start looking for the second */
-      o = s;
-      onull = p;
-      s = p + 1;
-    }
-  }
-
-  return NULL;
-}
-
-void mutt_parse_mime_message(struct Context *ctx, struct Header *cur)
-{
-  struct Message *msg = NULL;
-
-  do
-  {
-    if (cur->content->type != TYPEMESSAGE && cur->content->type != TYPEMULTIPART)
-      break; /* nothing to do */
-
-    if (cur->content->parts)
-      break; /* The message was parsed earlier. */
-
-    msg = mx_msg_open(ctx, cur->msgno);
-    if (msg)
-    {
-      mutt_parse_part(msg->fp, cur->content);
-
-      if (WithCrypto)
-        cur->security = crypt_query(cur->content);
-
-      mx_msg_close(ctx, &msg);
-    }
-  } while (0);
-
-  cur->attach_valid = false;
-}
-
-int mutt_rfc822_parse_line(struct Envelope *e, struct Header *hdr, char *line,
-                           char *p, short user_hdrs, short weed, short do_2047)
-{
-  int matched = 0;
+  int matched = 0;
 
   switch (tolower(line[0]))
   {
@@ -1153,15 +812,80 @@ int mutt_rfc822_parse_line(struct Envelope *e, struct Header *hdr, char *line,
     /* restore the original line */
     line[strlen(line)] = ':';
 
-    if (!(weed && Weed && mutt_matches_ignore(line)))
+    if (!(weed && Weed && mutt_matches_ignore(line)))
+    {
+      struct ListNode *np = mutt_list_insert_tail(&e->userhdrs, mutt_str_strdup(line));
+      if (do_2047)
+        rfc2047_decode(&np->data);
+    }
+  }
+
+  return matched;
+}
+
+/**
+ * mutt_rfc822_read_line - Read a header line from a file
+ *
+ * Reads an arbitrarily long header field, and looks ahead for continuation
+ * lines.  ``line'' must point to a dynamically allocated string; it is
+ * increased if more space is required to fit the whole line.
+ */
+char *mutt_rfc822_read_line(FILE *f, char *line, size_t *linelen)
+{
+  char *buf = line;
+  int ch;
+  size_t offset = 0;
+
+  while (true)
+  {
+    if (fgets(buf, *linelen - offset, f) == NULL || /* end of file or */
+        (ISSPACE(*line) && !offset))                /* end of headers */
+    {
+      *line = 0;
+      return line;
+    }
+
+    const size_t len = mutt_str_strlen(buf);
+    if (!len)
+      return line;
+
+    buf += len - 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 */
+      ch = fgetc(f);
+      if ((ch != ' ') && (ch != '\t'))
+      {
+        ungetc(ch, f);
+        return line; /* next line is a separate header field or EOH */
+      }
+
+      /* 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 */
+    }
+
+    buf++;
+    offset = buf - line;
+    if (*linelen < offset + STRING)
     {
-      struct ListNode *np = mutt_list_insert_tail(&e->userhdrs, mutt_str_strdup(line));
-      if (do_2047)
-        rfc2047_decode(&np->data);
+      /* grow the buffer */
+      *linelen += STRING;
+      mutt_mem_realloc(&line, *linelen);
+      buf = line + offset;
     }
   }
-
-  return matched;
+  /* not reached */
 }
 
 /**
@@ -1331,160 +1055,275 @@ struct Envelope *mutt_rfc822_read_header(FILE *f, struct Header *hdr,
 }
 
 /**
- * count_body_parts_check - Compares mime types to the ok and except lists
- * @param checklist List of AttachMatch
- * @param b         Email Body
- * @param dflt      Log whether the matches are OK, or Excluded
- * @retval true Attachment should be counted
+ * mutt_read_mime_header - Parse a MIME header
+ * @param fp      stream to read from
+ * @param digest  true if reading subparts of a multipart/digest
+ * @retval ptr New Body containing parsed structure
  */
-static bool count_body_parts_check(struct ListHead *checklist, struct Body *b, bool dflt)
+struct Body *mutt_read_mime_header(FILE *fp, bool digest)
 {
-  struct AttachMatch *a = NULL;
+  struct Body *p = mutt_body_new();
+  char *c = NULL;
+  char *line = mutt_mem_malloc(LONG_STRING);
+  size_t linelen = LONG_STRING;
 
-  /* If list is null, use default behavior. */
-  if (!checklist || STAILQ_EMPTY(checklist))
-  {
-    return false;
-  }
+  p->hdr_offset = ftello(fp);
+
+  p->encoding = ENC7BIT; /* default from RFC1521 */
+  p->type = digest ? TYPEMESSAGE : TYPETEXT;
+  p->disposition = DISPINLINE;
 
-  struct ListNode *np = NULL;
-  STAILQ_FOREACH(np, checklist, entries)
+  while (*(line = mutt_rfc822_read_line(fp, line, &linelen)) != 0)
   {
-    a = (struct AttachMatch *) np->data;
-    mutt_debug(5, "%s %d/%s ?? %s/%s [%d]... ", dflt ? "[OK]   " : "[EXCL] ", b->type,
-               b->subtype ? b->subtype : "*", a->major, a->minor, a->major_int);
-    if ((a->major_int == TYPEANY || a->major_int == b->type) &&
-        (!b->subtype || !regexec(&a->minor_regex, b->subtype, 0, NULL, 0)))
+    /* Find the value of the current header */
+    c = strchr(line, ':');
+    if (c)
     {
-      mutt_debug(5, "yes\n");
-      return true;
+      *c = 0;
+      c = mutt_str_skip_email_wsp(c + 1);
+      if (!*c)
+      {
+        mutt_debug(1, "skipping empty header field: %s\n", line);
+        continue;
+      }
     }
     else
     {
-      mutt_debug(5, "no\n");
+      mutt_debug(1, "bogus MIME header: %s\n", line);
+      break;
+    }
+
+    if (mutt_str_strncasecmp("content-", line, 8) == 0)
+    {
+      if (mutt_str_strcasecmp("type", line + 8) == 0)
+        mutt_parse_content_type(c, p);
+      else if (mutt_str_strcasecmp("language", line + 8) == 0)
+        mutt_parse_content_language(c, p);
+      else if (mutt_str_strcasecmp("transfer-encoding", line + 8) == 0)
+        p->encoding = mutt_check_encoding(c);
+      else if (mutt_str_strcasecmp("disposition", line + 8) == 0)
+        parse_content_disposition(c, p);
+      else if (mutt_str_strcasecmp("description", line + 8) == 0)
+      {
+        mutt_str_replace(&p->description, c);
+        rfc2047_decode(&p->description);
+      }
+    }
+#ifdef SUN_ATTACHMENT
+    else if (mutt_str_strncasecmp("x-sun-", line, 6) == 0)
+    {
+      if (mutt_str_strcasecmp("data-type", line + 6) == 0)
+        mutt_parse_content_type(c, p);
+      else if (mutt_str_strcasecmp("encoding-info", line + 6) == 0)
+        p->encoding = mutt_check_encoding(c);
+      else if (mutt_str_strcasecmp("content-lines", line + 6) == 0)
+        mutt_param_set(&p->parameter, "content-lines", c);
+      else if (mutt_str_strcasecmp("data-description", line + 6) == 0)
+      {
+        mutt_str_replace(&p->description, c);
+        rfc2047_decode(&p->description);
+      }
     }
+#endif
   }
+  p->offset = ftello(fp); /* Mark the start of the real data */
+  if (p->type == TYPETEXT && !p->subtype)
+    p->subtype = mutt_str_strdup("plain");
+  else if (p->type == TYPEMESSAGE && !p->subtype)
+    p->subtype = mutt_str_strdup("rfc822");
+
+  FREE(&line);
 
-  return false;
+  return p;
 }
 
-static int count_body_parts(struct Body *body, int flags)
+/**
+ * mutt_is_message_type - Determine if a mime type matches a message or not
+ * @param type    Message type enum value
+ * @param subtype Message subtype
+ * @retval true  Type is message/news or message/rfc822
+ * @retval false Otherwise
+ */
+bool mutt_is_message_type(int type, const char *subtype)
 {
-  int count = 0;
+  if (type != TYPEMESSAGE)
+    return false;
+
+  subtype = NONULL(subtype);
+  return ((mutt_str_strcasecmp(subtype, "rfc822") == 0) ||
+          (mutt_str_strcasecmp(subtype, "news") == 0));
+}
 
-  if (!body)
-    return 0;
+void mutt_parse_part(FILE *fp, struct Body *b)
+{
+  char *bound = NULL;
 
-  for (struct Body *bp = body; bp != NULL; bp = bp->next)
+  switch (b->type)
   {
-    /* Initial disposition is to count and not to recurse this part. */
-    bool shallcount = true; /* default */
-    bool shallrecurse = false;
+    case TYPEMULTIPART:
+#ifdef SUN_ATTACHMENT
+      if (mutt_str_strcasecmp(b->subtype, "x-sun-attachment") == 0)
+        bound = "--------";
+      else
+#endif
+        bound = mutt_param_get(&b->parameter, "boundary");
 
-    mutt_debug(5, "desc=\"%s\"; fn=\"%s\", type=\"%d/%s\"\n",
-               bp->description ? bp->description : ("none"),
-               bp->filename ? bp->filename : bp->d_filename ? bp->d_filename : "(none)",
-               bp->type, bp->subtype ? bp->subtype : "*");
+      fseeko(fp, b->offset, SEEK_SET);
+      b->parts = mutt_parse_multipart(fp, bound, b->offset + b->length,
+                                      (mutt_str_strcasecmp("digest", b->subtype) == 0));
+      break;
 
-    if (bp->type == TYPEMESSAGE)
-    {
-      shallrecurse = true;
+    case TYPEMESSAGE:
+      if (b->subtype)
+      {
+        fseeko(fp, b->offset, SEEK_SET);
+        if (mutt_is_message_type(b->type, b->subtype))
+          b->parts = mutt_rfc822_parse_message(fp, b);
+        else if (mutt_str_strcasecmp(b->subtype, "external-body") == 0)
+          b->parts = mutt_read_mime_header(fp, 0);
+        else
+          return;
+      }
+      break;
 
-      /* If it's an external body pointer, don't recurse it. */
-      if (mutt_str_strcasecmp(bp->subtype, "external-body") == 0)
-        shallrecurse = false;
+    default:
+      return;
+  }
 
-      /* Don't count containers if they're top-level. */
-      if (flags & MUTT_PARTS_TOPLEVEL)
-        shallcount = false; // top-level message/*
-    }
-    else if (bp->type == TYPEMULTIPART)
-    {
-      /* Always recurse multiparts, except multipart/alternative. */
-      shallrecurse = true;
-      if (mutt_str_strcasecmp(bp->subtype, "alternative") == 0)
-        shallrecurse = false;
-
-      /* Don't count containers if they're top-level. */
-      if (flags & MUTT_PARTS_TOPLEVEL)
-        shallcount = false; /* top-level multipart */
-    }
+  /* try to recover from parsing error */
+  if (!b->parts)
+  {
+    b->type = TYPETEXT;
+    mutt_str_replace(&b->subtype, "plain");
+  }
+}
 
-    if (bp->disposition == DISPINLINE && bp->type != TYPEMULTIPART &&
-        bp->type != TYPEMESSAGE && bp == body)
-    {
-      shallcount = false; /* ignore fundamental inlines */
-    }
+/**
+ * mutt_parse_multipart - parse a multipart structure
+ * @param fp       stream to read from
+ * @param boundary body separator
+ * @param end_off  length of the multipart body (used when the final
+ *                 boundary is missing to avoid reading too far)
+ * @param digest   true if reading a multipart/digest
+ * @retval ptr New Body containing parsed structure
+ */
+struct Body *mutt_parse_multipart(FILE *fp, const char *boundary, LOFF_T end_off, bool digest)
+{
+  char buffer[LONG_STRING];
+  struct Body *head = NULL, *last = NULL, *new = NULL;
+  bool final = false; /* did we see the ending boundary? */
 
-    /* If this body isn't scheduled for enumeration already, don't bother
-     * profiling it further.
-     */
-    if (shallcount)
+  if (!boundary)
+  {
+    mutt_error(_("multipart message has no boundary parameter!"));
+    return NULL;
+  }
+
+  const size_t blen = mutt_str_strlen(boundary);
+  while (ftello(fp) < end_off && fgets(buffer, LONG_STRING, fp) != NULL)
+  {
+    const size_t len = mutt_str_strlen(buffer);
+
+    const size_t crlf = (len > 1 && buffer[len - 2] == '\r') ? 1 : 0;
+
+    if (buffer[0] == '-' && buffer[1] == '-' &&
+        (mutt_str_strncmp(buffer + 2, boundary, blen) == 0))
     {
-      /* Turn off shallcount if message type is not in ok list,
-       * or if it is in except list. Check is done separately for
-       * inlines vs. attachments.
-       */
+      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 (bp->disposition == DISPATTACH)
+      if (len > 0)
       {
-        if (!count_body_parts_check(&AttachAllow, bp, true))
-          shallcount = false; /* attach not allowed */
-        if (count_body_parts_check(&AttachExclude, bp, false))
-          shallcount = false; /* attach excluded */
+        /* Remove any trailing whitespace, up to the length of the boundary */
+        for (size_t i = len - 1; ISSPACE(buffer[i]) && i >= blen + 2; i--)
+          buffer[i] = 0;
       }
-      else
+
+      /* Check for the end boundary */
+      if (mutt_str_strcmp(buffer + blen + 2, "--") == 0)
       {
-        if (!count_body_parts_check(&InlineAllow, bp, true))
-          shallcount = false; /* inline not allowed */
-        if (count_body_parts_check(&InlineExclude, bp, false))
-          shallcount = false; /* excluded */
+        final = true;
+        break; /* done parsing */
       }
-    }
+      else if (buffer[2 + blen] == 0)
+      {
+        new = mutt_read_mime_header(fp, digest);
 
-    if (shallcount)
-      count++;
-    bp->attach_qualifies = shallcount ? true : false;
+#ifdef SUN_ATTACHMENT
+        if (mutt_param_get(&new->parameter, "content-lines"))
+        {
+          int lines;
+          if (mutt_str_atoi(mutt_param_get(&new->parameter, "content-lines"), &lines) < 0)
+            lines = 0;
+          for (; lines; lines--)
+            if (ftello(fp) >= end_off || fgets(buffer, LONG_STRING, fp) == NULL)
+              break;
+        }
+#endif
 
-    mutt_debug(5, "%p shallcount = %d\n", (void *) bp, shallcount);
+        /*
+         * Consistency checking - catch
+         * bad attachment end boundaries
+         */
 
-    if (shallrecurse)
-    {
-      mutt_debug(5, "%p pre count = %d\n", (void *) bp, count);
-      bp->attach_count = count_body_parts(bp->parts, flags & ~MUTT_PARTS_TOPLEVEL);
-      count += bp->attach_count;
-      mutt_debug(5, "%p post count = %d\n", (void *) bp, count);
+        if (new->offset > end_off)
+        {
+          mutt_body_free(&new);
+          break;
+        }
+        if (head)
+        {
+          last->next = new;
+          last = new;
+        }
+        else
+          last = head = new;
+      }
     }
   }
 
-  mutt_debug(5, "return %d\n", count < 0 ? 0 : count);
-  return (count < 0) ? 0 : count;
-}
-
-int mutt_count_body_parts(struct Context *ctx, struct Header *hdr)
-{
-  bool keep_parts = false;
+  /* in case of missing end boundary, set the length to something reasonable */
+  if (last && last->length == 0 && !final)
+    last->length = end_off - last->offset;
 
-  if (hdr->attach_valid)
-    return hdr->attach_total;
+  /* parse recursive MIME parts */
+  for (last = head; last; last = last->next)
+    mutt_parse_part(fp, last);
 
-  if (hdr->content->parts)
-    keep_parts = true;
-  else
-    mutt_parse_mime_message(ctx, hdr);
+  return head;
+}
 
-  if (!STAILQ_EMPTY(&AttachAllow) || !STAILQ_EMPTY(&AttachExclude) ||
-      !STAILQ_EMPTY(&InlineAllow) || !STAILQ_EMPTY(&InlineExclude))
-  {
-    hdr->attach_total = count_body_parts(hdr->content, MUTT_PARTS_TOPLEVEL);
-  }
-  else
-    hdr->attach_total = 0;
+/**
+ * mutt_rfc822_parse_message - parse a Message/RFC822 body
+ * @param fp     stream to read from
+ * @param parent info about the message/rfc822 body part
+ * @retval ptr New Body containing parsed message
+ *
+ * NOTE: this assumes that 'parent->length' has been set!
+ */
+struct Body *mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
+{
+  parent->hdr = mutt_header_new();
+  parent->hdr->offset = ftello(fp);
+  parent->hdr->env = mutt_rfc822_read_header(fp, parent->hdr, 0, 0);
+  struct Body *msg = parent->hdr->content;
 
-  hdr->attach_valid = true;
+  /* 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);
 
-  if (!keep_parts)
-    mutt_body_free(&hdr->content->parts);
+  /* if body of this message is empty, we can end up with a negative length */
+  if (msg->length < 0)
+    msg->length = 0;
 
-  return hdr->attach_total;
+  mutt_parse_part(fp, msg);
+  return msg;
 }
similarity index 80%
rename from parse.h
rename to email/parse.h
index 44ffcfecaa1aa91e55f10591b840e68ce906d986..955c0eab4d230246f5dcdfd22ee23d2973bd7246 100644 (file)
--- a/parse.h
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef MUTT_PARSE_H
-#define MUTT_PARSE_H
+#ifndef _EMAIL_PARSE_H
+#define _EMAIL_PARSE_H
 
-#include <stdbool.h>
 #include <stdio.h>
 
 struct Body;
-struct Context;
 struct Envelope;
 struct Header;
 
-/* These Config Variables are only used in parse.c */
-extern char *SpamSeparator;
-
-#define MUTT_PARTS_TOPLEVEL (1 << 0) /* is the top-level part */
-
+struct Envelope *mutt_rfc822_read_header(FILE *f, struct Header *hdr, short user_hdrs, short weed);
+char *           mutt_rfc822_read_line(FILE *f, char *line, size_t *linelen);
+int              mutt_rfc822_parse_line(struct Envelope *e, struct Header *hdr, char *line, char *p, short user_hdrs, short weed, short do_2047);
 int              mutt_check_encoding(const char *c);
 int              mutt_check_mime_type(const char *s);
-int              mutt_count_body_parts(struct Context *ctx, struct Header *hdr);
 char *           mutt_extract_message_id(const char *s, const char **saveptr);
 void             mutt_parse_content_type(char *s, struct Body *ct);
-void             mutt_parse_mime_message(struct Context *ctx, struct Header *cur);
-struct Body *    mutt_parse_multipart(FILE *fp, const char *boundary, LOFF_T end_off, bool digest);
-void             mutt_parse_part(FILE *fp, struct Body *b);
 struct Body *    mutt_read_mime_header(FILE *fp, bool digest);
-int              mutt_rfc822_parse_line(struct Envelope *e, struct Header *hdr, char *line, char *p, short user_hdrs, short weed, short do_2047);
+
+bool mutt_is_message_type(int type, const char *subtype);
+void             mutt_parse_part(FILE *fp, struct Body *b);
+struct Body *    mutt_parse_multipart(FILE *fp, const char *boundary, LOFF_T end_off, bool digest);
 struct Body *    mutt_rfc822_parse_message(FILE *fp, struct Body *parent);
-struct Envelope *mutt_rfc822_read_header(FILE *f, struct Header *hdr, short user_hdrs, short weed);
-char *           mutt_rfc822_read_line(FILE *f, char *line, size_t *linelen);
 
-#endif /* MUTT_PARSE_H */
+#endif /* _EMAIL_PARSE_H */
index 79d43778e3f0f3a6a9ede46ea7915953315c6abb..5fb1c57f524aebf50d6c8daefec194cae85941e2 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -60,14 +60,12 @@ WHERE struct Hash *TagFormats;
 WHERE struct ListHead AlternativeOrderList INITVAL(STAILQ_HEAD_INITIALIZER(AlternativeOrderList));
 WHERE struct ListHead AutoViewList INITVAL(STAILQ_HEAD_INITIALIZER(AutoViewList));
 WHERE struct ListHead HeaderOrderList INITVAL(STAILQ_HEAD_INITIALIZER(HeaderOrderList));
-WHERE struct ListHead Ignore INITVAL(STAILQ_HEAD_INITIALIZER(Ignore));
 WHERE struct ListHead MailToAllow INITVAL(STAILQ_HEAD_INITIALIZER(MailToAllow));
 WHERE struct ListHead MimeLookupList INITVAL(STAILQ_HEAD_INITIALIZER(MimeLookupList));
 WHERE struct ListHead Muttrc INITVAL(STAILQ_HEAD_INITIALIZER(Muttrc));
 #ifdef USE_SIDEBAR
 WHERE struct ListHead SidebarWhitelist INITVAL(STAILQ_HEAD_INITIALIZER(SidebarWhitelist));
 #endif
-WHERE struct ListHead UnIgnore INITVAL(STAILQ_HEAD_INITIALIZER(UnIgnore));
 WHERE struct ListHead UserHeader INITVAL(STAILQ_HEAD_INITIALIZER(UserHeader));
 
 /* Lists of AttachMatch */
@@ -82,8 +80,6 @@ WHERE struct RegexList *MailLists;
 WHERE struct RegexList *UnMailLists;
 WHERE struct RegexList *SubscribedLists;
 WHERE struct RegexList *UnSubscribedLists;
-WHERE struct ReplaceList *SpamList;
-WHERE struct RegexList *NoSpamList;
 WHERE struct ReplaceList *SubjectRegexList;
 
 WHERE unsigned short Counter;
@@ -185,7 +181,6 @@ WHERE char *NmQueryWindowCurrentSearch;
 /* These variables are backing for config items */
 WHERE struct Regex *Mask;
 WHERE struct Regex *QuoteRegex;
-WHERE struct Regex *ReplyRegex;
 
 /* Quad-options */
 WHERE unsigned char Bounce;
@@ -251,7 +246,6 @@ WHERE bool SslVerifyPartialChains;
 WHERE bool MailCheckRecent;
 WHERE bool MaildirTrash;
 WHERE bool Markers;
-WHERE bool MarkOld;
 #if defined(USE_IMAP) || defined(USE_POP)
 WHERE bool MessageCacheClean;
 #endif
@@ -275,7 +269,6 @@ WHERE bool UseDomain;
 WHERE bool UseIpv6;
 #endif
 WHERE bool WaitKey;
-WHERE bool Weed;
 WHERE bool WrapSearch;
 WHERE bool WriteBcc; /**< write out a bcc header? */
 
index f5cf6202f35cb2cdeec3a3551fdc1c8a63851242..775e0fe7f3b34120e71cbec1564ce516f5e04811 100644 (file)
--- a/handler.c
+++ b/handler.c
 #include "keymap.h"
 #include "mutt_attach.h"
 #include "mutt_logging.h"
+#include "mutt_parse.h"
 #include "muttlib.h"
 #include "ncrypt/ncrypt.h"
 #include "opcodes.h"
 #include "options.h"
-#include "parse.h"
 #include "protos.h"
 #include "recvattach.h"
 #include "rfc1524.h"
index 25e15727addb9b3086d006d4d3d5cb37c808358f..f5aa346ae7f4954bc5374ef2fbe863f3fe044b38 100644 (file)
--- a/hdrline.c
+++ b/hdrline.c
 #include "globals.h"
 #include "mbtable.h"
 #include "mutt_curses.h"
+#include "mutt_parse.h"
 #include "mutt_thread.h"
 #include "mutt_window.h"
 #include "muttlib.h"
 #include "ncrypt/ncrypt.h"
 #include "options.h"
-#include "parse.h"
 #include "protos.h"
 #include "sort.h"
 
index 6a2367ddd8713e2f57e44684b32d3f4cd4606289..878ec75c88ffc7a3a031faa0b310c14a10665745 100644 (file)
@@ -53,7 +53,6 @@
 #include "muttlib.h"
 #include "mx.h"
 #include "options.h"
-#include "parse.h"
 #include "progress.h"
 #include "protos.h"
 #ifdef USE_HCACHE
diff --git a/init.h b/init.h
index 5f97fe9b69c11db47770a5aa1c468915f3063f69..2240392c44c38036d5927e43181a256f667fd21c 100644 (file)
--- a/init.h
+++ b/init.h
@@ -64,7 +64,6 @@
 #include "notmuch/mutt_notmuch.h"
 #include "options.h"
 #include "pager.h"
-#include "parse.h"
 #include "pattern.h"
 #include "pop/pop.h"
 #include "progress.h"
index 558ff38d0f7985339fe9234bfed283824c115915..7bdead18d0d5033d872b1369f601b8c4b2cb6ea4 100644 (file)
@@ -57,7 +57,6 @@
 #include "muttlib.h"
 #include "mx.h"
 #include "options.h"
-#include "parse.h"
 #include "progress.h"
 #include "protos.h"
 #include "sort.h"
index bb422b93e98e8eb4205d3ee3fb8e84b48f10dd12..a51124f66a84438ec4fb174a517436d9df3313c1 100644 (file)
@@ -51,7 +51,6 @@
 #include "muttlib.h"
 #include "mx.h"
 #include "options.h"
-#include "parse.h"
 #include "progress.h"
 #include "protos.h"
 #include "sort.h"
index 74078d27d9794fc24c7316b2b329984af1677ddf..f7bccf0c3cafdabaff059433c44b5a6adca6a44c 100644 (file)
@@ -48,7 +48,6 @@
 #include "ncrypt/ncrypt.h"
 #include "options.h"
 #include "pager.h"
-#include "parse.h"
 #include "protos.h"
 #include "recvattach.h"
 #include "rfc1524.h"
index c2e089e7cbd523a1538e3bb2cdf3f8e4228f31fe..45ab8a69453efe0e6ad847347e3d9e8bfdf86510 100644 (file)
@@ -38,7 +38,6 @@
 #include "muttlib.h"
 #include "ncrypt/ncrypt.h"
 #include "options.h"
-#include "parse.h"
 #include "protos.h"
 #include "sendlib.h"
 
diff --git a/mutt_parse.c b/mutt_parse.c
new file mode 100644 (file)
index 0000000..3f8c346
--- /dev/null
@@ -0,0 +1,231 @@
+/**
+ * @file
+ * Miscellaneous email parsing routines
+ *
+ * @authors
+ * Copyright (C) 1996-2000,2012-2013 Michael R. Elkins <me@mutt.org>
+ *
+ * @copyright
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include <ctype.h>
+#include <regex.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "mutt/mutt.h"
+#include "email/email.h"
+#include "mutt.h"
+#include "mutt_parse.h"
+#include "globals.h"
+#include "mailbox.h"
+#include "muttlib.h"
+#include "ncrypt/ncrypt.h"
+#include "options.h"
+#include "protos.h"
+#include "recvattach.h"
+
+struct Context;
+
+#define MUTT_PARTS_TOPLEVEL (1 << 0) /* is the top-level part */
+
+void mutt_parse_mime_message(struct Context *ctx, struct Header *cur)
+{
+  struct Message *msg = NULL;
+
+  do
+  {
+    if (cur->content->type != TYPEMESSAGE && cur->content->type != TYPEMULTIPART)
+      break; /* nothing to do */
+
+    if (cur->content->parts)
+      break; /* The message was parsed earlier. */
+
+    msg = mx_msg_open(ctx, cur->msgno);
+    if (msg)
+    {
+      mutt_parse_part(msg->fp, cur->content);
+
+      if (WithCrypto)
+        cur->security = crypt_query(cur->content);
+
+      mx_msg_close(ctx, &msg);
+    }
+  } while (0);
+
+  cur->attach_valid = false;
+}
+
+/**
+ * count_body_parts_check - Compares mime types to the ok and except lists
+ * @param checklist List of AttachMatch
+ * @param b         Email Body
+ * @param dflt      Log whether the matches are OK, or Excluded
+ * @retval true Attachment should be counted
+ */
+static bool count_body_parts_check(struct ListHead *checklist, struct Body *b, bool dflt)
+{
+  struct AttachMatch *a = NULL;
+
+  /* If list is null, use default behavior. */
+  if (!checklist || STAILQ_EMPTY(checklist))
+  {
+    return false;
+  }
+
+  struct ListNode *np = NULL;
+  STAILQ_FOREACH(np, checklist, entries)
+  {
+    a = (struct AttachMatch *) np->data;
+    mutt_debug(5, "%s %d/%s ?? %s/%s [%d]... ", dflt ? "[OK]   " : "[EXCL] ", b->type,
+               b->subtype ? b->subtype : "*", a->major, a->minor, a->major_int);
+    if ((a->major_int == TYPEANY || a->major_int == b->type) &&
+        (!b->subtype || !regexec(&a->minor_regex, b->subtype, 0, NULL, 0)))
+    {
+      mutt_debug(5, "yes\n");
+      return true;
+    }
+    else
+    {
+      mutt_debug(5, "no\n");
+    }
+  }
+
+  return false;
+}
+
+static int count_body_parts(struct Body *body, int flags)
+{
+  int count = 0;
+
+  if (!body)
+    return 0;
+
+  for (struct Body *bp = body; bp != NULL; bp = bp->next)
+  {
+    /* Initial disposition is to count and not to recurse this part. */
+    bool shallcount = true; /* default */
+    bool shallrecurse = false;
+
+    mutt_debug(5, "desc=\"%s\"; fn=\"%s\", type=\"%d/%s\"\n",
+               bp->description ? bp->description : ("none"),
+               bp->filename ? bp->filename : bp->d_filename ? bp->d_filename : "(none)",
+               bp->type, bp->subtype ? bp->subtype : "*");
+
+    if (bp->type == TYPEMESSAGE)
+    {
+      shallrecurse = true;
+
+      /* If it's an external body pointer, don't recurse it. */
+      if (mutt_str_strcasecmp(bp->subtype, "external-body") == 0)
+        shallrecurse = false;
+
+      /* Don't count containers if they're top-level. */
+      if (flags & MUTT_PARTS_TOPLEVEL)
+        shallcount = false; // top-level message/*
+    }
+    else if (bp->type == TYPEMULTIPART)
+    {
+      /* Always recurse multiparts, except multipart/alternative. */
+      shallrecurse = true;
+      if (mutt_str_strcasecmp(bp->subtype, "alternative") == 0)
+        shallrecurse = false;
+
+      /* Don't count containers if they're top-level. */
+      if (flags & MUTT_PARTS_TOPLEVEL)
+        shallcount = false; /* top-level multipart */
+    }
+
+    if (bp->disposition == DISPINLINE && bp->type != TYPEMULTIPART &&
+        bp->type != TYPEMESSAGE && bp == body)
+    {
+      shallcount = false; /* ignore fundamental inlines */
+    }
+
+    /* If this body isn't scheduled for enumeration already, don't bother
+     * profiling it further.
+     */
+    if (shallcount)
+    {
+      /* Turn off shallcount if message type is not in ok list,
+       * or if it is in except list. Check is done separately for
+       * inlines vs. attachments.
+       */
+
+      if (bp->disposition == DISPATTACH)
+      {
+        if (!count_body_parts_check(&AttachAllow, bp, true))
+          shallcount = false; /* attach not allowed */
+        if (count_body_parts_check(&AttachExclude, bp, false))
+          shallcount = false; /* attach excluded */
+      }
+      else
+      {
+        if (!count_body_parts_check(&InlineAllow, bp, true))
+          shallcount = false; /* inline not allowed */
+        if (count_body_parts_check(&InlineExclude, bp, false))
+          shallcount = false; /* excluded */
+      }
+    }
+
+    if (shallcount)
+      count++;
+    bp->attach_qualifies = shallcount ? true : false;
+
+    mutt_debug(5, "%p shallcount = %d\n", (void *) bp, shallcount);
+
+    if (shallrecurse)
+    {
+      mutt_debug(5, "%p pre count = %d\n", (void *) bp, count);
+      bp->attach_count = count_body_parts(bp->parts, flags & ~MUTT_PARTS_TOPLEVEL);
+      count += bp->attach_count;
+      mutt_debug(5, "%p post count = %d\n", (void *) bp, count);
+    }
+  }
+
+  mutt_debug(5, "return %d\n", count < 0 ? 0 : count);
+  return (count < 0) ? 0 : count;
+}
+
+int mutt_count_body_parts(struct Context *ctx, struct Header *hdr)
+{
+  bool keep_parts = false;
+
+  if (hdr->attach_valid)
+    return hdr->attach_total;
+
+  if (hdr->content->parts)
+    keep_parts = true;
+  else
+    mutt_parse_mime_message(ctx, hdr);
+
+  if (!STAILQ_EMPTY(&AttachAllow) || !STAILQ_EMPTY(&AttachExclude) ||
+      !STAILQ_EMPTY(&InlineAllow) || !STAILQ_EMPTY(&InlineExclude))
+  {
+    hdr->attach_total = count_body_parts(hdr->content, MUTT_PARTS_TOPLEVEL);
+  }
+  else
+    hdr->attach_total = 0;
+
+  hdr->attach_valid = true;
+
+  if (!keep_parts)
+    mutt_body_free(&hdr->content->parts);
+
+  return hdr->attach_total;
+}
diff --git a/mutt_parse.h b/mutt_parse.h
new file mode 100644 (file)
index 0000000..1f39f52
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+ * @file
+ * Miscellaneous email parsing routines
+ *
+ * @authors
+ * Copyright (C) 2018 Richard Russon <rich@flatcap.org>
+ *
+ * @copyright
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MUTT_PARSE_H
+#define MUTT_PARSE_H
+
+struct Context;
+struct Header;
+
+int  mutt_count_body_parts(struct Context *ctx, struct Header *hdr);
+void mutt_parse_mime_message(struct Context *ctx, struct Header *cur);
+
+#endif /* MUTT_PARSE_H */
index 505088971de7eec8420df044b083a125caf5f9a3..eabdd46cd742bd6d4a0901fd0492971714570900 100644 (file)
@@ -28,7 +28,6 @@
 #include "email/email.h"
 #include "mutt.h"
 #include "globals.h"
-#include "parse.h"
 
 int url_parse_mailto(struct Envelope *e, char **body, const char *src)
 {
index fbcd3bc64929f1f7529bdefd60412b8fa3d2f2c3..8ec0de45dcacb5513501ba6a3d3554c29a0d85e8 100644 (file)
--- a/muttlib.c
+++ b/muttlib.c
@@ -106,16 +106,6 @@ void mutt_adv_mktemp(char *s, size_t l)
   }
 }
 
-/**
- * mutt_matches_ignore - Does the string match the ignore list
- *
- * checks Ignore and UnIgnore using mutt_list_match
- */
-bool mutt_matches_ignore(const char *s)
-{
-  return mutt_list_match(s, &Ignore) && !mutt_list_match(s, &UnIgnore);
-}
-
 char *mutt_expand_path(char *s, size_t slen)
 {
   return mutt_expand_path_regex(s, slen, false);
index 8b58b20c13f71ecc301ac447c15e0519cbd931ce..3523d8ca5b060983a142fa0fb89e06e2c550bc9d 100644 (file)
 #include "globals.h"
 #include "handler.h"
 #include "mutt_curses.h"
+#include "mutt_parse.h"
 #include "muttlib.h"
 #include "ncrypt.h"
 #include "options.h"
-#include "parse.h"
 #include "protos.h"
 #include "send.h"
 #include "sendlib.h"
index 0a0d7549fa40a892e09eaee69da8f9563f281055..ea7cad64f5d4cd23267fd5ba8ba75a468a205783 100644 (file)
 #include "mutt_attach.h"
 #include "mutt_curses.h"
 #include "mutt_logging.h"
+#include "mutt_parse.h"
 #include "mutt_window.h"
 #include "muttlib.h"
 #include "ncrypt.h"
 #include "opcodes.h"
 #include "options.h"
 #include "pager.h"
-#include "parse.h"
 #include "protos.h"
 #include "recvattach.h"
 #include "sendlib.h"
index 788cf6ebc66afebf3a9b0864184594c03e3317e4..ea36b0722be6c5a8ef40d3d64abf90ba288dfe46 100644 (file)
 #include "hook.h"
 #include "mutt_attach.h"
 #include "mutt_curses.h"
+#include "mutt_parse.h"
 #include "muttlib.h"
 #include "ncrypt.h"
 #include "options.h"
-#include "parse.h"
 #include "pgpinvoke.h"
 #include "pgplib.h"
 #include "pgpmicalg.h"
index 6f6befcb2859fbf28b88a9d334b4a243006a892f..3270d582e30d3d9fb5fc2a5c653fbf520a63990d 100644 (file)
 #include "menu.h"
 #include "mutt_curses.h"
 #include "mutt_logging.h"
+#include "mutt_parse.h"
 #include "mutt_window.h"
 #include "muttlib.h"
 #include "ncrypt.h"
 #include "opcodes.h"
 #include "options.h"
-#include "parse.h"
 #include "protos.h"
 #include "send.h"
 #include "sendlib.h"
index 5b1db002a61ebfe78eaea67e719d437415a1ec81..4214f7db66c9e03e7fc5f41a80d020744510d36c 100644 (file)
 #include "mailbox.h"
 #include "mutt_account.h"
 #include "mutt_logging.h"
+#include "mutt_parse.h"
 #include "mutt_socket.h"
 #include "mutt_thread.h"
 #include "muttlib.h"
 #include "mx.h"
 #include "ncrypt/ncrypt.h"
 #include "options.h"
-#include "parse.h"
 #include "progress.h"
 #include "protos.h"
 #include "sort.h"
index da420f571508a7b30d3a570a33eb8d2bfd9e0a2b..8dff75d42b548878ece55026fc4a792b801d160a 100644 (file)
--- a/pattern.c
+++ b/pattern.c
 #include "mailbox.h"
 #include "menu.h"
 #include "mutt_logging.h"
+#include "mutt_parse.h"
 #include "muttlib.h"
 #include "mx.h"
 #include "ncrypt/ncrypt.h"
 #include "opcodes.h"
 #include "options.h"
-#include "parse.h"
 #include "progress.h"
 #include "protos.h"
 #include "state.h"
index b15e18d36cb2aff37db2aff29dd4b5324aa919ce..d096ea094005d773988d8167c89c9494e30657e0 100644 (file)
--- a/pop/pop.c
+++ b/pop/pop.c
@@ -53,7 +53,6 @@
 #include "mx.h"
 #include "ncrypt/ncrypt.h"
 #include "options.h"
-#include "parse.h"
 #include "progress.h"
 #include "protos.h"
 #ifdef USE_HCACHE
index a32518e7e545b8633e6542135b7ec83f5ae3a430..acaf4cd33c87dc419513e8653f99de9a331aa129 100644 (file)
 #include "mailbox.h"
 #include "menu.h"
 #include "mutt_logging.h"
+#include "mutt_parse.h"
 #include "mutt_thread.h"
 #include "muttlib.h"
 #include "ncrypt/ncrypt.h"
 #include "opcodes.h"
 #include "options.h"
-#include "parse.h"
 #include "protos.h"
 #include "send.h"
 #include "sendlib.h"
index 0af6fbc3fa82149da511b6eae7793c3d4c417793..0b5533e696723933242579c73f98ad9126b06ae8 100644 (file)
 #include "mutt_attach.h"
 #include "mutt_curses.h"
 #include "mutt_logging.h"
+#include "mutt_parse.h"
 #include "mutt_window.h"
 #include "muttlib.h"
 #include "mx.h"
 #include "ncrypt/ncrypt.h"
 #include "opcodes.h"
 #include "options.h"
-#include "parse.h"
 #include "protos.h"
 #include "recvcmd.h"
 #include "rfc1524.h"
@@ -462,23 +462,6 @@ int mutt_tag_attach(struct Menu *menu, int n, int m)
   return (cur->tagged - ot);
 }
 
-/**
- * mutt_is_message_type - Determine if a mime type matches a message or not
- * @param type    Message type enum value
- * @param subtype Message subtype
- * @retval true  Type is message/news or message/rfc822
- * @retval false Otherwise
- */
-bool mutt_is_message_type(int type, const char *subtype)
-{
-  if (type != TYPEMESSAGE)
-    return false;
-
-  subtype = NONULL(subtype);
-  return ((mutt_str_strcasecmp(subtype, "rfc822") == 0) ||
-          (mutt_str_strcasecmp(subtype, "news") == 0));
-}
-
 /**
  * prepend_curdir - Add './' to the beginning of a path
  * @param buf    Buffer for the result
index 334d289a2b89cefabc83397a8fa7cb3838a2992b..d29cbbd3c2cdca7feda79b908dee0cc28668aa2c 100644 (file)
@@ -39,6 +39,5 @@ void mutt_update_tree(struct AttachCtx *actx);
 
 const char *attach_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, unsigned long data, enum FormatFlag flags);
 void mutt_view_attachments(struct Header *hdr);
-bool mutt_is_message_type(int type, const char *subtype);
 
 #endif /* _MUTT_RECVATTACH_H */
diff --git a/send.c b/send.c
index ae0350546a74eb4575015827aea6618360296921..4c735ee72da03374b5c9aa6e555f994fc6a5959a 100644 (file)
--- a/send.c
+++ b/send.c
 #include "mutt_attach.h"
 #include "mutt_header.h"
 #include "mutt_logging.h"
+#include "mutt_parse.h"
 #include "muttlib.h"
 #include "ncrypt/ncrypt.h"
 #include "options.h"
-#include "parse.h"
 #include "pattern.h"
 #include "protos.h"
 #include "rfc3676.h"
index 7dd397ea1918b9895eb2a12606a68e1e8d4d5e92..292533d159c24eb2c17a62a9690415429c39a610 100644 (file)
--- a/sendlib.c
+++ b/sendlib.c
 #include "handler.h"
 #include "mailbox.h"
 #include "mutt_curses.h"
+#include "mutt_parse.h"
 #include "mutt_window.h"
 #include "muttlib.h"
 #include "mx.h"
 #include "ncrypt/ncrypt.h"
 #include "options.h"
 #include "pager.h"
-#include "parse.h"
 #include "protos.h"
 #include "recvattach.h"
 #include "send.h"