~ubuntu-dev/ubuntu/lucid/mutt/lucid-201002101854

« back to all changes in this revision

Viewing changes to imap/imap.c

Tags: 1.5.18-6
* Grab from upstream:
  + Guard idata->mailbox read in imap_mailbox_state.
    The bug happens when a user has more than a imap mailbox, when
    he/she browses through them mutt will segfault.
    (Closes: #462266, #513230, #514309. Mutt: #3057)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * Copyright (C) 1996-8 Michael R. Elkins <me@mutt.org>
3
3
 * Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
4
 
 * Copyright (C) 1999-2006 Brendan Cully <brendan@kublai.com>
 
4
 * Copyright (C) 1999-2007 Brendan Cully <brendan@kublai.com>
5
5
 * 
6
6
 *     This program is free software; you can redistribute it and/or modify
7
7
 *     it under the terms of the GNU General Public License as published by
63
63
  char buf[LONG_STRING];
64
64
  char mailbox[LONG_STRING];
65
65
  char mbox[LONG_STRING];
 
66
  int rc;
66
67
 
67
68
  if (imap_parse_path (path, &mx))
68
69
    return -1;
82
83
    FREE (&mx.mbox);
83
84
    return 0;
84
85
  }
85
 
 
86
86
  FREE (&mx.mbox);
 
87
 
 
88
  if (imap_mboxcache_get (idata, mailbox, 0))
 
89
  {
 
90
    dprint (3, (debugfile, "imap_access: found %s in cache\n", mailbox));
 
91
    return 0;
 
92
  }
 
93
 
87
94
  imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
88
95
 
89
96
  if (mutt_bit_isset (idata->capabilities, IMAP4REV1))
96
103
    return -1;
97
104
  }
98
105
 
99
 
  if (imap_exec (idata, buf, IMAP_CMD_FAIL_OK) < 0)
 
106
  if ((rc = imap_exec (idata, buf, IMAP_CMD_FAIL_OK)) < 0)
100
107
  {
101
108
    dprint (1, (debugfile, "imap_access: Can't check STATUS of %s\n", mbox));
102
 
    return -1;
 
109
    return rc;
103
110
  }
104
111
 
105
112
  return 0;
223
230
    fputc (c, fp);
224
231
    
225
232
    if (pbar && !(pos % 1024))
226
 
      mutt_progress_bar (pbar, pos);
 
233
      mutt_progress_update (pbar, pos, -1);
227
234
#ifdef DEBUG
228
235
    if (debuglevel >= IMAP_LOG_LTRL)
229
236
      fputc (c, debugfile);
241
248
  HEADER* h;
242
249
  int i, cacheno;
243
250
 
244
 
#if USE_HCACHE
245
 
  header_cache_t *hc;
246
 
  char uidbuf[32];
247
 
  
248
 
  hc = mutt_hcache_open (HeaderCache, idata->ctx->path);
 
251
#ifdef USE_HCACHE
 
252
  idata->hcache = imap_hcache_open (idata, NULL);
249
253
#endif
250
254
 
251
255
  for (i = 0; i < idata->ctx->msgcount; i++)
257
261
      dprint (2, (debugfile, "Expunging message UID %d.\n", HEADER_DATA (h)->uid));
258
262
 
259
263
      h->active = 0;
 
264
      idata->ctx->size -= h->content->length;
260
265
 
261
266
      imap_cache_del (idata, h);
262
267
#if USE_HCACHE
263
 
      if (hc)
264
 
      {
265
 
        sprintf (uidbuf, "/%u", HEADER_DATA(h)->uid);
266
 
        mutt_hcache_delete (hc, uidbuf, imap_hcache_keylen);
267
 
      }
 
268
      imap_hcache_del (idata, HEADER_DATA(h)->uid);
268
269
#endif
269
270
 
270
271
      /* free cached body from disk, if necessary */
281
282
  }
282
283
 
283
284
#if USE_HCACHE
284
 
  mutt_hcache_close (hc);
 
285
  imap_hcache_close (idata);
285
286
#endif
286
287
 
287
288
  /* We may be called on to expunge at any time. We can't rely on the caller
341
342
    }
342
343
    if (flags & M_IMAP_CONN_NOSELECT && idata && idata->state >= IMAP_SELECTED)
343
344
      continue;
 
345
    if (idata && idata->status == IMAP_FATAL)
 
346
      continue;
344
347
    break;
345
348
  }
 
349
  if (!conn)
 
350
          return NULL; /* this happens when the initial connection fails */
