Changeset 5501:e0f0a7915711 for imap

Show
Ignore:
Timestamp:
2008-08-29 16:54:56 (3 months ago)
Author:
Brendan Cully <brendan@…>
Branch:
HEAD
Message:

Use sorted headers in imap_exec_msgset. Fixes [e68f79fef249].
Closes #3000 again.

Location:
imap
Files:
4 modified

Legend:

Unmodified
Added
Removed
  • imap/command.c

    r5499 r5501  
    197197 *     for checking for a mailbox on append and login 
    198198 *   IMAP_CMD_PASS: command contains a password. Suppress logging. 
     199 *   IMAP_CMD_QUEUE: only queue command, do not execute. 
    199200 * Return 0 on success, -1 on Failure, -2 on OK Failure 
    200201 */ 
  • imap/imap.c

    r5499 r5501  
    857857} 
    858858 
    859 /* imap_make_msg_set: make an IMAP4rev1 UID message set out of a set of 
    860  *   headers, given a flag enum to filter on. 
    861  * Params: idata: IMAP_DATA containing context containing header set 
    862  *         buf: to write message set into 
    863  *         flag: enum of flag type on which to filter 
    864  *         changed: include only changed messages in message set 
    865  *         invert: invert sense of flag, eg M_READ matches unread messages 
    866  * Returns: number of messages in message set (0 if no matches) */ 
    867 int imap_make_msg_set (IMAP_DATA* idata, BUFFER* buf, int flag, int changed, 
    868                        int invert) 
    869 { 
    870   HEADER** hdrs;        /* sorted local copy */ 
     859/* Note: headers must be in SORT_ORDER. See imap_exec_msgset for args. 
     860 * Pos is an opaque pointer a la strtok. It should be 0 at first call. */ 
     861static int imap_make_msg_set (IMAP_DATA* idata, BUFFER* buf, int flag, 
     862                              int changed, int invert, int* pos) 
     863{ 
     864  HEADER** hdrs = idata->ctx->hdrs; 
    871865  int count = 0;        /* number of messages in message set */ 
    872866  int match = 0;        /* whether current message matches flag condition */ 
    873867  unsigned int setstart = 0;    /* start of current message range */ 
    874868  int n; 
    875   short oldsort;        /* we clobber reverse, must restore it */ 
    876869  int started = 0; 
    877870 
    878   if (Sort != SORT_ORDER) 
    879   { 
    880     hdrs = safe_calloc (idata->ctx->msgcount, sizeof (HEADER*)); 
    881     memcpy (hdrs, idata->ctx->hdrs, idata->ctx->msgcount * sizeof (HEADER*)); 
    882      
    883     oldsort = Sort; 
    884     Sort = SORT_ORDER; 
    885     qsort ((void*) hdrs, idata->ctx->msgcount, sizeof (HEADER*), 
    886       mutt_get_sort_func (SORT_ORDER)); 
    887     Sort = oldsort; 
    888   } 
    889   else 
    890     hdrs = idata->ctx->hdrs; 
     871  hdrs = idata->ctx->hdrs; 
    891872   
    892   for (n = 0; n < idata->ctx->msgcount; n++) 
     873  for (n = *pos; 
     874       n < idata->ctx->msgcount && buf->dptr - buf->data < IMAP_MAX_CMDLEN; 
     875       n++) 
    893876  { 
    894877    match = 0; 
     
    952935  } 
    953936 
     937  *pos = n; 
     938 
     939  return count; 
     940} 
     941 
     942/* Prepares commands for all messages matching conditions (must be flushed 
     943 * with imap_exec) 
     944 * Params: 
     945 *   idata: IMAP_DATA containing context containing header set 
     946 *   pre, post: commands are of the form "%s %s %s %s", tag, 
     947 *     pre, message set, post 
     948 *   flag: enum of flag type on which to filter 
     949 *   changed: include only changed messages in message set 
     950 *   invert: invert sense of flag, eg M_READ matches unread messages 
     951 * Returns: number of matched messages, or -1 on failure */ 
     952int imap_exec_msgset (IMAP_DATA* idata, const char* pre, const char* post, 
     953                      int flag, int changed, int invert) 
     954{ 
     955  HEADER** hdrs = NULL; 
     956  short oldsort; 
     957  BUFFER* cmd; 
     958  int pos; 
     959  int rc; 
     960  int count = 0; 
     961 
     962  if (! (cmd = mutt_buffer_init (NULL))) 
     963  { 
     964    dprint (1, (debugfile, "imap_exec_msgset: unable to allocate buffer\n")); 
     965    return -1; 
     966  } 
     967 
     968  /* We make a copy of the headers just in case resorting doesn't give 
     969   exactly the original order (duplicate messages?), because other parts of 
     970   the ctx are tied to the header order. This may be overkill. */ 
     971  oldsort = Sort; 
    954972  if (Sort != SORT_ORDER) 
    955     FREE (&hdrs); 
    956  
    957   return count; 
     973  { 
     974    hdrs = idata->ctx->hdrs; 
     975    idata->ctx->hdrs = safe_malloc (idata->ctx->msgcount * sizeof (HEADER*)); 
     976    memcpy (idata->ctx->hdrs, hdrs, idata->ctx->msgcount * sizeof (HEADER*)); 
     977 
     978    oldsort = Sort; 
     979    Sort = SORT_ORDER; 
     980    qsort (idata->ctx->hdrs, idata->ctx->msgcount, sizeof (HEADER*), 
     981           mutt_get_sort_func (SORT_ORDER)); 
     982  } 
     983 
     984  pos = 0; 
     985 
     986  do 
     987  { 
     988    cmd->dptr = cmd->data; 
     989    mutt_buffer_printf (cmd, "%s ", pre); 
     990    rc = imap_make_msg_set (idata, cmd, flag, changed, invert, &pos); 
     991    if (rc > 0) 
     992    { 
     993      mutt_buffer_printf (cmd, " %s", post); 
     994      if (imap_exec (idata, cmd->data, IMAP_CMD_QUEUE)) 
     995      { 
     996        rc = -1; 
     997        goto out; 
     998      } 
     999      count += rc; 
     1000    } 
     1001  } 
     1002  while (rc > 0); 
     1003   
     1004  rc = count; 
     1005 
     1006out: 
     1007  mutt_buffer_free (&cmd); 
     1008  if (oldsort != Sort) 
     1009  { 
     1010    Sort = oldsort; 
     1011    FREE (&idata->ctx->hdrs); 
     1012    idata->ctx->hdrs = hdrs; 
     1013  } 
     1014 
     1015  return rc; 
    9581016} 
    9591017 
     
    9781036 
    9791037/* Update the IMAP server to reflect the flags a single message.  */ 
    980  
    9811038int imap_sync_message (IMAP_DATA *idata, HEADER *hdr, BUFFER *cmd, 
    9821039                       int *err_continue) 
     
    10561113} 
    10571114 
    1058 static int sync_helper (IMAP_DATA* idata, BUFFER* buf, int right, int flag, 
    1059                         const char* name) 
    1060 { 
    1061   int rc = 0; 
     1115static int sync_helper (IMAP_DATA* idata, int right, int flag, const char* name) 
     1116{ 
     1117  int count = 0; 
     1118  int rc; 
     1119 
     1120  char buf[LONG_STRING]; 
    10621121 
    10631122  if (!mutt_bit_isset (idata->ctx->rights, right)) 
    10641123    return 0; 
    1065    
     1124 
    10661125  if (right == M_ACL_WRITE && !imap_has_flag (idata->flags, name)) 
    10671126    return 0; 
    10681127 
    1069   buf->dptr = buf->data; 
    1070   mutt_buffer_addstr (buf, "UID STORE "); 
    1071   if (imap_make_msg_set (idata, buf, flag, 1, 0)) 
    1072   { 
    1073     rc++; 
    1074     mutt_buffer_printf (buf, " +FLAGS.SILENT (%s)", name); 
    1075     imap_exec (idata, buf->data, IMAP_CMD_QUEUE); 
    1076   } 
    1077   buf->dptr = buf->data; 
    1078   mutt_buffer_addstr (buf, "UID STORE "); 
    1079   if (imap_make_msg_set (idata, buf, flag, 1, 1)) 
    1080   { 
    1081     rc++; 
    1082     mutt_buffer_printf (buf, " -FLAGS.SILENT (%s)", name); 
    1083     imap_exec (idata, buf->data, IMAP_CMD_QUEUE); 
    1084   } 
    1085    
    1086   return rc; 
     1128  snprintf (buf, sizeof(buf), "+FLAGS.SILENT (%s)", name); 
     1129  if ((rc = imap_exec_msgset (idata, "UID STORE", buf, flag, 1, 0)) < 0) 
     1130    return rc; 
     1131  count += rc; 
     1132 
     1133  buf[0] = '-'; 
     1134  if ((rc = imap_exec_msgset (idata, "UID STORE", buf, flag, 1, 1)) < 0) 
     1135    return rc; 
     1136  count += rc; 
     1137 
     1138  return count; 
    10871139} 
    10881140 
     
    10961148  IMAP_DATA* idata; 
    10971149  CONTEXT* appendctx = NULL; 
    1098   BUFFER cmd; 
    10991150  HEADER* h; 
    11001151  HEADER** hdrs = NULL; 
    11011152  int oldsort; 
    1102   int deleted; 
    11031153  int n; 
    11041154  int rc; 
     
    11191169    return rc; 
    11201170 
    1121   memset (&cmd, 0, sizeof (cmd)); 
    1122  
    11231171  /* if we are expunging anyway, we can do deleted messages very quickly... */ 
    11241172  if (expunge && mutt_bit_isset (idata->ctx->rights, M_ACL_DELETE)) 
    11251173  { 
    1126     mutt_buffer_addstr (&cmd, "UID STORE "); 
    1127     deleted = imap_make_msg_set (idata, &cmd, M_DELETED, 1, 0); 
    1128  
    1129     /* if we have a message set, then let's delete */ 
    1130     if (deleted) 
    1131     { 
    1132       mutt_message (_("Marking %d messages deleted..."), deleted); 
    1133       mutt_buffer_addstr (&cmd, " +FLAGS.SILENT (\\Deleted)"); 
     1174    if ((rc = imap_exec_msgset (idata, "UID STORE", "+FLAGS.SILENT (\\Deleted)", 
     1175                                M_DELETED, 1, 0)) < 0) 
     1176    { 
     1177      mutt_error (_("Expunge failed")); 
     1178      mutt_sleep (1); 
     1179      goto out; 
     1180    } 
     1181 
     1182    if (rc > 0) 
     1183    { 
    11341184      /* mark these messages as unchanged so second pass ignores them. Done 
    11351185       * here so BOGUS UW-IMAP 4.7 SILENT FLAGS updates are ignored. */ 
    11361186      for (n = 0; n < ctx->msgcount; n++) 
    1137         if (ctx->hdrs[n]->deleted && ctx->hdrs[n]->changed) 
    1138           ctx->hdrs[n]->active = 0; 
    1139       if (imap_exec (idata, cmd.data, 0) != 0) 
    1140       { 
    1141         mutt_error (_("Expunge failed")); 
    1142         mutt_sleep (1); 
    1143         rc = -1; 
    1144         goto out; 
    1145       } 
     1187        if (ctx->hdrs[n]->deleted && ctx->hdrs[n]->changed) 
     1188          ctx->hdrs[n]->active = 0; 
     1189      mutt_message (_("Marking %d messages deleted..."), rc); 
    11461190    } 
    11471191  } 
     
    11771221          appendctx = mx_open_mailbox (ctx->path, M_APPEND | M_QUIET, NULL); 
    11781222        if (!appendctx) 
    1179         { 
    11801223          dprint (1, (debugfile, "imap_sync_mailbox: Error opening mailbox in append mode\n")); 
    1181         } 
    11821224        else 
    11831225          _mutt_save_message (h, appendctx, 1, 0, 0); 
     
    11931235  rc = 0; 
    11941236 
    1195   /* presort here to avoid doing 10 resorts in imap_make_msg_set */ 
     1237  /* presort here to avoid doing 10 resorts in imap_exec_msgset */ 
    11961238  oldsort = Sort; 
    11971239  if (Sort != SORT_ORDER) 
     
    12071249  } 
    12081250 
    1209   rc += sync_helper (idata, &cmd, M_ACL_DELETE, M_DELETED, "\\Deleted"); 
    1210   rc += sync_helper (idata, &cmd, M_ACL_WRITE, M_FLAG, "\\Flagged"); 
    1211   rc += sync_helper (idata, &cmd, M_ACL_WRITE, M_OLD, "Old"); 
    1212   rc += sync_helper (idata, &cmd, M_ACL_SEEN, M_READ, "\\Seen"); 
    1213   rc += sync_helper (idata, &cmd, M_ACL_WRITE, M_REPLIED, "\\Answered"); 
     1251  rc += sync_helper (idata, M_ACL_DELETE, M_DELETED, "\\Deleted"); 
     1252  rc += sync_helper (idata, M_ACL_WRITE, M_FLAG, "\\Flagged"); 
     1253  rc += sync_helper (idata, M_ACL_WRITE, M_OLD, "Old"); 
     1254  rc += sync_helper (idata, M_ACL_SEEN, M_READ, "\\Seen"); 
     1255  rc += sync_helper (idata, M_ACL_WRITE, M_REPLIED, "\\Answered"); 
    12141256 
    12151257  if (oldsort != Sort) 
     
    12201262  } 
    12211263 
    1222   if (rc) 
    1223   { 
    1224     if ((rc = imap_exec (idata, NULL, 0)) != IMAP_CMD_OK) 
    1225     { 
    1226       if (ctx->closing) 
     1264  if (rc && (imap_exec (idata, NULL, 0) != IMAP_CMD_OK)) 
     1265  { 
     1266    if (ctx->closing) 
     1267    { 
     1268      if (mutt_yesorno (_("Error saving flags. Close anyway?"), 0) == M_YES) 
    12271269      { 
    1228         if (mutt_yesorno (_("Error saving flags. Close anyway?"), 0) == M_YES) 
    1229         { 
    1230           rc = 0; 
    1231           idata->state = IMAP_AUTHENTICATED; 
    1232           goto out; 
    1233         } 
     1270        rc = 0; 
     1271        idata->state = IMAP_AUTHENTICATED; 
     1272        goto out; 
    12341273      } 
    1235       else 
    1236         mutt_error _("Error saving flags"); 
    1237       goto out; 
    1238     } 
    1239   } 
     1274    } 
     1275    else 
     1276      mutt_error _("Error saving flags"); 
     1277    goto out; 
     1278  } 
     1279 
    12401280  for (n = 0; n < ctx->msgcount; n++) 
    12411281    ctx->hdrs[n]->changed = 0; 
     
    12691309 
    12701310 out: 
    1271   if (cmd.data) 
    1272     FREE (&cmd.data); 
    12731311  if (appendctx) 
    12741312  { 
  • imap/imap_private.h

    r5499 r5501  
    5656 
    5757#define SEQLEN 5 
     58/* maximum length of command lines before they must be split (for 
     59 * lazy servers) */ 
     60#define IMAP_MAX_CMDLEN 1024 
    5861 
    5962#define IMAP_REOPEN_ALLOW     (1<<0) 
     
    226229                                 int create); 
    227230void imap_mboxcache_free (IMAP_DATA* idata); 
    228 int imap_make_msg_set (IMAP_DATA* idata, BUFFER* buf, int flag, int changed, 
    229                       int invert); 
     231int imap_exec_msgset (IMAP_DATA* idata, const char* pre, const char* post, 
     232                      int flag, int changed, int invert); 
    230233int imap_open_connection (IMAP_DATA* idata); 
    231234void imap_close_connection (IMAP_DATA* idata); 
  • imap/message.c

    r5499 r5501  
    689689  IMAP_DATA* idata; 
    690690  BUFFER cmd, sync_cmd; 
    691   char uid[11]; 
    692691  char mbox[LONG_STRING]; 
    693692  char mmbox[LONG_STRING]; 
     693  char prompt[LONG_STRING]; 
    694694  int rc; 
    695695  int n; 
    696696  IMAP_MBOX mx; 
    697697  int err_continue = M_NO; 
     698  int triedcreate = 0; 
    698699 
    699700  idata = (IMAP_DATA*) ctx->data; 
     
    720721   
    721722  imap_fix_path (idata, mx.mbox, mbox, sizeof (mbox)); 
    722  
    723   memset (&sync_cmd, 0, sizeof (sync_cmd)); 
    724   memset (&cmd, 0, sizeof (cmd)); 
    725   mutt_buffer_addstr (&cmd, "UID COPY "); 
    726  
    727   /* Null HEADER* means copy tagged messages */ 
    728   if (!h) 
    729   { 
    730     /* if any messages have attachments to delete, fall through to FETCH 
    731      * and APPEND. TODO: Copy what we can with COPY, fall through for the 
    732      * remainder. */ 
    733     for (n = 0; n < ctx->msgcount; n++) 
    734     { 
    735       if (ctx->hdrs[n]->tagged && ctx->hdrs[n]->attach_del) 
     723  imap_munge_mbox_name (mmbox, sizeof (mmbox), mbox); 
     724 
     725  /* loop in case of TRYCREATE */ 
     726  do 
     727  { 
     728    memset (&sync_cmd, 0, sizeof (sync_cmd)); 
     729    memset (&cmd, 0, sizeof (cmd)); 
     730 
     731    /* Null HEADER* means copy tagged messages */ 
     732    if (!h) 
     733    { 
     734      /* if any messages have attachments to delete, fall through to FETCH 
     735       * and APPEND. TODO: Copy what we can with COPY, fall through for the 
     736       * remainder. */ 
     737      for (n = 0; n < ctx->msgcount; n++) 
    736738      { 
    737         dprint (3, (debugfile, "imap_copy_messages: Message contains attachments to be deleted\n")); 
    738         return 1; 
     739        if (ctx->hdrs[n]->tagged && ctx->hdrs[n]->attach_del) 
     740        { 
     741          dprint (3, (debugfile, "imap_copy_messages: Message contains attachments to be deleted\n")); 
     742          return 1; 
     743        } 
     744 
     745        if (ctx->hdrs[n]->tagged && ctx->hdrs[n]->active && 
     746            ctx->hdrs[n]->changed) 
     747        { 
     748          rc = imap_sync_message (idata, ctx->hdrs[n], &sync_cmd, &err_continue); 
     749          if (rc < 0) 
     750          { 
     751            dprint (1, (debugfile, "imap_copy_messages: could not sync\n")); 
     752            goto fail; 
     753          } 
     754        } 
    739755      } 
    740756 
    741       if (ctx->hdrs[n]->tagged && ctx->hdrs[n]->active && 
    742           ctx->hdrs[n]->changed) 
     757      rc = imap_exec_msgset (idata, "UID COPY", mmbox, M_TAG, 0, 0); 
     758      if (!rc) 
    743759      { 
    744         rc = imap_sync_message (idata, ctx->hdrs[n], &sync_cmd, &err_continue); 
    745         if (rc < 0) 
    746         { 
    747           dprint (1, (debugfile, "imap_copy_messages: could not sync\n")); 
    748           goto fail; 
    749         } 
     760        dprint (1, (debugfile, "imap_copy_messages: No messages tagged\n")); 
     761        goto fail; 
    750762      } 
    751     } 
    752  
    753     rc = imap_make_msg_set (idata, &cmd, M_TAG, 0, 0); 
    754     if (!rc) 
    755     { 
    756       dprint (1, (debugfile, "imap_copy_messages: No messages tagged\n")); 
    757       goto fail; 
    758     } 
    759     mutt_message (_("Copying %d messages to %s..."), rc, mbox); 
    760   } 
    761   else 
    762   { 
    763     mutt_message (_("Copying message %d to %s..."), h->index+1, mbox); 
    764     snprintf (uid, sizeof (uid), "%u", HEADER_DATA (h)->uid); 
    765     mutt_buffer_addstr (&cmd, uid); 
    766  
    767     if (h->active && h->changed) 
    768     { 
    769       rc = imap_sync_message (idata, h, &sync_cmd, &err_continue); 
    770       if (rc < 0) 
     763      else if (rc < 0) 
    771764      { 
    772         dprint (1, (debugfile, "imap_copy_messages: could not sync\n")); 
    773         goto fail; 
     765        dprint (1, (debugfile, "could not queue copy\n")); 
     766        goto fail; 
    774767      } 
    775     } 
    776   } 
    777  
    778   /* let's get it on */ 
    779   mutt_buffer_addstr (&cmd, " "); 
    780   imap_munge_mbox_name (mmbox, sizeof (mmbox), mbox); 
    781   mutt_buffer_addstr (&cmd, mmbox); 
    782  
    783   rc = imap_exec (idata, cmd.data, IMAP_CMD_FAIL_OK); 
    784   if (rc == -2) 
    785   { 
    786     /* bail out if command failed for reasons other than nonexistent target */ 
    787     if (ascii_strncasecmp (imap_get_qualifier (idata->buf), "[TRYCREATE]", 11)) 
    788     { 
    789       imap_error ("imap_copy_messages", idata->buf); 
    790       goto fail; 
    791     } 
    792     dprint (2, (debugfile, "imap_copy_messages: server suggests TRYCREATE\n")); 
    793     snprintf (mmbox, sizeof (mmbox), _("Create %s?"), mbox); 
    794     if (option (OPTCONFIRMCREATE) && mutt_yesorno (mmbox, 1) < 1) 
    795     { 
    796       mutt_clear_error (); 
    797       goto fail; 
    798     } 
    799     if (imap_create_mailbox (idata, mbox) < 0) 
    800       goto fail; 
    801  
    802     /* try again */ 
    803     rc = imap_exec (idata, cmd.data, 0); 
    804   } 
     768      else 
     769        mutt_message (_("Copying %d messages to %s..."), rc, mbox); 
     770    } 
     771    else 
     772    { 
     773      mutt_message (_("Copying message %d to %s..."), h->index+1, mbox); 
     774      mutt_buffer_printf (&cmd, "UID COPY %u %s", HEADER_DATA (h)->uid, mmbox); 
     775 
     776      if (h->active && h->changed) 
     777      { 
     778        rc = imap_sync_message (idata, h, &sync_cmd, &err_continue); 
     779        if (rc < 0) 
     780        { 
     781          dprint (1, (debugfile, "imap_copy_messages: could not sync\n")); 
     782          goto fail; 
     783        } 
     784      }     
     785      if ((rc = imap_exec (idata, cmd.data, IMAP_CMD_QUEUE)) < 0) 
     786      { 
     787        dprint (1, (debugfile, "could not queue copy\n")); 
     788        goto fail; 
     789      } 
     790    } 
     791 
     792    /* let's get it on */ 
     793    rc = imap_exec (idata, NULL, IMAP_CMD_FAIL_OK); 
     794    if (rc == -2) 
     795    { 
     796      if (triedcreate) 
     797      { 
     798        dprint (1, (debugfile, "Already tried to create mailbox %s\n", mbox)); 
     799        break; 
     800      } 
     801      /* bail out if command failed for reasons other than nonexistent target */ 
     802      if (ascii_strncasecmp (imap_get_qualifier (idata->buf), "[TRYCREATE]", 11)) 
     803        break; 
     804      dprint (3, (debugfile, "imap_copy_messages: server suggests TRYCREATE\n")); 
     805      snprintf (prompt, sizeof (prompt), _("Create %s?"), mbox); 
     806      if (option (OPTCONFIRMCREATE) && mutt_yesorno (prompt, 1) < 1) 
     807      { 
     808        mutt_clear_error (); 
     809        break; 
     810      } 
     811      if (imap_create_mailbox (idata, mbox) < 0) 
     812        break; 
     813      triedcreate = 1; 
     814    } 
     815  } 
     816  while (rc == -2); 
     817 
    805818  if (rc != 0) 
    806819  {