/** * @file * Miscellaneous email parsing routines * * @authors * Copyright (C) 1996-2000,2012-2013 Michael R. Elkins * * @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 . */ /** * @page mutt_parse Miscellaneous email parsing routines * * Miscellaneous email parsing routines */ #include "config.h" #include #include #include #include "mutt/mutt.h" #include "email/lib.h" #include "mutt_parse.h" #include "mx.h" #include "ncrypt/ncrypt.h" struct ListHead AttachAllow = STAILQ_HEAD_INITIALIZER(AttachAllow); ///< List of attachment types to be counted struct ListHead AttachExclude = STAILQ_HEAD_INITIALIZER(AttachExclude); ///< List of attachment types to be ignored struct ListHead InlineAllow = STAILQ_HEAD_INITIALIZER(InlineAllow); ///< List of inline types to counted struct ListHead InlineExclude = STAILQ_HEAD_INITIALIZER(InlineExclude); ///< List of inline types to ignore /** * mutt_parse_mime_message - Parse a MIME email * @param m Mailbox * @param e Email */ void mutt_parse_mime_message(struct Mailbox *m, struct Email *e) { do { if ((e->content->type != TYPE_MESSAGE) && (e->content->type != TYPE_MULTIPART)) break; /* nothing to do */ if (e->content->parts) break; /* The message was parsed earlier. */ struct Message *msg = mx_msg_open(m, e->msgno); if (msg) { mutt_parse_part(msg->fp, e->content); if (WithCrypto) e->security = crypt_query(e->content); mx_msg_close(m, &msg); } } while (false); e->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(LL_DEBUG3, "%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 == TYPE_ANY) || (a->major_int == b->type)) && (!b->subtype || !regexec(&a->minor_regex, b->subtype, 0, NULL, 0))) { mutt_debug(LL_DEBUG3, "yes\n"); return true; } else { mutt_debug(LL_DEBUG3, "no\n"); } } return false; } /** * count_body_parts - Count the MIME Body parts * @param body Body of email * @retval num Number of MIME Body parts */ static int count_body_parts(struct Body *body) { if (!body) return 0; int count = 0; for (struct Body *bp = body; bp; bp = bp->next) { /* Initial disposition is to count and not to recurse this part. */ bool shallcount = true; /* default */ bool shallrecurse = false; mutt_debug(LL_DEBUG5, "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 == TYPE_MESSAGE) { shallrecurse = true; /* If it's an external body pointer, don't recurse it. */ if (mutt_str_strcasecmp(bp->subtype, "external-body") == 0) shallrecurse = false; } else if (bp->type == TYPE_MULTIPART) { /* Always recurse multiparts, except multipart/alternative. */ shallrecurse = true; if (mutt_str_strcasecmp(bp->subtype, "alternative") == 0) shallrecurse = false; } if ((bp->disposition == DISP_INLINE) && (bp->type != TYPE_MULTIPART) && (bp->type != TYPE_MESSAGE) && (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 == DISP_ATTACH) { 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; mutt_debug(LL_DEBUG3, "%p shallcount = %d\n", (void *) bp, shallcount); if (shallrecurse) { mutt_debug(LL_DEBUG3, "%p pre count = %d\n", (void *) bp, count); bp->attach_count = count_body_parts(bp->parts); count += bp->attach_count; mutt_debug(LL_DEBUG3, "%p post count = %d\n", (void *) bp, count); } } mutt_debug(LL_DEBUG3, "return %d\n", (count < 0) ? 0 : count); return (count < 0) ? 0 : count; } /** * mutt_count_body_parts - Count the MIME Body parts * @param m Mailbox * @param e Email * @retval num Number of MIME Body parts */ int mutt_count_body_parts(struct Mailbox *m, struct Email *e) { bool keep_parts = false; if (e->attach_valid) return e->attach_total; if (e->content->parts) keep_parts = true; else mutt_parse_mime_message(m, e); if (!STAILQ_EMPTY(&AttachAllow) || !STAILQ_EMPTY(&AttachExclude) || !STAILQ_EMPTY(&InlineAllow) || !STAILQ_EMPTY(&InlineExclude)) { e->attach_total = count_body_parts(e->content); } else e->attach_total = 0; e->attach_valid = true; if (!keep_parts) mutt_body_free(&e->content->parts); return e->attach_total; }