346
351
 
347
352
  if (!idata)
348
353
  {
365
370
    if (!imap_authenticate (idata))
366
371
    {
367
372
      idata->state = IMAP_AUTHENTICATED;
 
373
      new = 1;
368
374
      if (idata->conn->ssf)
369
375
        dprint (2, (debugfile, "Communication encrypted at %d bits\n",
370
376
                    idata->conn->ssf));
376
382
  }
377
383
  if (new && idata->state == IMAP_AUTHENTICATED)
378
384
  {
 
385
    /* capabilities may have changed */
 
386
    imap_cmd_queue (idata, "CAPABILITY");
379
387
    /* get root delimiter, '/' as default */
380
388
    idata->delim = '/';
381
389
    imap_cmd_queue (idata, "LIST \"\" \"\"");
399
407
 
400
408
  if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE)
401
409
  {
402
 
    mutt_socket_close (idata->conn);
403
 
    idata->state = IMAP_DISCONNECTED;
 
410
    imap_close_connection (idata);
404
411
    return -1;
405
412
  }
406
413
 
467
474
 
468
475
#if defined(USE_SSL)
469
476
 err_close_conn:
 
477
  imap_close_connection (idata);
 
478
#endif
 
479
 bail:
 
480
  FREE (&idata->capstr);
 
481
  return -1;
 
482
}
 
483
 
 
484
void imap_close_connection(IMAP_DATA* idata)
 
485
{
470
486
  mutt_socket_close (idata->conn);
471
487
  idata->state = IMAP_DISCONNECTED;
472
 
#endif
473
 
 bail:
474
 
  FREE (&idata->capstr);
475
 
  return -1;
 
488
  idata->seqno = idata->nextcmd = idata->lastcmd = idata->status = 0;
 
489
  memset (idata->cmds, 0, sizeof (IMAP_COMMAND) * IMAP_PIPELINE_DEPTH);
476
490
}
477
491
 
478
492
/* imap_get_flags: Make a simple list out of a FLAGS response.
536
550
{
537
551
  CONNECTION *conn;
538
552
  IMAP_DATA *idata;
539
 
  IMAP_STATUS* status, sb;
 
553
  IMAP_STATUS* status;
540
554
  char buf[LONG_STRING];
541
555
  char bufout[LONG_STRING];
542
556
  int count = 0;
559
573
 
560
574
  /* once again the context is new */
561
575
  ctx->data = idata;
 
576
  ctx->mx_close = imap_close_mailbox;
562
577
 
563
578
  /* Clean up path and replace the one in the ctx */
564
579
  imap_fix_path (idata, mx.mbox, buf, sizeof (buf));
573
588
 
574
589
  /* clear mailbox status */
575
590
  idata->status = 0;
576
 
  memset (idata->rights, 0, (RIGHTSMAX+7)/8);
 
591
  memset (idata->ctx->rights, 0, sizeof (idata->ctx->rights));
577
592
  idata->newMailCount = 0;
578
593
 
579
594
  mutt_message (_("Selecting %s..."), idata->mailbox);
588
603
  /* assume we have all rights if ACL is unavailable */
589
604
  else
590
605
  {
591
 
    mutt_bit_set (idata->rights, IMAP_ACL_LOOKUP);
592
 
    mutt_bit_set (idata->rights, IMAP_ACL_READ);
593
 
    mutt_bit_set (idata->rights, IMAP_ACL_SEEN);
594
 
    mutt_bit_set (idata->rights, IMAP_ACL_WRITE);
595
 
    mutt_bit_set (idata->rights, IMAP_ACL_INSERT);
596
 
    mutt_bit_set (idata->rights, IMAP_ACL_POST);
597
 
    mutt_bit_set (idata->rights, IMAP_ACL_CREATE);
598
 
    mutt_bit_set (idata->rights, IMAP_ACL_DELETE);
 
606
    mutt_bit_set (idata->ctx->rights, M_ACL_LOOKUP);
 
607
    mutt_bit_set (idata->ctx->rights, M_ACL_READ);
 
608
    mutt_bit_set (idata->ctx->rights, M_ACL_SEEN);
 
609
    mutt_bit_set (idata->ctx->rights, M_ACL_WRITE);
 
610
    mutt_bit_set (idata->ctx->rights, M_ACL_INSERT);
 
611
    mutt_bit_set (idata->ctx->rights, M_ACL_POST);
 
612
    mutt_bit_set (idata->ctx->rights, M_ACL_CREATE);
 
613
    mutt_bit_set (idata->ctx->rights, M_ACL_DELETE);
599
614
  }
