#endif
#include "mutt.h"
-#include "mailbox.h"
+#include "buffer.h"
+#include "enter.h"
+#include "ascii.h"
+#include "recvattach.h"
+#include "mx.h"
#include "mime.h"
#include "rfc2047.h"
#include "rfc2231.h"
#include "lib/intl.h"
#include "lib/str.h"
#include "lib/rx.h"
+#include "lib/debug.h"
#include <string.h>
#include <ctype.h>
* lines. ``line'' must point to a dynamically allocated string; it is
* increased if more space is required to fit the whole line.
*/
-static char *read_rfc822_line (FILE * f, char *line, size_t * linelen)
+char *mutt_read_rfc822_line (FILE * f, char *line, size_t * linelen)
{
char *buf = line;
char ch;
return (line);
}
- buf += mutt_strlen (buf) - 1;
+ buf += str_len (buf) - 1;
if (*buf == '\n') {
/* we did get a full line. remove trailing space */
while (ISSPACE (*buf))
if (*linelen < offset + STRING) {
/* grow the buffer */
*linelen += STRING;
- safe_realloc (&line, *linelen);
+ mem_realloc (&line, *linelen);
buf = line + offset;
}
}
new = NULL;
if (*s == '<') {
- n = mutt_strlen (s);
+ n = str_len (s);
if (s[n - 1] != '>') {
o = s;
s = NULL;
continue;
}
- new = safe_strdup (s);
+ new = str_dup (s);
}
else if (o) {
- m = mutt_strlen (s);
+ m = str_len (s);
if (s[m - 1] == '>') {
- new = safe_malloc (sizeof (char) * (n + m + 1));
+ new = mem_malloc (sizeof (char) * (n + m + 1));
strcpy (new, o); /* __STRCPY_CHECKED__ */
strcpy (new + n, s); /* __STRCPY_CHECKED__ */
}
*/
if (!(at = strchr (new, '@')) || strchr (at + 1, '@')
|| (in_reply_to && at - new <= 8))
- FREE (&new);
+ mem_free (&new);
else {
- t = (LIST *) safe_malloc (sizeof (LIST));
+ t = (LIST *) mem_malloc (sizeof (LIST));
t->data = new;
t->next = lst;
lst = t;
const char *p;
size_t i;
- dprint (2, (debugfile, "parse_parameters: `%s'\n", s));
+ debug_print (2, ("`%s'\n", s));
while (*s) {
if ((p = strpbrk (s, "=;")) == NULL) {
- dprint (1,
- (debugfile, "parse_parameters: malformed parameter: %s\n", s));
+ debug_print (1, ("malformed parameter: %s\n", s));
goto bail;
}
new = mutt_new_parameter ();
- new->attribute = safe_malloc (i + 1);
+ new->attribute = mem_malloc (i + 1);
memcpy (new->attribute, s, i);
new->attribute[i] = 0;
buffer[i] = 0;
}
- new->value = safe_strdup (buffer);
+ new->value = str_dup (buffer);
- dprint (2, (debugfile, "parse_parameter: `%s' = `%s'\n",
- new->attribute ? new->attribute : "",
+ debug_print (2, ("`%s' = `%s'\n", new->attribute ? new->attribute : "",
new->value ? new->value : ""));
/* Add this parameter to the list */
head = cur = new;
}
else {
- dprint (1,
- (debugfile, "parse_parameters(): parameter with no value: %s\n",
- s));
+ debug_print (1, ("parameter with no value: %s\n", s));
s = p;
}
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;
}
char *pc;
char *subtype;
- FREE (&ct->subtype);
+ mem_free (&ct->subtype);
mutt_free_parameter (&ct->parameter);
/* First extract any existing parameters */
* let that take precedence, and don't set it here */
if ((pc = mutt_get_parameter ("name", ct->parameter)) != 0
&& !ct->filename)
- ct->filename = safe_strdup (pc);
+ ct->filename = str_dup (pc);
#ifdef SUN_ATTACHMENT
/* this is deep and utter perversion */
*subtype++ = '\0';
for (pc = subtype; *pc && !ISSPACE (*pc) && *pc != ';'; pc++);
*pc = '\0';
- ct->subtype = safe_strdup (subtype);
+ ct->subtype = str_dup (subtype);
}
/* Finally, get the major type */
#ifdef SUN_ATTACHMENT
if (ascii_strcasecmp ("x-sun-attachment", s) == 0)
- ct->subtype = safe_strdup ("x-sun-attachment");
+ ct->subtype = str_dup ("x-sun-attachment");
#endif
if (ct->type == TYPEOTHER) {
- ct->xtype = safe_strdup (s);
+ ct->xtype = str_dup (s);
}
if (ct->subtype == NULL) {
* field, so we can attempt to convert the type to BODY here.
*/
if (ct->type == TYPETEXT)
- ct->subtype = safe_strdup ("plain");
+ ct->subtype = str_dup ("plain");
else if (ct->type == TYPEAUDIO)
- ct->subtype = safe_strdup ("basic");
+ ct->subtype = str_dup ("basic");
else if (ct->type == TYPEMESSAGE)
- ct->subtype = safe_strdup ("rfc822");
+ ct->subtype = str_dup ("rfc822");
else if (ct->type == TYPEOTHER) {
char buffer[SHORT_STRING];
ct->type = TYPEAPPLICATION;
snprintf (buffer, sizeof (buffer), "x-%s", s);
- ct->subtype = safe_strdup (buffer);
+ ct->subtype = str_dup (buffer);
}
else
- ct->subtype = safe_strdup ("x-unknown");
+ ct->subtype = str_dup ("x-unknown");
}
/* Default character set for text types. */
if ((s =
mutt_get_parameter ("filename",
(parms = parse_parameters (s)))) != 0)
- mutt_str_replace (&ct->filename, s);
+ str_replace (&ct->filename, s);
if ((s = mutt_get_parameter ("name", parms)) != 0)
- ct->form_name = safe_strdup (s);
+ ct->form_name = str_dup (s);
mutt_free_parameter (&parms);
}
}
{
BODY *p = mutt_new_body ();
char *c;
- char *line = safe_malloc (LONG_STRING);
+ char *line = mem_malloc (LONG_STRING);
size_t linelen = LONG_STRING;
- p->hdr_offset = ftell (fp);
+ p->hdr_offset = ftello (fp);
p->encoding = ENC7BIT; /* default from RFC1521 */
p->type = digest ? TYPEMESSAGE : TYPETEXT;
p->disposition = DISPINLINE;
- while (*(line = read_rfc822_line (fp, line, &linelen)) != 0) {
+ while (*(line = mutt_read_rfc822_line (fp, line, &linelen)) != 0) {
/* Find the value of the current header */
if ((c = strchr (line, ':'))) {
*c = 0;
c++;
SKIPWS (c);
if (!*c) {
- dprint (1,
- (debugfile,
- "mutt_read_mime_header(): skipping empty header field: %s\n",
- line));
+ debug_print (1, ("skipping empty header field: %s\n", line));
continue;
}
}
else {
- dprint (1,
- (debugfile, "read_mime_header: bogus MIME header: %s\n", line));
+ debug_print (1, ("bogus MIME header: %s\n", line));
break;
}
else if (!ascii_strcasecmp ("disposition", line + 8))
parse_content_disposition (c, p);
else if (!ascii_strcasecmp ("description", line + 8)) {
- mutt_str_replace (&p->description, c);
+ str_replace (&p->description, c);
rfc2047_decode (&p->description);
}
}
else if (!ascii_strcasecmp ("content-lines", line + 6))
mutt_set_parameter ("content-lines", c, &(p->parameter));
else if (!ascii_strcasecmp ("data-description", line + 6)) {
- mutt_str_replace (&p->description, c);
+ str_replace (&p->description, c);
rfc2047_decode (&p->description);
}
}
#endif
}
- p->offset = ftell (fp); /* Mark the start of the real data */
+ p->offset = ftello (fp); /* Mark the start of the real data */
if (p->type == TYPETEXT && !p->subtype)
- p->subtype = safe_strdup ("plain");
+ p->subtype = str_dup ("plain");
else if (p->type == TYPEMESSAGE && !p->subtype)
- p->subtype = safe_strdup ("rfc822");
+ p->subtype = str_dup ("rfc822");
- FREE (&line);
+ mem_free (&line);
return (p);
}
#endif
bound = mutt_get_parameter ("boundary", b->parameter);
- fseek (fp, b->offset, SEEK_SET);
+ fseeko (fp, b->offset, SEEK_SET);
b->parts = mutt_parse_multipart (fp, bound,
b->offset + b->length,
ascii_strcasecmp ("digest",
case TYPEMESSAGE:
if (b->subtype) {
- fseek (fp, b->offset, SEEK_SET);
+ fseeko (fp, b->offset, SEEK_SET);
if (mutt_is_message_type (b->type, b->subtype))
b->parts = mutt_parse_messageRFC822 (fp, b);
else if (ascii_strcasecmp (b->subtype, "external-body") == 0)
/* try to recover from parsing error */
if (!b->parts) {
b->type = TYPETEXT;
- mutt_str_replace (&b->subtype, "plain");
+ str_replace (&b->subtype, "plain");
}
}
BODY *msg;
parent->hdr = mutt_new_header ();
- parent->hdr->offset = ftell (fp);
+ parent->hdr->offset = ftello (fp);
parent->hdr->env = mutt_read_rfc822_header (fp, parent->hdr, 0, 0);
msg = parent->hdr->content;
* digest 1 if reading a multipart/digest, 0 otherwise
*/
-BODY *mutt_parse_multipart (FILE * fp, const char *boundary, long end_off,
+BODY *mutt_parse_multipart (FILE * fp, const char *boundary, LOFF_T end_off,
int digest)
{
#ifdef SUN_ATTACHMENT
return (NULL);
}
- blen = mutt_strlen (boundary);
- while (ftell (fp) < end_off && fgets (buffer, LONG_STRING, fp) != NULL) {
- len = mutt_strlen (buffer);
+ blen = str_len (boundary);
+ while (ftello (fp) < end_off && fgets (buffer, LONG_STRING, fp) != NULL) {
+ len = str_len (buffer);
crlf = (len > 1 && buffer[len - 2] == '\r') ? 1 : 0;
if (buffer[0] == '-' && buffer[1] == '-' &&
- mutt_strncmp (buffer + 2, boundary, blen) == 0) {
+ str_ncmp (buffer + 2, boundary, blen) == 0) {
if (last) {
- last->length = ftell (fp) - last->offset - len - 1 - crlf;
+ last->length = ftello (fp) - last->offset - len - 1 - crlf;
if (last->parts && last->parts->length == 0)
last->parts->length =
- ftell (fp) - last->parts->offset - len - 1 - crlf;
+ 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;
buffer[i] = 0;
/* Check for the end boundary */
- if (mutt_strcmp (buffer + blen + 2, "--") == 0) {
+ if (str_cmp (buffer + blen + 2, "--") == 0) {
final = 1;
break; /* done parsing */
}
for (lines =
atoi (mutt_get_parameter ("content-lines", new->parameter));
lines; lines--)
- if (ftell (fp) >= end_off
+ if (ftello (fp) >= end_off
|| fgets (buffer, LONG_STRING, fp) == NULL)
break;
}
else if (sscanf (t, "%d:%d", &hour, &min) == 2)
sec = 0;
else {
- dprint (1,
- (debugfile, "parse_date: could not process time format: %s\n",
- t));
+ debug_print (1, ("could not process time format: %s\n", t));
return (-1);
}
tm.tm_hour = hour;
}
if (count < 4) { /* don't check for missing timezone */
- dprint (1,
- (debugfile,
- "parse_date(): error parsing date format, using received time\n"));
+ debug_print (1, ("error parsing date format, using received time\n"));
return (-1);
}
if ((s = strchr (s, '<')) == NULL || (p = strchr (s, '>')) == NULL)
return (NULL);
l = (size_t) (p - s) + 1;
- r = safe_malloc (l + 1);
+ r = mem_malloc (l + 1);
memcpy (r, s, l);
r[l] = 0;
return (r);
void mutt_parse_mime_message (CONTEXT * ctx, HEADER * cur)
{
MESSAGE *msg;
+ int flags = 0;
- if (cur->content->type != TYPEMESSAGE
- && cur->content->type != TYPEMULTIPART)
- return; /* nothing to do */
+ do {
+ if (cur->content->type != TYPEMESSAGE
+ && cur->content->type != TYPEMULTIPART)
+ break; /* nothing to do */
- if (cur->content->parts)
- return; /* The message was parsed earlier. */
+ if (cur->content->parts)
+ break; /* The message was parsed earlier. */
- if ((msg = mx_open_message (ctx, cur->msgno))) {
- mutt_parse_part (msg->fp, cur->content);
+ if ((msg = mx_open_message (ctx, cur->msgno))) {
+ mutt_parse_part (msg->fp, cur->content);
- if (WithCrypto)
- cur->security = crypt_query (cur->content);
+ if (WithCrypto)
+ cur->security = crypt_query (cur->content);
- mx_close_message (&msg);
- }
+ mx_close_message (&msg);
+ }
+ } while (0);
+ mutt_count_body_parts (cur, flags | M_PARTS_RECOUNT);
}
int mutt_parse_rfc822_line (ENVELOPE * e, HEADER * hdr, char *line, char *p,
}
else if (ascii_strcasecmp (line + 8, "description") == 0) {
if (hdr) {
- mutt_str_replace (&hdr->content->description, p);
+ str_replace (&hdr->content->description, p);
rfc2047_decode (&hdr->content->description);
}
matched = 1;
case 'd':
if (!ascii_strcasecmp ("ate", line + 1)) {
- mutt_str_replace (&e->date, p);
+ str_replace (&e->date, p);
if (hdr)
hdr->date_sent = mutt_parse_date (p, hdr);
matched = 1;
* bothered me for _years_ */
if (!e->from) {
e->from = rfc822_new_address ();
- e->from->personal = safe_strdup (line + 6);
+ e->from->personal = str_dup (p);
}
matched = 1;
}
#ifdef USE_NNTP
- else if (!mutt_strcasecmp (line + 1, "ollowup-to")) {
+ else if (!str_casecmp (line + 1, "ollowup-to")) {
if (!e->followup_to) {
- mutt_remove_trailing_ws (p);
- e->followup_to = safe_strdup (mutt_skip_whitespace (p));
+ str_skip_trailws (p);
+ e->followup_to = str_dup (str_skip_initws (p));
}
matched = 1;
}
/* Take the first mailto URL */
if (url_check_scheme (beg) == U_MAILTO) {
- FREE (&e->list_post);
- e->list_post = mutt_substrdup (beg, end);
+ mem_free (&e->list_post);
+ e->list_post = str_substrdup (beg, end);
break;
}
}
matched = 1;
}
else if (!ascii_strcasecmp (line + 1, "essage-id")) {
- /* We add a new "Message-Id:" when building a message */
- FREE (&e->message_id);
+ /* We add a new "Message-ID:" when building a message */
+ mem_free (&e->message_id);
e->message_id = extract_message_id (p);
matched = 1;
}
#ifdef USE_NNTP
case 'n':
- if (!mutt_strcasecmp (line + 1, "ewsgroups")) {
- FREE (&e->newsgroups);
- mutt_remove_trailing_ws (p);
- e->newsgroups = safe_strdup (mutt_skip_whitespace (p));
+ if (!str_casecmp (line + 1, "ewsgroups")) {
+ mem_free (&e->newsgroups);
+ str_skip_trailws (p);
+ e->newsgroups = str_dup (str_skip_initws (p));
matched = 1;
}
break;
case 'o':
/* field `Organization:' saves only for pager! */
- if (!mutt_strcasecmp (line + 1, "rganization")) {
- if (!e->organization && mutt_strcasecmp (p, "unknown"))
- e->organization = safe_strdup (p);
+ if (!str_casecmp (line + 1, "rganization")) {
+ if (!e->organization && str_casecmp (p, "unknown"))
+ e->organization = str_dup (p);
}
break;
case 's':
if (!ascii_strcasecmp (line + 1, "ubject")) {
if (!e->subject)
- e->subject = safe_strdup (p);
+ e->subject = str_dup (p);
matched = 1;
}
else if (!ascii_strcasecmp (line + 1, "ender")) {
}
else if ((!ascii_strcasecmp ("upersedes", line + 1) ||
!ascii_strcasecmp ("upercedes", line + 1)) && hdr)
- e->supersedes = safe_strdup (p);
+ e->supersedes = str_dup (p);
break;
case 't':
matched = 1;
}
else if (ascii_strcasecmp (line + 1, "-label") == 0) {
- e->x_label = safe_strdup (p);
+ e->x_label = str_dup (p);
matched = 1;
}
#ifdef USE_NNTP
- else if (!mutt_strcasecmp (line + 1, "-comment-to")) {
+ else if (!str_casecmp (line + 1, "-comment-to")) {
if (!e->x_comment_to)
- e->x_comment_to = safe_strdup (p);
+ e->x_comment_to = str_dup (p);
matched = 1;
}
- else if (!mutt_strcasecmp (line + 1, "ref")) {
+ else if (!str_casecmp (line + 1, "ref")) {
if (!e->xref)
- e->xref = safe_strdup (p);
+ e->xref = str_dup (p);
matched = 1;
}
#endif
/* Keep track of the user-defined headers */
if (!matched && user_hdrs) {
/* restore the original line */
- line[mutt_strlen (line)] = ':';
+ line[str_len (line)] = ':';
if (weed && option (OPTWEED) && mutt_matches_ignore (line, Ignore)
&& !mutt_matches_ignore (line, UnIgnore))
}
else
last = e->userhdrs = mutt_new_list ();
- last->data = safe_strdup (line);
+ last->data = str_dup (line);
if (do_2047)
rfc2047_decode (&last->data);
}
{
ENVELOPE *e = mutt_new_envelope ();
LIST *last = NULL;
- char *line = safe_malloc (LONG_STRING);
+ char *line = mem_malloc (LONG_STRING);
char *p;
- long loc;
+ LOFF_T loc;
int matched;
size_t linelen = LONG_STRING;
char buf[LONG_STRING + 1];
/* set the defaults from RFC1521 */
hdr->content->type = TYPETEXT;
- hdr->content->subtype = safe_strdup ("plain");
+ hdr->content->subtype = str_dup ("plain");
hdr->content->encoding = ENC7BIT;
hdr->content->length = -1;
}
}
- while ((loc = ftell (f)),
- *(line = read_rfc822_line (f, line, &linelen)) != 0) {
+ while ((loc = ftello (f)),
+ *(line = mutt_read_rfc822_line (f, line, &linelen)) != 0) {
matched = 0;
if ((p = strpbrk (line, ": \t")) == NULL || *p != ':') {
time_t t;
/* some bogus MTAs will quote the original "From " line */
- if (mutt_strncmp (">From ", line, 6) == 0)
+ if (str_ncmp (">From ", line, 6) == 0)
continue; /* just ignore */
else if (is_from (line, return_path, sizeof (return_path), &t)) {
/* MH somtimes has the From_ line in the middle of the header! */
continue;
}
- fseek (f, loc, 0);
+ fseeko (f, loc, 0);
break; /* end of header */
}
}
if (e->spam && e->spam->data)
- dprint (5, (debugfile, "p822: spam = %s\n", e->spam->data));
+ debug_print (5, ("spam = %s\n", e->spam->data));
}
}
}
- FREE (&line);
+ mem_free (&line);
if (hdr) {
hdr->content->hdr_offset = hdr->offset;
- hdr->content->offset = ftell (f);
-
- /* do RFC2047 decoding */
- rfc2047_decode_adrlist (e->from);
- rfc2047_decode_adrlist (e->to);
- rfc2047_decode_adrlist (e->cc);
- rfc2047_decode_adrlist (e->bcc);
- rfc2047_decode_adrlist (e->reply_to);
- rfc2047_decode_adrlist (e->mail_followup_to);
- rfc2047_decode_adrlist (e->return_path);
- rfc2047_decode_adrlist (e->sender);
-
- if (e->subject) {
- regmatch_t pmatch[1];
-
- rfc2047_decode (&e->subject);
-
- if (regexec (ReplyRegexp.rx, e->subject, 1, pmatch, 0) == 0)
- e->real_subj = e->subject + pmatch[0].rm_eo;
- else
- e->real_subj = e->subject;
- }
-
+ hdr->content->offset = ftello (f);
+ rfc2047_decode_envelope (e);
/* check for missing or invalid date */
if (hdr->date_sent <= 0) {
- dprint (1,
- (debugfile,
- "read_rfc822_header(): no date found, using received time from msg separator\n"));
+ debug_print (1, ("no date found, using received "
+ "time from msg separator\n"));
hdr->date_sent = hdr->received;
}
}
return p;
}
+
+
+/* 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;
+}