Hi Brendan and all, I rebuilt the patch after issues with diff options. Here comes the patch for imap partial fetch.
The patch introduces imap_partial_fetch into mutt. To try it out, add the line set imap_partial_fetch=yes to your .muttrc file. The code introduced here will at least partly resolve the issue related to imap partial fetch. I often get emails which a 3.6k text part and with 22 M of images. The proposed change will as a minimum allow users to check the text of a message before downloading 22M of images. The patch has been tested at least once and it builds. What's next? Cheers, Tilman
diff -ru muttsrc/commands.c mycleanmutt/commands.c --- muttsrc/commands.c 2014-02-01 21:48:14.425507687 +0100 +++ mycleanmutt/commands.c 2014-02-01 22:03:15.666597898 +0100 @@ -69,7 +69,7 @@ snprintf (buf, sizeof (buf), "%s/%s", TYPE (cur->content), cur->content->subtype); - mutt_parse_mime_message (Context, cur); + mutt_parse_mime_message (Context, cur, option (OPTIMAPPARTIALFETCH) ? 1 : 0); mutt_message_hook (Context, cur, M_MESSAGEHOOK); /* see if crypto is needed for this message. if so, we should exit curses */ @@ -370,7 +370,7 @@ } if (decode) - mutt_parse_mime_message (Context, h); + mutt_parse_mime_message (Context, h, option (OPTIMAPPARTIALFETCH) ? 1 : 0); mutt_copy_message (fp, Context, h, cmflags, chflags); } @@ -402,7 +402,7 @@ if (WithCrypto && decode) { - mutt_parse_mime_message (Context, h); + mutt_parse_mime_message (Context, h, option (OPTIMAPPARTIALFETCH) ? 1 : 0); if(h->security & ENCRYPT && !crypt_valid_passphrase(h->security)) return 1; } @@ -427,7 +427,7 @@ if(Context->hdrs[Context->v2r[i]]->tagged) { mutt_message_hook (Context, Context->hdrs[Context->v2r[i]], M_MESSAGEHOOK); - mutt_parse_mime_message(Context, Context->hdrs[Context->v2r[i]]); + mutt_parse_mime_message(Context, Context->hdrs[Context->v2r[i]], option (OPTIMAPPARTIALFETCH) ? 1 : 0); if (Context->hdrs[Context->v2r[i]]->security & ENCRYPT && !crypt_valid_passphrase(Context->hdrs[Context->v2r[i]]->security)) return 1; @@ -709,7 +709,7 @@ set_copy_flags (h, decode, decrypt, &cmflags, &chflags); if (decode || decrypt) - mutt_parse_mime_message (Context, h); + mutt_parse_mime_message (Context, h, option (OPTIMAPPARTIALFETCH) ? 1 : 0); if ((rc = mutt_append_message (ctx, Context, h, cmflags, chflags)) != 0) return rc; @@ -979,11 +979,11 @@ { MESSAGE *msg; int rv = 0; - + h->security |= PGP_TRADITIONAL_CHECKED; - mutt_parse_mime_message (Context, h); - if ((msg = mx_open_message (Context, h->msgno)) == NULL) + mutt_parse_mime_message (Context, h, option (OPTIMAPPARTIALFETCH) ? 1 : 0); + if ((msg = mx_open_message (Context, h->msgno, 0)) == NULL) return 0; if (crypt_pgp_check_traditional (msg->fp, h->content, 0)) { Only in mycleanmutt/contrib: Makefile Only in mycleanmutt/contrib: Makefile.in diff -ru muttsrc/copy.c mycleanmutt/copy.c --- muttsrc/copy.c 2014-02-01 21:48:14.461489868 +0100 +++ mycleanmutt/copy.c 2014-02-01 22:03:36.686702129 +0100 @@ -682,7 +682,7 @@ MESSAGE *msg; int r; - if ((msg = mx_open_message (src, hdr->msgno)) == NULL) + if ((msg = mx_open_message (src, hdr->msgno, 1)) == NULL) return -1; if ((r = _mutt_copy_message (fpout, msg->fp, hdr, hdr->content, flags, chflags)) == 0 && (ferror (fpout) || feof (fpout))) @@ -737,7 +737,7 @@ MESSAGE *msg; int r; - if ((msg = mx_open_message (src, hdr->msgno)) == NULL) + if ((msg = mx_open_message (src, hdr->msgno, 0)) == NULL) return -1; r = _mutt_append_message (dest, msg->fp, src, hdr, hdr->content, cmflags, chflags); mx_close_message (&msg); diff -ru muttsrc/crypt.c mycleanmutt/crypt.c --- muttsrc/crypt.c 2014-02-01 21:48:14.469485908 +0100 +++ mycleanmutt/crypt.c 2014-02-01 21:38:02.092787775 +0100 @@ -609,7 +609,7 @@ { if (Context->hdrs[Context->v2r[i]]->tagged) { - mutt_parse_mime_message (Context, Context->hdrs[Context->v2r[i]]); + mutt_parse_mime_message (Context, Context->hdrs[Context->v2r[i]], option (OPTIMAPPARTIALFETCH) ? 1 : 0); if (Context->hdrs[Context->v2r[i]]->security & ENCRYPT && !crypt_valid_passphrase (Context->hdrs[Context->v2r[i]]->security)) { @@ -660,7 +660,7 @@ } else { - mutt_parse_mime_message (Context, h); + mutt_parse_mime_message (Context, h, option (OPTIMAPPARTIALFETCH) ? 1 : 0); if (!(h->security & ENCRYPT && !crypt_valid_passphrase (h->security))) { if ((WithCrypto & APPLICATION_PGP) diff -ru muttsrc/imap/imap.h mycleanmutt/imap/imap.h --- muttsrc/imap/imap.h 2014-02-01 21:48:14.577432446 +0100 +++ mycleanmutt/imap/imap.h 2014-02-01 21:38:01.812926387 +0100 @@ -57,7 +57,7 @@ /* message.c */ int imap_append_message (CONTEXT* ctx, MESSAGE* msg); int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete); -int imap_fetch_message (MESSAGE* msg, CONTEXT* ctx, int msgno); +int imap_fetch_message (MESSAGE* msg, CONTEXT* ctx, int msgno, int partial_fetch); /* socket.c */ void imap_logout_all (void); diff -ru muttsrc/imap/message.c mycleanmutt/imap/message.c --- muttsrc/imap/message.c 2014-02-01 21:48:14.585428486 +0100 +++ mycleanmutt/imap/message.c 2014-02-01 21:38:01.800932328 +0100 @@ -42,6 +42,8 @@ #include "bcache.h" +#include "mime.h" + static FILE* msg_cache_get (IMAP_DATA* idata, HEADER* h); static FILE* msg_cache_put (IMAP_DATA* idata, HEADER* h); static int msg_cache_commit (IMAP_DATA* idata, HEADER* h); @@ -389,7 +391,7 @@ return retval; } -int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno) +int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno, int partial_fetch) { IMAP_DATA* idata; HEADER* h; @@ -408,15 +410,37 @@ * fails. Thanks Sam. */ short fetched = 0; + /* TW change 2013-12-31 f** NYE */ + LOFF_T first_part_size = 0; + LOFF_T first_part_offset = 0; + + /* TW change on 2014-01-01 */ + char bs[LONG_STRING]; + char bps[LONG_STRING]; + idata = (IMAP_DATA*) ctx->data; h = ctx->hdrs[msgno]; + if(h->content->type==TYPEMULTIPART) + { + if(h->content->parts) + { + first_part_size = h->content->parts->length; + first_part_offset = h->content->parts->offset; + } + } + if ((msg->fp = msg_cache_get (idata, h))) { - if (HEADER_DATA(h)->parsed) - return 0; - else - goto parsemsg; + /* either the message has been fetched already or it should be fetched only partially */ + if(HEADER_DATA(h)->partial==0 || (HEADER_DATA(h)->partial==1&&partial_fetch==1&&first_part_size<16384)) + { + if (HEADER_DATA(h)->parsed) { + return 0; + } else { + goto parsemsg; + } + } } /* we still do some caching even if imap_cachedir is unset */ @@ -457,10 +481,27 @@ * command handler */ h->active = 0; - snprintf (buf, sizeof (buf), "UID FETCH %u %s", HEADER_DATA(h)->uid, + if(partial_fetch==1) + { + /* Added by TW on 2014-01-01 to ensure the first part of a message is all fetched */ + if(first_part_size<16384) + { + first_part_size=16384; + } + snprintf (bps, sizeof(bps),"BODY.PEEK[]<0.%i>",(int) first_part_size); + snprintf (bs, sizeof(bs), "BODY[]<0.%i>",(int) first_part_size); + snprintf (buf, sizeof (buf), "UID FETCH %u %s", HEADER_DATA(h)->uid, + (mutt_bit_isset (idata->capabilities, IMAP4REV1) ? + (option (OPTIMAPPEEK) ? bps : bs) : + "RFC822")); + HEADER_DATA(h)->partial = 1; + } else { + snprintf (buf, sizeof (buf), "UID FETCH %u %s", HEADER_DATA(h)->uid, (mutt_bit_isset (idata->capabilities, IMAP4REV1) ? (option (OPTIMAPPEEK) ? "BODY.PEEK[]" : "BODY[]") : "RFC822")); + HEADER_DATA(h)->partial = 0; + } imap_cmd_start (idata, buf); do @@ -568,7 +609,10 @@ fgets (buf, sizeof (buf), msg->fp); } - h->content->length = ftell (msg->fp) - h->content->offset; +/* Changed by TW on 2013-12-31 to resolve the issue with wrong message sizes */ + if(partial_fetch==0) { + h->content->length = ftell (msg->fp) - h->content->offset; + } /* This needs to be done in case this is a multipart message */ #if defined(HAVE_PGP) || defined(HAVE_SMIME) diff -ru muttsrc/imap/message.h mycleanmutt/imap/message.h --- muttsrc/imap/message.h 2014-02-01 21:48:14.585428486 +0100 +++ mycleanmutt/imap/message.h 2014-02-01 21:38:01.808928368 +0100 @@ -35,6 +35,7 @@ unsigned int changed : 1; unsigned int parsed : 1; + unsigned int partial : 1; unsigned int uid; /* 32-bit Message UID */ LIST *keywords; diff -ru muttsrc/init.h mycleanmutt/init.h --- muttsrc/init.h 2014-02-01 21:48:14.609416606 +0100 +++ mycleanmutt/init.h 2014-02-01 21:38:02.044811544 +0100 @@ -1149,6 +1149,12 @@ ** .pp ** This variable defaults to the value of $$imap_user. */ + { "imap_partial_fetch", DT_BOOL, R_NONE, OPTIMAPPARTIALFETCH, 0 }, + /* + ** .pp + ** If enabled, mutt will download only the selected part of an IMAP message. + ** Useful in case of IMAP messages with large attachments. + */ { "imap_pass", DT_STR, R_NONE, UL &ImapPass, UL 0 }, /* ** .pp diff -ru muttsrc/mailbox.h mycleanmutt/mailbox.h --- muttsrc/mailbox.h 2014-02-01 21:48:14.649396799 +0100 +++ mycleanmutt/mailbox.h 2014-02-01 21:38:01.732965995 +0100 @@ -56,7 +56,7 @@ CONTEXT *mx_open_mailbox (const char *, int, CONTEXT *); -MESSAGE *mx_open_message (CONTEXT *, int); +MESSAGE *mx_open_message (CONTEXT *, int, int); MESSAGE *mx_open_new_message (CONTEXT *, HEADER *, int); void mx_fastclose_mailbox (CONTEXT *); diff -ru muttsrc/mutt.h mycleanmutt/mutt.h --- muttsrc/mutt.h 2014-02-01 21:48:14.677382943 +0100 +++ mycleanmutt/mutt.h 2014-02-01 21:38:02.080793721 +0100 @@ -364,6 +364,7 @@ OPTIMAPCHECKSUBSCRIBED, OPTIMAPIDLE, OPTIMAPLSUB, + OPTIMAPPARTIALFETCH, OPTIMAPPASSIVE, OPTIMAPPEEK, OPTIMAPSERVERNOISE, diff -ru muttsrc/mx.c mycleanmutt/mx.c --- muttsrc/mx.c 2014-02-01 21:48:14.701371058 +0100 +++ mycleanmutt/mx.c 2014-02-01 21:38:02.084791736 +0100 @@ -1349,7 +1349,7 @@ } /* return a stream pointer for a message */ -MESSAGE *mx_open_message (CONTEXT *ctx, int msgno) +MESSAGE *mx_open_message (CONTEXT *ctx, int msgno, int partial_fetch) { MESSAGE *msg; @@ -1386,7 +1386,7 @@ #ifdef USE_IMAP case M_IMAP: { - if (imap_fetch_message (msg, ctx, msgno) != 0) + if (imap_fetch_message (msg, ctx, msgno, partial_fetch) != 0) FREE (&msg); break; } diff -ru muttsrc/parse.c mycleanmutt/parse.c --- muttsrc/parse.c 2014-02-01 21:48:14.713365122 +0100 +++ mycleanmutt/parse.c 2014-02-01 21:38:01.645009558 +0100 @@ -649,8 +649,13 @@ } /* in case of missing end boundary, set the length to something reasonable */ - if (last && last->length == 0 && !final) + if (last && last->length == 0 && !final) + { last->length = end_off - last->offset; +#ifdef USE_IMAP + +#endif /* USE_IMAP */ + } /* parse recursive MIME parts */ for(last = head; last; last = last->next) @@ -945,7 +950,7 @@ return NULL; } -void mutt_parse_mime_message (CONTEXT *ctx, HEADER *cur) +void mutt_parse_mime_message (CONTEXT *ctx, HEADER *cur, int partial_fetch) { MESSAGE *msg; @@ -954,11 +959,13 @@ cur->content->type != TYPEMULTIPART) break; /* nothing to do */ - if (cur->content->parts) +/* changed by TW on 2014-01-02: When partial_fetch==0, the presence of the first part of a message is no good indicator of whether the message has been parsed earlier */ + if (partial_fetch==0 && cur->content->parts) break; /* The message was parsed earlier. */ - if ((msg = mx_open_message (ctx, cur->msgno))) + if ((msg = mx_open_message (ctx, cur->msgno, partial_fetch))) { + mutt_parse_part (msg->fp, cur->content); if (WithCrypto) @@ -1626,7 +1633,7 @@ if (hdr->content->parts) keep_parts = 1; else - mutt_parse_mime_message (ctx, hdr); + mutt_parse_mime_message (ctx, hdr, option (OPTIMAPPARTIALFETCH) ? 1 : 0); if (AttachAllow || AttachExclude || InlineAllow || InlineExclude) hdr->attach_total = count_body_parts(hdr->content, M_PARTS_TOPLEVEL); diff -ru muttsrc/pattern.c mycleanmutt/pattern.c --- muttsrc/pattern.c 2014-02-01 21:48:14.717363138 +0100 +++ mycleanmutt/pattern.c 2014-02-01 22:02:55.074495797 +0100 @@ -155,7 +155,7 @@ char *buf; size_t blen; - if ((msg = mx_open_message (ctx, msgno)) != NULL) + if ((msg = mx_open_message (ctx, msgno, 0)) != NULL) { if (option (OPTTHOROUGHSRC)) { @@ -175,7 +175,7 @@ if (pat->op != M_HEADER) { - mutt_parse_mime_message (ctx, h); + mutt_parse_mime_message (ctx, h, option (OPTIMAPPARTIALFETCH) ? 1 : 0); if (WithCrypto && (h->security & ENCRYPT) && !crypt_valid_passphrase(h->security)) diff -ru muttsrc/pgp.c mycleanmutt/pgp.c --- muttsrc/pgp.c 2014-02-01 21:48:14.721361157 +0100 +++ mycleanmutt/pgp.c 2014-02-01 21:38:01.856904605 +0100 @@ -675,7 +675,7 @@ if (h) { - mutt_parse_mime_message (Context, h); + mutt_parse_mime_message (Context, h, option (OPTIMAPPARTIALFETCH) ? 1 : 0); if(h->security & PGPENCRYPT && !pgp_valid_passphrase ()) return; } @@ -695,7 +695,7 @@ { if (Context->hdrs[Context->v2r[i]]->tagged) { - mutt_parse_mime_message (Context, Context->hdrs[Context->v2r[i]]); + mutt_parse_mime_message (Context, Context->hdrs[Context->v2r[i]], option (OPTIMAPPARTIALFETCH) ? 1 : 0); if (Context->hdrs[Context->v2r[i]]->security & PGPENCRYPT && !pgp_valid_passphrase()) { @@ -709,7 +709,7 @@ } else { - mutt_parse_mime_message (Context, h); + mutt_parse_mime_message (Context, h, option (OPTIMAPPARTIALFETCH) ? 1 : 0); if (h->security & PGPENCRYPT && !pgp_valid_passphrase()) { safe_fclose (&fpout); Only in mycleanmutt/po: bg.gmo Only in mycleanmutt/po: ca.gmo Only in mycleanmutt/po: cs.gmo Only in mycleanmutt/po: da.gmo Only in mycleanmutt/po: de.gmo Only in mycleanmutt/po: el.gmo Only in mycleanmutt/po: eo.gmo Only in mycleanmutt/po: es.gmo Only in mycleanmutt/po: et.gmo Only in mycleanmutt/po: eu.gmo Only in mycleanmutt/po: fr.gmo Only in mycleanmutt/po: ga.gmo Only in mycleanmutt/po: gl.gmo Only in mycleanmutt/po: hu.gmo Only in mycleanmutt/po: id.gmo Only in mycleanmutt/po: it.gmo Only in mycleanmutt/po: ja.gmo Only in mycleanmutt/po: ko.gmo Only in mycleanmutt/po: lt.gmo Only in mycleanmutt/po: nl.gmo Only in mycleanmutt/po: pl.gmo Only in mycleanmutt/po: POTFILES Only in mycleanmutt/po: pt_BR.gmo Only in mycleanmutt/po: ru.gmo Only in mycleanmutt/po: sk.gmo Only in mycleanmutt/po: sv.gmo Only in mycleanmutt/po: tr.gmo Only in mycleanmutt/po: uk.gmo Only in mycleanmutt/po: zh_CN.gmo Only in mycleanmutt/po: zh_TW.gmo diff -ru muttsrc/postpone.c mycleanmutt/postpone.c --- muttsrc/postpone.c 2014-02-01 21:48:15.005220570 +0100 +++ mycleanmutt/postpone.c 2014-02-01 21:38:02.116775894 +0100 @@ -536,7 +536,7 @@ memset (&s, 0, sizeof (s)); - if (!fp && (msg = mx_open_message (ctx, hdr->msgno)) == NULL) + if (!fp && (msg = mx_open_message (ctx, hdr->msgno, 0)) == NULL) return (-1); if (!fp) fp = msg->fp; diff -ru muttsrc/protos.h mycleanmutt/protos.h --- muttsrc/protos.h 2014-02-01 21:48:15.009218584 +0100 +++ mycleanmutt/protos.h 2014-02-01 21:38:01.716973911 +0100 @@ -222,7 +222,7 @@ void _mutt_mktemp (char *, size_t, const char *, int); void mutt_normalize_time (struct tm *); void mutt_paddstr (int, const char *); -void mutt_parse_mime_message (CONTEXT *ctx, HEADER *); +void mutt_parse_mime_message (CONTEXT *ctx, HEADER *, int); void mutt_parse_part (FILE *, BODY *); void mutt_perror (const char *); void mutt_prepare_envelope (ENVELOPE *, int); diff -ru muttsrc/recvattach.c mycleanmutt/recvattach.c --- muttsrc/recvattach.c 2014-02-01 21:48:15.017214630 +0100 +++ mycleanmutt/recvattach.c 2014-02-01 21:38:02.096785800 +0100 @@ -950,11 +950,13 @@ int op = OP_NULL; /* make sure we have parsed this message */ - mutt_parse_mime_message (Context, hdr); + /* Adapted by TW on 2014-01-02: parse the full message */ + hdr->content->parts=NULL; + mutt_parse_mime_message (Context, hdr, 0); mutt_message_hook (Context, hdr, M_MESSAGEHOOK); - if ((msg = mx_open_message (Context, hdr->msgno)) == NULL) + if ((msg = mx_open_message (Context, hdr->msgno, 0)) == NULL) return; diff -ru muttsrc/send.c mycleanmutt/send.c --- muttsrc/send.c 2014-02-01 21:48:15.045200762 +0100 +++ mycleanmutt/send.c 2014-02-01 21:38:01.645009558 +0100 @@ -364,7 +364,7 @@ { int chflags = CH_DECODE, cmflags = 0; - mutt_parse_mime_message (ctx, cur); + mutt_parse_mime_message (ctx, cur, option (OPTIMAPPARTIALFETCH) ? 1 : 0); mutt_message_hook (ctx, cur, M_MESSAGEHOOK); if (WithCrypto && (cur->security & ENCRYPT) && option (OPTFORWDECODE)) @@ -429,7 +429,7 @@ crypt_valid_passphrase (cur->security); } - mutt_parse_mime_message (ctx, cur); + mutt_parse_mime_message (ctx, cur, option (OPTIMAPPARTIALFETCH) ? 1 : 0); mutt_message_hook (ctx, cur, M_MESSAGEHOOK); mutt_make_attribution (ctx, cur, out); diff -ru muttsrc/sendlib.c mycleanmutt/sendlib.c --- muttsrc/sendlib.c 2014-02-01 21:48:15.049198786 +0100 +++ mycleanmutt/sendlib.c 2014-02-01 21:38:02.144762036 +0100 @@ -1288,7 +1288,7 @@ body->disposition = DISPINLINE; body->noconv = 1; - mutt_parse_mime_message (ctx, hdr); + mutt_parse_mime_message (ctx, hdr, option (OPTIMAPPARTIALFETCH) ? 1 : 0); chflags = CH_XMIT; cmflags = 0; @@ -2528,7 +2528,7 @@ } /* If we failed to open a message, return with error */ - if (!fp && (msg = mx_open_message (Context, h->msgno)) == NULL) + if (!fp && (msg = mx_open_message (Context, h->msgno, 0)) == NULL) return -1; if (!fp) fp = msg->fp; diff -ru muttsrc/VERSION mycleanmutt/VERSION --- muttsrc/VERSION 2014-02-01 21:48:14.397521555 +0100 +++ mycleanmutt/VERSION 2014-02-01 21:38:01.353154112 +0100 @@ -1 +1 @@ -1.5.22 +1.5.23