600
615
  /* pipeline the postponed count if possible */
601
616
  pmx.mbox = NULL;
611
626
 
612
627
  imap_cmd_start (idata, bufout);
613
628
 
614
 
  if (!(status = imap_mboxcache_get (idata, idata->mailbox)))
615
 
  {
616
 
    memset (&sb, 0, sizeof (IMAP_STATUS));
617
 
    sb.name = idata->mailbox;
618
 
    idata->mboxcache = mutt_add_list_n (idata->mboxcache, &sb, sizeof (IMAP_STATUS));
619
 
    status = imap_mboxcache_get (idata, idata->mailbox);
620
 
    status->name = safe_strdup (idata->mailbox);
621
 
  }
 
629
  status = imap_mboxcache_get (idata, idata->mailbox, 1);
 
630
 
622
631
  do
623
632
  {
624
633
    char *pc;
724
733
  }
725
734
#endif
726
735
 
727
 
  if (!(mutt_bit_isset(idata->rights, IMAP_ACL_DELETE) ||
728
 
        mutt_bit_isset(idata->rights, IMAP_ACL_SEEN) ||
729
 
        mutt_bit_isset(idata->rights, IMAP_ACL_WRITE) ||
730
 
        mutt_bit_isset(idata->rights, IMAP_ACL_INSERT)))
 
736
  if (!(mutt_bit_isset(idata->ctx->rights, M_ACL_DELETE) ||
 
737
        mutt_bit_isset(idata->ctx->rights, M_ACL_SEEN) ||
 
738
        mutt_bit_isset(idata->ctx->rights, M_ACL_WRITE) ||
 
739
        mutt_bit_isset(idata->ctx->rights, M_ACL_INSERT)))
731
740
     ctx->readonly = 1;
732
741
 
733
742
  ctx->hdrmax = count;
734
743
  ctx->hdrs = safe_calloc (count, sizeof (HEADER *));
735
744
  ctx->v2r = safe_calloc (count, sizeof (int));
736
745
  ctx->msgcount = 0;
 
746
 
737
747
  if (count && (imap_read_headers (idata, 0, count-1) < 0))
738
748
  {
739
749
    mutt_error _("Error opening mailbox");
760
770
  char buf[LONG_STRING];
761
771
  char mailbox[LONG_STRING];
762
772
  IMAP_MBOX mx;
 
773
  int rc;
763
774
 
764
775
  if (imap_parse_path (ctx->path, &mx))
765
776
    return -1;
782
793
  FREE (&mx.mbox);
783
794
 
784
795
  /* really we should also check for W_OK */
785
 
  if (!imap_access (ctx->path, F_OK))
 
796
  if ((rc = imap_access (ctx->path, F_OK)) == 0)
786
797
    return 0;
787
798
 
 
799
  if (rc == -1)
 
800
    return -1;
 
801
 
788
802
  snprintf (buf, sizeof (buf), _("Create %s?"), mailbox);
789
803
  if (option (OPTCONFIRMCREATE) && mutt_yesorno (buf, 1) < 1)
790
804
    return -1;
815
829
static void imap_set_flag (IMAP_DATA* idata, int aclbit, int flag,
816
830
  const char *str, char *flags, size_t flsize)
817
831
{
818
 
  if (mutt_bit_isset (idata->rights, aclbit))
 
832
  if (mutt_bit_isset (idata->ctx->rights, aclbit))
819
833
    if (flag && imap_has_flag (idata->flags, str))
820
834
      safe_strcat (flags, flsize, str);
821
835
}
846
860
 *   headers, given a flag enum to filter on.
847
861
 * Params: idata: IMAP_DATA containing context containing header set
848
862
 *         buf: to write message set into
849
 
 *         buflen: length of buffer
850
863
 *         flag: enum of flag type on which to filter
851
864
 *         changed: include only changed messages in message set
852
865
 *         invert: invert sense of flag, eg M_READ matches unread messages
928
941
      else if (n == idata->ctx->msgcount-1)
929
942
        mutt_buffer_printf (buf, ":%u", HEADER_DATA (hdrs[n])->uid);
930
943
    }
