#endif
#include "mutt.h"
+#include "buffer.h"
+#include "enter.h"
+#include "ascii.h"
+#include "recvattach.h"
#include "mx.h"
#include "mime.h"
#include "rfc2047.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;
if (*linelen < offset + STRING) {
/* grow the buffer */
*linelen += STRING;
- safe_realloc (&line, *linelen);
+ mem_realloc (&line, *linelen);
buf = line + offset;
}
}
else if (o) {
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;
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;
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 */
{
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;
}
#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 = str_dup ("plain");
else if (p->type == TYPEMESSAGE && !p->subtype)
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)
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
}
blen = str_len (boundary);
- while (ftell (fp) < end_off && fgets (buffer, LONG_STRING, fp) != NULL) {
+ 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] == '-' &&
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;
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;
}
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,
* bothered me for _years_ */
if (!e->from) {
e->from = rfc822_new_address ();
- e->from->personal = str_dup (line + 6);
+ e->from->personal = str_dup (p);
}
matched = 1;
}
/* Take the first mailto URL */
if (url_check_scheme (beg) == U_MAILTO) {
- FREE (&e->list_post);
+ 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 (!str_casecmp (line + 1, "ewsgroups")) {
- FREE (&e->newsgroups);
+ mem_free (&e->newsgroups);
str_skip_trailws (p);
e->newsgroups = str_dup (str_skip_initws (p));
matched = 1;
{
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];
}
}
- 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 != ':') {
continue;
}
- fseek (f, loc, 0);
+ fseeko (f, loc, 0);
break; /* end of header */
}
}
- 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) {
- debug_print (1, ("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;
+}