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

Reply via email to