931
 
    /* this message is not expunged and doesn't match. End current set. */
932
 
    else if (setstart && hdrs[n]->active)
 
944
    /* End current set if message doesn't match or we've reached the end
 
945
     * of the mailbox via inactive messages following the last match. */
 
946
    else if (setstart && (hdrs[n]->active || n == idata->ctx->msgcount-1))
933
947
    {
934
948
      if (HEADER_DATA (hdrs[n-1])->uid > setstart)
935
949
        mutt_buffer_printf (buf, ":%u", HEADER_DATA (hdrs[n-1])->uid);
985
999
 
986
1000
  flags[0] = '\0';
987
1001
      
988
 
  imap_set_flag (idata, IMAP_ACL_SEEN, hdr->read, "\\Seen ",
 
1002
  imap_set_flag (idata, M_ACL_SEEN, hdr->read, "\\Seen ",
989
1003
                 flags, sizeof (flags));
990
 
  imap_set_flag (idata, IMAP_ACL_WRITE, hdr->old,
 
1004
  imap_set_flag (idata, M_ACL_WRITE, hdr->old,
991
1005
                 "Old ", flags, sizeof (flags));
992
 
  imap_set_flag (idata, IMAP_ACL_WRITE, hdr->flagged,
 
1006
  imap_set_flag (idata, M_ACL_WRITE, hdr->flagged,
993
1007
                 "\\Flagged ", flags, sizeof (flags));
994
 
  imap_set_flag (idata, IMAP_ACL_WRITE, hdr->replied,
 
1008
  imap_set_flag (idata, M_ACL_WRITE, hdr->replied,
995
1009
                 "\\Answered ", flags, sizeof (flags));
996
 
  imap_set_flag (idata, IMAP_ACL_DELETE, hdr->deleted,
 
1010
  imap_set_flag (idata, M_ACL_DELETE, hdr->deleted,
997
1011
                 "\\Deleted ", flags, sizeof (flags));
998
1012
 
999
1013
  /* now make sure we don't lose custom tags */
1000
 
  if (mutt_bit_isset (idata->rights, IMAP_ACL_WRITE))
 
1014
  if (mutt_bit_isset (idata->ctx->rights, M_ACL_WRITE))
1001
1015
    imap_add_keywords (flags, hdr, idata->flags, sizeof (flags));
1002
1016
 
1003
1017
  mutt_remove_trailing_ws (flags);
1006
1020
   * explicitly revoke all system flags (if we have permission) */
1007
1021
  if (!*flags)
1008
1022
  {
1009
 
    imap_set_flag (idata, IMAP_ACL_SEEN, 1, "\\Seen ", flags, sizeof (flags));
1010
 
    imap_set_flag (idata, IMAP_ACL_WRITE, 1, "Old ", flags, sizeof (flags));
1011
 
    imap_set_flag (idata, IMAP_ACL_WRITE, 1, "\\Flagged ", flags, sizeof (flags));
1012
 
    imap_set_flag (idata, IMAP_ACL_WRITE, 1, "\\Answered ", flags, sizeof (flags));
1013
 
    imap_set_flag (idata, IMAP_ACL_DELETE, 1, "\\Deleted ", flags, sizeof (flags));
 
1023
    imap_set_flag (idata, M_ACL_SEEN, 1, "\\Seen ", flags, sizeof (flags));
 
1024
    imap_set_flag (idata, M_ACL_WRITE, 1, "Old ", flags, sizeof (flags));
 
1025
    imap_set_flag (idata, M_ACL_WRITE, 1, "\\Flagged ", flags, sizeof (flags));
 
1026
    imap_set_flag (idata, M_ACL_WRITE, 1, "\\Answered ", flags, sizeof (flags));
 
1027
    imap_set_flag (idata, M_ACL_DELETE, 1, "\\Deleted ", flags, sizeof (flags));
1014
1028
 
1015
1029
    mutt_remove_trailing_ws (flags);
1016
1030
 
1046
1060
{
1047
1061
  int rc = 0;
1048
1062
 
1049
 
  if (!mutt_bit_isset (idata->rights, right))
 
1063
  if (!mutt_bit_isset (idata->ctx->rights, right))
1050
1064
    return 0;
1051
1065
  
1052
 
  if (right == IMAP_ACL_WRITE && !imap_has_flag (idata->flags, name))
 
1066
  if (right == M_ACL_WRITE && !imap_has_flag (idata->flags, name))
1053
1067
    return 0;
1054
1068
 
1055
1069
  buf->dptr = buf->data;
1088
1102
  int deleted;
1089
1103
  int n;
1090
1104
  int rc;
1091
 
#if USE_HCACHE
1092
 
  void* hc = NULL;
1093
 
  char uidbuf[32];
1094
 
#endif
1095
1105
  
1096
1106
  idata = (IMAP_DATA*) ctx->data;
1097
1107
 
1111
1121
  memset (&cmd, 0, sizeof (cmd));
1112
1122
 
1113
1123
  /* if we are expunging anyway, we can do deleted messages very quickly... */
1114
 
  if (expunge && mutt_bit_isset (idata->rights, IMAP_ACL_DELETE))
 
1124
  if (expunge && mutt_bit_isset (idata->ctx->rights, M_ACL_DELETE))
1115
1125
  {
1116
1126
    mutt_buffer_addstr (&cmd, "UID STORE ");
1117
1127
    deleted = imap_make_msg_set (idata, &cmd, M_DELETED, 1, 0);
1137
1147
  }
1138
1148
 
1139
1149
#if USE_HCACHE
1140
 
  if (expunge && ctx->closing)
1141
 
    hc = mutt_hcache_open (HeaderCache, idata->ctx->path);
 
1150
  idata->hcache = imap_hcache_open (idata, NULL);
1142
1151
#endif
1143
1152
 
1144
1153
  /* save messages with real (non-flag) changes */
1147
1156
    h = ctx->hdrs[n];
1148
1157
 
1149
1158
    if (h->deleted)
 
1159
    {
1150
1160
      imap_cache_del (idata, h);
1151
1161
#if USE_HCACHE
1152
 
    if (hc && h->deleted)
1153
 
    {
1154
 
      sprintf (uidbuf, "/%u", HEADER_DATA(h)->uid);
1155
 
      mutt_hcache_delete (hc, uidbuf, imap_hcache_keylen);
 
1162
      imap_hcache_del (idata, HEADER_DATA(h)->uid);
 
1163
#endif
1156
1164
    }
1157
 
#endif
 
1165
    
1158
1166
    if (h->active && h->changed)
1159
1167
    {
1160
1168
      /* if the message has been rethreaded or attachments have been deleted
1177
1185
    }
1178
1186
  }
1179
1187
 
 
1188
#if USE_HCACHE
 
1189
  imap_hcache_close (idata);
 
1190
#endif
 
1191
 
1180
1192
  /* sync +/- flags for the five flags mutt cares about */
1181
1193
  rc = 0;
1182
1194
 
1194
1206
           mutt_get_sort_func (SORT_ORDER));
1195
1207
  }
1196
1208
 
1197
 
  rc += sync_helper (idata, &cmd, IMAP_ACL_DELETE, M_DELETED, "\\Deleted");
1198
 
  rc += sync_helper (idata, &cmd, IMAP_ACL_WRITE, M_FLAG, "\\Flagged");
1199
 
  rc += sync_helper (idata, &cmd, IMAP_ACL_WRITE, M_OLD, "Old");
1200
 
  rc += sync_helper (idata, &cmd, IMAP_ACL_SEEN, M_READ, "\\Seen");
1201
 
  rc += sync_helper (idata, &cmd, IMAP_ACL_WRITE, M_REPLIED, "\\Answered");
 
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");
1202
1214
 
1203
1215
  if (oldsort != Sort)
1204
1216
  {
1231
1243
 
1232
1244
  /* We must send an EXPUNGE command if we're not closing. */
1233
1245
  if (expunge && !(ctx->closing) &&
1234
 
      mutt_bit_isset(idata->rights, IMAP_ACL_DELETE))
 
1246
      mutt_bit_isset(idata->ctx->rights, M_ACL_DELETE))
1235
1247
  {
1236
1248
    mutt_message _("Expunging messages from server...");
1237
1249
    /* Set expunge bit so we don't get spurious reopened messages */
1250
1262
    idata->state = IMAP_AUTHENTICATED;
1251
1263
  }
1252
1264
 
 
1265
  if (option (OPTMESSAGECACHECLEAN))
 
1266
    imap_cache_clean (idata);
 
1267
 
1253
1268
  rc = 0;
 
1269
 
1254
1270
 out:
1255
 
#if USE_HCACHE
1256
 
  mutt_hcache_close (hc);
1257
 
#endif
1258
1271
  if (cmd.data)
1259
1272
    FREE (&cmd.data);
1260
1273
  if (appendctx)
1266
1279
}
1267
1280
 
1268
1281
/* imap_close_mailbox: clean up IMAP data in CONTEXT */
1269
 
void imap_close_mailbox (CONTEXT* ctx)
 
1282
int imap_close_mailbox (CONTEXT* ctx)
1270
1283
{
1271
1284
  IMAP_DATA* idata;
1272
1285
  int i;
1274
1287
  idata = (IMAP_DATA*) ctx->data;
1275
1288
  /* Check to see if the mailbox is actually open */
1276
1289
  if (!idata)
1277
 
    return;
 
1290
    return 0;
1278
1291
 
1279
1292
  if (ctx == idata->ctx)
1280
1293
  {
1300
1313
 
1301
1314
  /* free IMAP part of headers */
1302
1315
  for (i = 0; i < ctx->msgcount; i++)
1303
 
    imap_free_header_data (&(ctx->hdrs[i]->data));
 
1316
    /* mailbox may not have fully loaded */
 
1317
    if (ctx->hdrs[i] && ctx->hdrs[i]->data)
 
1318
      imap_free_header_data (&(ctx->hdrs[i]->data));
1304
1319
 
1305
1320
  for (i = 0; i < IMAP_CACHE_LEN; i++)
1306
1321
  {
1312
1327
  }
1313
1328
 
1314
1329
  mutt_bcache_close (&idata->bcache);
 
1330
 
 
1331
  return 0;
1315
1332
}
1316
1333
 
1317
1334
/* use the NOOP or IDLE command to poll for new mail
1444
1461
     * IDLEd elsewhere */
1445
1462
    if (!imap_mxcmp (name, idata->mailbox))
1446
1463
      continue;
1447
 
      
1448
 
    if (!lastdata)
1449
 
      lastdata = idata;
1450
 
 
1451
 
    if (idata != lastdata)
 
1464
 
 
1465
    if (!mutt_bit_isset (idata->capabilities, IMAP4REV1) &&
 
1466
        !mutt_bit_isset (idata->capabilities, STATUS))
 
1467
    {
 
1468
      dprint (2, (debugfile, "Server doesn't support STATUS\n"));
 
1469
      continue;
 
1470
    }
 
1471
 
 
1472
    if (lastdata && idata != lastdata)
1452
1473
    {
1453
1474
      /* Send commands to previous server. Sorting the buffy list
1454
1475
       * may prevent some infelicitous interleavings */
1458
1479
      lastdata = NULL;
1459
1480
    }
1460
1481
 
1461
 
    if (!mutt_bit_isset (idata->capabilities, IMAP4REV1) &&
1462
 
        !mutt_bit_isset (idata->capabilities, STATUS))
1463
 
    {
1464
 
      dprint (2, (debugfile, "Server doesn't support STATUS\n"));
1465
 
      continue;
1466
 
    }
1467
 
    
 
1482
    if (!lastdata)
 
1483
      lastdata = idata;
 
1484
 
1468
1485
    imap_munge_mbox_name (munged, sizeof (munged), name);
1469
 
    snprintf (command, sizeof (command), "STATUS %s (UIDNEXT UIDVALIDITY UNSEEN)", munged);
 
1486
    snprintf (command, sizeof (command),
 
1487
              "STATUS %s (UIDNEXT UIDVALIDITY UNSEEN RECENT)", munged);
1470
1488
 
1471
1489
    if (imap_cmd_queue (idata, command) < 0)
1472
1490
    {
1540
1558
    imap_exec (idata, buf, 0);
1541
1559
 
1542
1560
  queued = 0;
1543
 
  if ((status = imap_mboxcache_get (idata, mbox)))
 
1561
  if ((status = imap_mboxcache_get (idata, mbox, 0)))
1544
1562
    return status->messages;
1545
1563
  
1546
1564
  return 0;
1547
1565
}
1548
1566
 
1549
 
/* return cached mailbox stats or NULL */
1550
 
IMAP_STATUS* imap_mboxcache_get (IMAP_DATA* idata, const char* mbox)
 
1567
/* return cached mailbox stats or NULL if create is 0 */
 
1568
IMAP_STATUS* imap_mboxcache_get (IMAP_DATA* idata, const char* mbox, int create)
1551
1569
{
1552
1570
  LIST* cur;
1553
1571
  IMAP_STATUS* status;
 
1572
  IMAP_STATUS scache;
 
1573
#ifdef USE_HCACHE
 
1574
  header_cache_t *hc = NULL;
 
1575
  unsigned int *uidvalidity = NULL;
 
1576
  unsigned int *uidnext = NULL;
 
1577
#endif
1554
1578
  
1555
1579
  for (cur = idata->mboxcache; cur; cur = cur->next)
1556
1580
  {
1559
1583
    if (!imap_mxcmp (mbox, status->name))
1560
1584
      return status;
1561
1585
  }
1562
 
  
1563
 
  return NULL;
 
1586
  status = NULL;
 
1587
 
 
1588
  /* lame */
 
1589
  if (create)
 
1590
  {
 
1591
    memset (&scache, 0, sizeof (scache));
 
1592
    scache.name = (char*)mbox;
 
1593
    idata->mboxcache = mutt_add_list_n (idata->mboxcache, &scache,
 
1594
                                        sizeof (scache));
 
1595
    status = imap_mboxcache_get (idata, mbox, 0);
 
1596
    status->name = safe_strdup (mbox);
 
1597
  }
 
1598
 
 
1599
#ifdef USE_HCACHE
 
1600
  hc = imap_hcache_open (idata, mbox);
 
1601
  if (hc)
 
1602
  {
 
1603
    uidvalidity = mutt_hcache_fetch_raw (hc, "/UIDVALIDITY", imap_hcache_keylen);
 
1604
    uidnext = mutt_hcache_fetch_raw (hc, "/UIDNEXT", imap_hcache_keylen);
 
1605
    mutt_hcache_close (hc);
 
1606
    if (uidvalidity)
 
1607
    {
 
1608
      if (!status)
 
1609
      {
 
1610
        FREE (&uidvalidity);
 
1611
        FREE (&uidnext);
 
1612
        return imap_mboxcache_get (idata, mbox, 1);
 
1613
      }
 
1614
      status->uidvalidity = *uidvalidity;
 
1615
      status->uidnext = uidnext ? *uidnext: 0;
 
1616
      dprint (3, (debugfile, "mboxcache: hcache uidvalidity %d, uidnext %d\n",
 
1617
                  status->uidvalidity, status->uidnext));
 
1618
    }
 
1619
    FREE (&uidvalidity);
 
1620
    FREE (&uidnext);
 
1621
  }
 
1622
#endif
 
1623
 
 
1624
  return status;
1564
1625
}
1565
1626
 
1566
1627
void imap_mboxcache_free (IMAP_DATA* idata)
1732
1793
  BUFFER err, token;
1733
1794
  IMAP_MBOX mx;
1734
1795
 
1735
 
  if (!mx_is_imap (path) || imap_parse_path (path, &mx))
 
1796
  if (!mx_is_imap (path) || imap_parse_path (path, &mx) || !mx.mbox)
1736
1797
  {
1737
1798
    mutt_error (_("Bad mailbox name"));
1738
1799
    return -1;
1805
1866
  int matchlen;
1806
1867
  
1807
1868
  matchlen = mutt_strlen (dest);
1808
 
  for (mailbox = Incoming; mailbox && mailbox->next; mailbox = mailbox->next)
 
1869
  for (mailbox = Incoming; mailbox; mailbox = mailbox->next)
1809
1870
  {
1810
1871
    if (!mutt_strncmp (dest, mailbox->path, matchlen))
1811
1872
    {
1819
1880
    }
1820
1881
  }
1821
1882
  
1822
 
  for (conn = mutt_socket_head (); conn && conn->next; conn = conn->next)
 
1883
  for (conn = mutt_socket_head (); conn; conn = conn->next)
1823
1884
  {
1824
1885
    ciss_url_t url;
1825
1886
    char urlstr[LONG_STRING];
1861
1922
  IMAP_MBOX mx;
1862
1923
  int rc;
1863
1924
 
1864
 
  if (imap_parse_path (path, &mx) || !mx.mbox)
 
1925
  if (imap_parse_path (path, &mx))
1865
1926
  {
1866
1927
    strfcpy (dest, path, dlen);
1867
1928
    return imap_complete_hosts (dest, dlen);