+
+
+/* Compares mime types to the ok and except lists */
+int count_body_parts_check(LIST **checklist, BODY *b, int dflt) {
+ LIST *type;
+ ATTACH_MATCH *a;
+
+ /* If list is null, use default behavior. */
+ if (! *checklist) {
+ /*return dflt;*/
+ return 0;
+ }
+
+ for (type = *checklist; type; type = type->next) {
+ a = (ATTACH_MATCH *)type->data;
+ debug_print(5, ("cbpc: %s %d/%s ?? %s/%s [%d]... ",
+ dflt ? "[OK] " : "[EXCL] ",
+ b->type, b->subtype, a->major, a->minor, a->major_int));
+ if ((a->major_int == TYPEANY || a->major_int == b->type) &&
+ !regexec(&a->minor_rx, b->subtype, 0, NULL, 0)) {
+ debug_print(5, ("yes\n"));
+ return 1;
+ } else {
+ debug_print(5, ("no\n"));
+ }
+ }
+ return 0;
+}
+
+#define AT_COUNT(why) { shallcount = 1; }
+#define AT_NOCOUNT(why) { shallcount = 0; }
+
+int count_body_parts (BODY *body, int flags) {
+ int count = 0;
+ int shallcount, shallrecurse;
+ BODY *bp;
+
+ if (body == NULL)
+ return 0;
+
+ for (bp = body; bp != NULL; bp = bp->next) {
+ /* Initial disposition is to count and not to recurse this part. */
+ AT_COUNT("default");
+ shallrecurse = 0;
+
+ debug_print(5, ("bp: 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 = 1;
+
+ /* If it's an external body pointer, don't recurse it. */
+ if (!ascii_strcasecmp (bp->subtype, "external-body"))
+ shallrecurse = 0;
+
+ /* Don't count containers if they're top-level. */
+ if (flags & M_PARTS_TOPLEVEL)
+ AT_NOCOUNT("top-level message/*");
+ } else if (bp->type == TYPEMULTIPART) {
+ /* Always recurse multiparts, except multipart/alternative. */
+ shallrecurse = 1;
+ if (!str_casecmp(bp->subtype, "alternative"))
+ shallrecurse = 0;
+
+ /* Don't count containers if they're top-level. */
+ if (flags & M_PARTS_TOPLEVEL)
+ AT_NOCOUNT("top-level multipart");
+ }
+
+ if (bp->disposition == DISPINLINE &&
+ bp->type != TYPEMULTIPART && bp->type != TYPEMESSAGE && bp == body)
+ AT_NOCOUNT("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, 1))
+ AT_NOCOUNT("attach not allowed");
+ if (count_body_parts_check(&AttachExclude, bp, 0))
+ AT_NOCOUNT("attach excluded");
+ } else {
+ if (!count_body_parts_check(&InlineAllow, bp, 1))
+ AT_NOCOUNT("inline not allowed");
+ if (count_body_parts_check(&InlineExclude, bp, 0))
+ AT_NOCOUNT("excluded");
+ }
+ }
+
+ if (shallcount)
+ count++;
+ bp->attach_qualifies = shallcount ? 1 : 0;
+
+ debug_print(5, ("cbp: %08x shallcount = %d\n", (unsigned int)bp, shallcount));
+
+ if (shallrecurse) {
+ debug_print(5, ("cbp: %08x pre count = %d\n", (unsigned int)bp, count));
+ bp->attach_count = count_body_parts(bp->parts, flags & ~M_PARTS_TOPLEVEL);
+ count += bp->attach_count;
+ debug_print(5, ("cbp: %08x post count = %d\n", (unsigned int)bp, count));
+ }
+ }
+
+ debug_print(5, ("bp: return %d\n", count < 0 ? 0 : count));
+ return count < 0 ? 0 : count;
+}
+
+int mutt_count_body_parts (HEADER *hdr, int flags) {
+ if (!option (OPTCOUNTATTACH))
+ return (0);
+ if (hdr->attach_valid && !(flags & M_PARTS_RECOUNT))
+ return hdr->attach_total;
+
+ if (AttachAllow || AttachExclude || InlineAllow || InlineExclude)
+ hdr->attach_total = count_body_parts(hdr->content, flags | M_PARTS_TOPLEVEL);
+ else
+ hdr->attach_total = 0;
+
+ hdr->attach_valid = 1;
+ return hdr->attach_total;
+}