]> git.llucax.com Git - software/mutt-debian.git/blob - imap/imap.c
refreshed sidebar patch, readded it to mutt-patched, re-enabled the build of mutt...
[software/mutt-debian.git] / imap / imap.c
1 /*
2  * Copyright (C) 1996-8 Michael R. Elkins <me@mutt.org>
3  * Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
4  * Copyright (C) 1999-2009 Brendan Cully <brendan@kublai.com>
5  * 
6  *     This program is free software; you can redistribute it and/or modify
7  *     it under the terms of the GNU General Public License as published by
8  *     the Free Software Foundation; either version 2 of the License, or
9  *     (at your option) any later version.
10  * 
11  *     This program is distributed in the hope that it will be useful,
12  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *     GNU General Public License for more details.
15  * 
16  *     You should have received a copy of the GNU General Public License
17  *     along with this program; if not, write to the Free Software
18  *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */ 
20
21 /* Support for IMAP4rev1, with the occasional nod to IMAP 4. */
22
23 #if HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include "mutt.h"
28 #include "mx.h"
29 #include "mailbox.h"
30 #include "globals.h"
31 #include "sort.h"
32 #include "browser.h"
33 #include "message.h"
34 #include "imap_private.h"
35 #if defined(USE_SSL)
36 # include "mutt_ssl.h"
37 #endif
38 #include "buffy.h"
39 #if USE_HCACHE
40 #include "hcache.h"
41 #endif
42
43 #include <unistd.h>
44 #include <ctype.h>
45 #include <string.h>
46 #include <stdlib.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49
50 /* imap forward declarations */
51 static char* imap_get_flags (LIST** hflags, char* s);
52 static int imap_check_capabilities (IMAP_DATA* idata);
53 static void imap_set_flag (IMAP_DATA* idata, int aclbit, int flag,
54                            const char* str, char* flags, size_t flsize);
55
56 /* imap_access: Check permissions on an IMAP mailbox.
57  * TODO: ACL checks. Right now we assume if it exists we can
58  *       mess with it. */
59 int imap_access (const char* path, int flags)
60 {
61   IMAP_DATA* idata;
62   IMAP_MBOX mx;
63   char buf[LONG_STRING];
64   char mailbox[LONG_STRING];
65   char mbox[LONG_STRING];
66   int rc;
67
68   if (imap_parse_path (path, &mx))
69     return -1;
70
71   if (!(idata = imap_conn_find (&mx.account,
72     option (OPTIMAPPASSIVE) ? M_IMAP_CONN_NONEW : 0)))
73   {
74     FREE (&mx.mbox);
75     return -1;
76   }
77
78   imap_fix_path (idata, mx.mbox, mailbox, sizeof (mailbox));
79   if (!*mailbox)
80     strfcpy (mailbox, "INBOX", sizeof (mailbox));
81
82   /* we may already be in the folder we're checking */
83   if (!ascii_strcmp(idata->mailbox, mx.mbox))
84   {
85     FREE (&mx.mbox);
86     return 0;
87   }
88   FREE (&mx.mbox);
89
90   if (imap_mboxcache_get (idata, mailbox, 0))
91   {
92     dprint (3, (debugfile, "imap_access: found %s in cache\n", mailbox));
93     return 0;
94   }
95
96   imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
97
98   if (mutt_bit_isset (idata->capabilities, IMAP4REV1))
99     snprintf (buf, sizeof (buf), "STATUS %s (UIDVALIDITY)", mbox);
100   else if (mutt_bit_isset (idata->capabilities, STATUS))
101     snprintf (buf, sizeof (buf), "STATUS %s (UID-VALIDITY)", mbox);
102   else
103   {
104     dprint (2, (debugfile, "imap_access: STATUS not supported?\n"));
105     return -1;
106   }
107
108   if ((rc = imap_exec (idata, buf, IMAP_CMD_FAIL_OK)) < 0)
109   {
110     dprint (1, (debugfile, "imap_access: Can't check STATUS of %s\n", mbox));
111     return rc;
112   }
113
114   return 0;
115 }
116
117 int imap_create_mailbox (IMAP_DATA* idata, char* mailbox)
118 {
119   char buf[LONG_STRING], mbox[LONG_STRING];
120
121   imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
122   snprintf (buf, sizeof (buf), "CREATE %s", mbox);
123       
124   if (imap_exec (idata, buf, 0) != 0)
125   {
126     mutt_error (_("CREATE failed: %s"), imap_cmd_trailer (idata));
127     return -1;
128   }
129
130   return 0;
131 }
132
133 int imap_rename_mailbox (IMAP_DATA* idata, IMAP_MBOX* mx, const char* newname)
134 {
135   char oldmbox[LONG_STRING];
136   char newmbox[LONG_STRING];
137   char buf[LONG_STRING];
138
139   imap_munge_mbox_name (oldmbox, sizeof (oldmbox), mx->mbox);
140   imap_munge_mbox_name (newmbox, sizeof (newmbox), newname);
141
142   snprintf (buf, sizeof (buf), "RENAME %s %s", oldmbox, newmbox);
143
144   if (imap_exec (idata, buf, 0) != 0)
145     return -1;
146
147   return 0;
148 }
149
150 int imap_delete_mailbox (CONTEXT* ctx, IMAP_MBOX mx)
151 {
152   char buf[LONG_STRING], mbox[LONG_STRING];
153   IMAP_DATA *idata;
154
155   if (!ctx || !ctx->data) {
156     if (!(idata = imap_conn_find (&mx.account,
157           option (OPTIMAPPASSIVE) ? M_IMAP_CONN_NONEW : 0)))
158     {
159       FREE (&mx.mbox);
160       return -1;
161     }
162   } else {
163     idata = ctx->data;
164   }
165
166   imap_munge_mbox_name (mbox, sizeof (mbox), mx.mbox);
167   snprintf (buf, sizeof (buf), "DELETE %s", mbox);
168
169   if (imap_exec ((IMAP_DATA*) idata, buf, 0) != 0)
170     return -1;
171
172   return 0;
173 }
174
175 /* imap_logout_all: close all open connections. Quick and dirty until we can
176  *   make sure we've got all the context we need. */
177 void imap_logout_all (void) 
178 {
179   CONNECTION* conn;
180   CONNECTION* tmp;
181
182   conn = mutt_socket_head ();
183
184   while (conn)
185   {
186     tmp = conn->next;
187
188     if (conn->account.type == M_ACCT_TYPE_IMAP && conn->fd >= 0)
189     {
190       mutt_message (_("Closing connection to %s..."), conn->account.host);
191       imap_logout ((IMAP_DATA**) (void*) &conn->data);
192       mutt_clear_error ();
193       mutt_socket_close (conn);
194       mutt_socket_free (conn);
195     }
196
197     conn = tmp;
198   }
199 }
200
201 /* imap_read_literal: read bytes bytes from server into file. Not explicitly
202  *   buffered, relies on FILE buffering. NOTE: strips \r from \r\n.
203  *   Apparently even literals use \r\n-terminated strings ?! */
204 int imap_read_literal (FILE* fp, IMAP_DATA* idata, long bytes, progress_t* pbar)
205 {
206   long pos;
207   char c;
208
209   int r = 0;
210
211   dprint (2, (debugfile, "imap_read_literal: reading %ld bytes\n", bytes));
212  
213   for (pos = 0; pos < bytes; pos++)
214   {
215     if (mutt_socket_readchar (idata->conn, &c) != 1)
216     {
217       dprint (1, (debugfile, "imap_read_literal: error during read, %ld bytes read\n", pos));
218       idata->status = IMAP_FATAL;
219       
220       return -1;
221     }
222
223 #if 1
224     if (r == 1 && c != '\n')
225       fputc ('\r', fp);
226
227     if (c == '\r')
228     {
229       r = 1;
230       continue;
231     }
232     else
233       r = 0;
234 #endif
235     fputc (c, fp);
236     
237     if (pbar && !(pos % 1024))
238       mutt_progress_update (pbar, pos, -1);
239 #ifdef DEBUG
240     if (debuglevel >= IMAP_LOG_LTRL)
241       fputc (c, debugfile);
242 #endif
243   }
244
245   return 0;
246 }
247
248 /* imap_expunge_mailbox: Purge IMAP portion of expunged messages from the
249  *   context. Must not be done while something has a handle on any headers
250  *   (eg inside pager or editor). That is, check IMAP_REOPEN_ALLOW. */
251 void imap_expunge_mailbox (IMAP_DATA* idata)
252 {
253   HEADER* h;
254   int i, cacheno;
255
256 #ifdef USE_HCACHE
257   idata->hcache = imap_hcache_open (idata, NULL);
258 #endif
259
260   for (i = 0; i < idata->ctx->msgcount; i++)
261   {
262     h = idata->ctx->hdrs[i];
263
264     if (h->index == -1)
265     {
266       dprint (2, (debugfile, "Expunging message UID %d.\n", HEADER_DATA (h)->uid));
267
268       h->active = 0;
269       idata->ctx->size -= h->content->length;
270
271       imap_cache_del (idata, h);
272 #if USE_HCACHE
273       imap_hcache_del (idata, HEADER_DATA(h)->uid);
274 #endif
275
276       /* free cached body from disk, if necessary */
277       cacheno = HEADER_DATA(h)->uid % IMAP_CACHE_LEN;
278       if (idata->cache[cacheno].uid == HEADER_DATA(h)->uid &&
279           idata->cache[cacheno].path)
280       {
281         unlink (idata->cache[cacheno].path);
282         FREE (&idata->cache[cacheno].path);
283       }
284
285       imap_free_header_data (&h->data);
286     }
287   }
288
289 #if USE_HCACHE
290   imap_hcache_close (idata);
291 #endif
292
293   /* We may be called on to expunge at any time. We can't rely on the caller
294    * to always know to rethread */
295   mx_update_tables (idata->ctx, 0);
296   mutt_sort_headers (idata->ctx, 1);
297 }
298
299 /* imap_check_capabilities: make sure we can log in to this server. */
300 static int imap_check_capabilities (IMAP_DATA* idata)
301 {
302   if (imap_exec (idata, "CAPABILITY", 0) != 0)
303   {
304     imap_error ("imap_check_capabilities", idata->buf);
305     return -1;
306   }
307
308   if (!(mutt_bit_isset(idata->capabilities,IMAP4)
309       ||mutt_bit_isset(idata->capabilities,IMAP4REV1)))
310   {
311     mutt_error _("This IMAP server is ancient. Mutt does not work with it.");
312     mutt_sleep (2);     /* pause a moment to let the user see the error */
313
314     return -1;
315   }
316
317   return 0;
318 }
319
320 /* imap_conn_find: Find an open IMAP connection matching account, or open
321  *   a new one if none can be found. */
322 IMAP_DATA* imap_conn_find (const ACCOUNT* account, int flags)
323 {
324   CONNECTION* conn = NULL;
325   ACCOUNT* creds = NULL;
326   IMAP_DATA* idata = NULL;
327   int new = 0;
328
329   while ((conn = mutt_conn_find (conn, account)))
330   {
331     if (!creds)
332       creds = &conn->account;
333     else
334       memcpy (&conn->account, creds, sizeof (ACCOUNT));
335
336     idata = (IMAP_DATA*)conn->data;
337     if (flags & M_IMAP_CONN_NONEW)
338     {
339       if (!idata)
340       {
341         /* This should only happen if we've come to the end of the list */
342         mutt_socket_free (conn);
343         return NULL;
344       }
345       else if (idata->state < IMAP_AUTHENTICATED)
346         continue;
347     }
348     if (flags & M_IMAP_CONN_NOSELECT && idata && idata->state >= IMAP_SELECTED)
349       continue;
350     if (idata && idata->status == IMAP_FATAL)
351       continue;
352     break;
353   }
354   if (!conn)
355     return NULL; /* this happens when the initial connection fails */
356
357   if (!idata)
358   {
359     /* The current connection is a new connection */
360     if (! (idata = imap_new_idata ()))
361     {
362       mutt_socket_free (conn);
363       return NULL;
364     }
365
366     conn->data = idata;
367     idata->conn = conn;
368     new = 1;
369   }
370
371   if (idata->state == IMAP_DISCONNECTED)
372     imap_open_connection (idata);
373   if (idata->state == IMAP_CONNECTED)
374   {
375     if (!imap_authenticate (idata))
376     {
377       idata->state = IMAP_AUTHENTICATED;
378       new = 1;
379       if (idata->conn->ssf)
380         dprint (2, (debugfile, "Communication encrypted at %d bits\n",
381                     idata->conn->ssf));
382     }
383     else
384       mutt_account_unsetpass (&idata->conn->account);
385     
386     FREE (&idata->capstr);
387   }
388   if (new && idata->state == IMAP_AUTHENTICATED)
389   {
390     /* capabilities may have changed */
391     imap_exec (idata, "CAPABILITY", IMAP_CMD_QUEUE);
392     /* get root delimiter, '/' as default */
393     idata->delim = '/';
394     imap_exec (idata, "LIST \"\" \"\"", IMAP_CMD_QUEUE);
395     if (option (OPTIMAPCHECKSUBSCRIBED))
396       imap_exec (idata, "LSUB \"\" \"*\"", IMAP_CMD_QUEUE);
397     /* we may need the root delimiter before we open a mailbox */
398     imap_exec (idata, NULL, IMAP_CMD_FAIL_OK);
399   }
400
401   return idata;
402 }
403
404 int imap_open_connection (IMAP_DATA* idata)
405 {
406   char buf[LONG_STRING];
407
408   if (mutt_socket_open (idata->conn) < 0)
409     return -1;
410
411   idata->state = IMAP_CONNECTED;
412
413   if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE)
414   {
415     imap_close_connection (idata);
416     return -1;
417   }
418
419   if (ascii_strncasecmp ("* OK", idata->buf, 4) == 0)
420   {
421     if (ascii_strncasecmp ("* OK [CAPABILITY", idata->buf, 16)
422         && imap_check_capabilities (idata))
423       goto bail;
424 #if defined(USE_SSL)
425     /* Attempt STARTTLS if available and desired. */
426     if (!idata->conn->ssf && (option(OPTSSLFORCETLS) ||
427                               mutt_bit_isset (idata->capabilities, STARTTLS)))
428     {
429       int rc;
430       
431       if (option(OPTSSLFORCETLS))
432         rc = M_YES;
433       else if ((rc = query_quadoption (OPT_SSLSTARTTLS,
434         _("Secure connection with TLS?"))) == -1)
435         goto err_close_conn;
436       if (rc == M_YES) {
437         if ((rc = imap_exec (idata, "STARTTLS", IMAP_CMD_FAIL_OK)) == -1)
438           goto bail;
439         if (rc != -2)
440         {
441           if (mutt_ssl_starttls (idata->conn))
442           {
443             mutt_error (_("Could not negotiate TLS connection"));
444             mutt_sleep (1);
445             goto err_close_conn;
446           }
447           else
448           {
449             /* RFC 2595 demands we recheck CAPABILITY after TLS completes. */
450             if (imap_exec (idata, "CAPABILITY", 0))
451               goto bail;
452           }
453         }
454       }
455     }
456
457     if (option(OPTSSLFORCETLS) && ! idata->conn->ssf)
458     {
459       mutt_error _("Encrypted connection unavailable");
460       mutt_sleep (1);
461       goto err_close_conn;
462     }
463 #endif    
464   }
465   else if (ascii_strncasecmp ("* PREAUTH", idata->buf, 9) == 0)
466   {
467     idata->state = IMAP_AUTHENTICATED;
468     if (imap_check_capabilities (idata) != 0)
469       goto bail;
470     FREE (&idata->capstr);
471   } 
472   else
473   {
474     imap_error ("imap_open_connection()", buf);
475     goto bail;
476   }
477
478   return 0;
479
480 #if defined(USE_SSL)
481  err_close_conn:
482   imap_close_connection (idata);
483 #endif
484  bail:
485   FREE (&idata->capstr);
486   return -1;
487 }
488
489 void imap_close_connection(IMAP_DATA* idata)
490 {
491   mutt_socket_close (idata->conn);
492   idata->state = IMAP_DISCONNECTED;
493   idata->seqno = idata->nextcmd = idata->lastcmd = idata->status = 0;
494   memset (idata->cmds, 0, sizeof (IMAP_COMMAND) * idata->cmdslots);
495 }
496
497 /* imap_get_flags: Make a simple list out of a FLAGS response.
498  *   return stream following FLAGS response */
499 static char* imap_get_flags (LIST** hflags, char* s)
500 {
501   LIST* flags;
502   char* flag_word;
503   char ctmp;
504
505   /* sanity-check string */
506   if (ascii_strncasecmp ("FLAGS", s, 5) != 0)
507   {
508     dprint (1, (debugfile, "imap_get_flags: not a FLAGS response: %s\n",
509       s));
510     return NULL;
511   }
512   s += 5;
513   SKIPWS(s);
514   if (*s != '(')
515   {
516     dprint (1, (debugfile, "imap_get_flags: bogus FLAGS response: %s\n",
517       s));
518     return NULL;
519   }
520
521   /* create list, update caller's flags handle */
522   flags = mutt_new_list();
523   *hflags = flags;
524
525   while (*s && *s != ')')
526   {
527     s++;
528     SKIPWS(s);
529     flag_word = s;
530     while (*s && (*s != ')') && !ISSPACE (*s))
531       s++;
532     ctmp = *s;
533     *s = '\0';
534     if (*flag_word)
535       mutt_add_list (flags, flag_word);
536     *s = ctmp;
537   }
538
539   /* note bad flags response */
540   if (*s != ')')
541   {
542     dprint (1, (debugfile,
543       "imap_get_flags: Unterminated FLAGS response: %s\n", s));
544     mutt_free_list (hflags);
545
546     return NULL;
547   }
548
549   s++;
550
551   return s;
552 }
553
554 int imap_open_mailbox (CONTEXT* ctx)
555 {
556   CONNECTION *conn;
557   IMAP_DATA *idata;
558   IMAP_STATUS* status;
559   char buf[LONG_STRING];
560   char bufout[LONG_STRING];
561   int count = 0;
562   IMAP_MBOX mx, pmx;
563   int rc;
564   
565   if (imap_parse_path (ctx->path, &mx))
566   {
567     mutt_error (_("%s is an invalid IMAP path"), ctx->path);
568     return -1;
569   }
570
571   /* we require a connection which isn't currently in IMAP_SELECTED state */
572   if (!(idata = imap_conn_find (&(mx.account), M_IMAP_CONN_NOSELECT)))
573     goto fail_noidata;
574   if (idata->state < IMAP_AUTHENTICATED)
575     goto fail;
576
577   conn = idata->conn;
578
579   /* once again the context is new */
580   ctx->data = idata;
581   ctx->mx_close = imap_close_mailbox;
582
583   /* Clean up path and replace the one in the ctx */
584   imap_fix_path (idata, mx.mbox, buf, sizeof (buf));
585   if (!*buf)
586     strfcpy (buf, "INBOX", sizeof (buf));
587   FREE(&(idata->mailbox));
588   idata->mailbox = safe_strdup (buf);
589   imap_qualify_path (buf, sizeof (buf), &mx, idata->mailbox);
590
591   FREE (&(ctx->path));
592   ctx->path = safe_strdup (buf);
593
594   idata->ctx = ctx;
595
596   /* clear mailbox status */
597   idata->status = 0;
598   memset (idata->ctx->rights, 0, sizeof (idata->ctx->rights));
599   idata->newMailCount = 0;
600
601   mutt_message (_("Selecting %s..."), idata->mailbox);
602   imap_munge_mbox_name (buf, sizeof(buf), idata->mailbox);
603   
604   /* pipeline ACL test */
605   if (mutt_bit_isset (idata->capabilities, ACL))
606   {
607     snprintf (bufout, sizeof (bufout), "MYRIGHTS %s", buf);
608     imap_exec (idata, bufout, IMAP_CMD_QUEUE);
609   }
610   /* assume we have all rights if ACL is unavailable */
611   else
612   {
613     mutt_bit_set (idata->ctx->rights, M_ACL_LOOKUP);
614     mutt_bit_set (idata->ctx->rights, M_ACL_READ);
615     mutt_bit_set (idata->ctx->rights, M_ACL_SEEN);
616     mutt_bit_set (idata->ctx->rights, M_ACL_WRITE);
617     mutt_bit_set (idata->ctx->rights, M_ACL_INSERT);
618     mutt_bit_set (idata->ctx->rights, M_ACL_POST);
619     mutt_bit_set (idata->ctx->rights, M_ACL_CREATE);
620     mutt_bit_set (idata->ctx->rights, M_ACL_DELETE);
621   }
622   /* pipeline the postponed count if possible */
623   pmx.mbox = NULL;
624   if (mx_is_imap (Postponed) && !imap_parse_path (Postponed, &pmx)
625       && mutt_account_match (&pmx.account, &mx.account))
626     imap_status (Postponed, 1);
627   FREE (&pmx.mbox);
628
629   snprintf (bufout, sizeof (bufout), "%s %s",
630     ctx->readonly ? "EXAMINE" : "SELECT", buf);
631
632   idata->state = IMAP_SELECTED;
633
634   imap_cmd_start (idata, bufout);
635
636   status = imap_mboxcache_get (idata, idata->mailbox, 1);
637
638   do
639   {
640     char *pc;
641     
642     if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
643       break;
644
645     pc = idata->buf + 2;
646
647     /* Obtain list of available flags here, may be overridden by a
648      * PERMANENTFLAGS tag in the OK response */
649     if (ascii_strncasecmp ("FLAGS", pc, 5) == 0)
650     {
651       /* don't override PERMANENTFLAGS */
652       if (!idata->flags)
653       {
654         dprint (3, (debugfile, "Getting mailbox FLAGS\n"));
655         if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
656           goto fail;
657       }
658     }
659     /* PERMANENTFLAGS are massaged to look like FLAGS, then override FLAGS */
660     else if (ascii_strncasecmp ("OK [PERMANENTFLAGS", pc, 18) == 0)
661     {
662       dprint (3, (debugfile, "Getting mailbox PERMANENTFLAGS\n"));
663       /* safe to call on NULL */
664       mutt_free_list (&(idata->flags));
665       /* skip "OK [PERMANENT" so syntax is the same as FLAGS */
666       pc += 13;
667       if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
668         goto fail;
669     }
670     /* save UIDVALIDITY for the header cache */
671     else if (ascii_strncasecmp ("OK [UIDVALIDITY", pc, 14) == 0)
672     {
673       dprint (3, (debugfile, "Getting mailbox UIDVALIDITY\n"));
674       pc += 3;
675       pc = imap_next_word (pc);
676       idata->uid_validity = strtol (pc, NULL, 10);
677       status->uidvalidity = idata->uid_validity;
678     }
679     else if (ascii_strncasecmp ("OK [UIDNEXT", pc, 11) == 0)
680     {
681       dprint (3, (debugfile, "Getting mailbox UIDNEXT\n"));
682       pc += 3;
683       pc = imap_next_word (pc);
684       idata->uidnext = strtol (pc, NULL, 10);
685       status->uidnext = idata->uidnext;
686     }
687     else
688     {
689       pc = imap_next_word (pc);
690       if (!ascii_strncasecmp ("EXISTS", pc, 6))
691       {
692         count = idata->newMailCount;
693         idata->newMailCount = 0;
694       }
695     }
696   }
697   while (rc == IMAP_CMD_CONTINUE);
698
699   if (rc == IMAP_CMD_NO)
700   {
701     char *s;
702     s = imap_next_word (idata->buf); /* skip seq */
703     s = imap_next_word (s); /* Skip response */
704     mutt_error ("%s", s);
705     mutt_sleep (2);
706     goto fail;
707   }
708
709   if (rc != IMAP_CMD_OK)
710     goto fail;
711
712   /* check for READ-ONLY notification */
713   if (!ascii_strncasecmp (imap_get_qualifier (idata->buf), "[READ-ONLY]", 11)  \
714   && !mutt_bit_isset (idata->capabilities, ACL))
715   {
716     dprint (2, (debugfile, "Mailbox is read-only.\n"));
717     ctx->readonly = 1;
718   }
719
720 #ifdef DEBUG
721   /* dump the mailbox flags we've found */
722   if (debuglevel > 2)
723   {
724     if (!idata->flags)
725       dprint (3, (debugfile, "No folder flags found\n"));
726     else
727     {
728       LIST* t = idata->flags;
729
730       dprint (3, (debugfile, "Mailbox flags: "));
731
732       t = t->next;
733       while (t)
734       {
735         dprint (3, (debugfile, "[%s] ", t->data));
736         t = t->next;
737       }
738       dprint (3, (debugfile, "\n"));
739     }
740   }
741 #endif
742
743   if (!(mutt_bit_isset(idata->ctx->rights, M_ACL_DELETE) ||
744         mutt_bit_isset(idata->ctx->rights, M_ACL_SEEN) ||
745         mutt_bit_isset(idata->ctx->rights, M_ACL_WRITE) ||
746         mutt_bit_isset(idata->ctx->rights, M_ACL_INSERT)))
747      ctx->readonly = 1;
748
749   ctx->hdrmax = count;
750   ctx->hdrs = safe_calloc (count, sizeof (HEADER *));
751   ctx->v2r = safe_calloc (count, sizeof (int));
752   ctx->msgcount = 0;
753
754   if (count && (imap_read_headers (idata, 0, count-1) < 0))
755   {
756     mutt_error _("Error opening mailbox");
757     mutt_sleep (1);
758     goto fail;
759   }
760
761   dprint (2, (debugfile, "imap_open_mailbox: msgcount is %d\n", ctx->msgcount));
762   FREE (&mx.mbox);
763   return 0;
764
765  fail:
766   if (idata->state == IMAP_SELECTED)
767     idata->state = IMAP_AUTHENTICATED;
768  fail_noidata:
769   FREE (&mx.mbox);
770   return -1;
771 }
772
773 int imap_open_mailbox_append (CONTEXT *ctx)
774 {
775   CONNECTION *conn;
776   IMAP_DATA *idata;
777   char buf[LONG_STRING];
778   char mailbox[LONG_STRING];
779   IMAP_MBOX mx;
780   int rc;
781
782   if (imap_parse_path (ctx->path, &mx))
783     return -1;
784
785   /* in APPEND mode, we appear to hijack an existing IMAP connection -
786    * ctx is brand new and mostly empty */
787
788   if (!(idata = imap_conn_find (&(mx.account), 0)))
789   {
790     FREE (&mx.mbox);
791     return -1;
792   }
793
794   conn = idata->conn;
795
796   ctx->magic = M_IMAP;
797   ctx->data = idata;
798
799   imap_fix_path (idata, mx.mbox, mailbox, sizeof (mailbox));
800   if (!*mailbox)
801     strfcpy (mailbox, "INBOX", sizeof (mailbox));
802   FREE (&mx.mbox);
803
804   /* really we should also check for W_OK */
805   if ((rc = imap_access (ctx->path, F_OK)) == 0)
806     return 0;
807
808   if (rc == -1)
809     return -1;
810
811   snprintf (buf, sizeof (buf), _("Create %s?"), mailbox);
812   if (option (OPTCONFIRMCREATE) && mutt_yesorno (buf, 1) < 1)
813     return -1;
814
815   if (imap_create_mailbox (idata, mailbox) < 0)
816     return -1;
817
818   return 0;
819 }
820
821 /* imap_logout: Gracefully log out of server. */
822 void imap_logout (IMAP_DATA** idata)
823 {
824   /* we set status here to let imap_handle_untagged know we _expect_ to
825    * receive a bye response (so it doesn't freak out and close the conn) */
826   (*idata)->status = IMAP_BYE;
827   imap_cmd_start (*idata, "LOGOUT");
828   while (imap_cmd_step (*idata) == IMAP_CMD_CONTINUE)
829     ;
830
831   imap_free_idata (idata);
832 }
833
834 /* imap_set_flag: append str to flags if we currently have permission
835  *   according to aclbit */
836 static void imap_set_flag (IMAP_DATA* idata, int aclbit, int flag,
837   const char *str, char *flags, size_t flsize)
838 {
839   if (mutt_bit_isset (idata->ctx->rights, aclbit))
840     if (flag && imap_has_flag (idata->flags, str))
841       safe_strcat (flags, flsize, str);
842 }
843
844 /* imap_has_flag: do a caseless comparison of the flag against a flag list,
845 *   return 1 if found or flag list has '\*', 0 otherwise */
846 int imap_has_flag (LIST* flag_list, const char* flag)
847 {
848   if (!flag_list)
849     return 0;
850   
851   flag_list = flag_list->next;
852   while (flag_list)
853   {
854     if (!ascii_strncasecmp (flag_list->data, flag, strlen (flag_list->data)))
855       return 1;
856     
857     if (!ascii_strncmp (flag_list->data, "\\*", strlen (flag_list->data)))
858       return 1;
859     
860     flag_list = flag_list->next;
861   }
862   
863   return 0;
864 }
865
866 /* Note: headers must be in SORT_ORDER. See imap_exec_msgset for args.
867  * Pos is an opaque pointer a la strtok. It should be 0 at first call. */
868 static int imap_make_msg_set (IMAP_DATA* idata, BUFFER* buf, int flag,
869                               int changed, int invert, int* pos)
870 {
871   HEADER** hdrs = idata->ctx->hdrs;
872   int count = 0;        /* number of messages in message set */
873   int match = 0;        /* whether current message matches flag condition */
874   unsigned int setstart = 0;    /* start of current message range */
875   int n;
876   int started = 0;
877
878   hdrs = idata->ctx->hdrs;
879   
880   for (n = *pos;
881        n < idata->ctx->msgcount && buf->dptr - buf->data < IMAP_MAX_CMDLEN;
882        n++)
883   {
884     match = 0;
885     /* don't include pending expunged messages */
886     if (hdrs[n]->active)
887       switch (flag)
888       {
889         case M_DELETED:
890           if (hdrs[n]->deleted != HEADER_DATA(hdrs[n])->deleted)
891             match = invert ^ hdrs[n]->deleted;
892           break;
893         case M_FLAG:
894           if (hdrs[n]->flagged != HEADER_DATA(hdrs[n])->flagged)
895             match = invert ^ hdrs[n]->flagged;
896           break;
897         case M_OLD:
898           if (hdrs[n]->old != HEADER_DATA(hdrs[n])->old)
899             match = invert ^ hdrs[n]->old;
900           break;
901         case M_READ:
902           if (hdrs[n]->read != HEADER_DATA(hdrs[n])->read)
903             match = invert ^ hdrs[n]->read;
904           break;
905         case M_REPLIED:
906           if (hdrs[n]->replied != HEADER_DATA(hdrs[n])->replied)
907             match = invert ^ hdrs[n]->replied;
908           break;
909
910         case M_TAG:
911           if (hdrs[n]->tagged)
912             match = 1;
913           break;
914       }
915
916     if (match && (!changed || hdrs[n]->changed))
917     {
918       count++;
919       if (setstart == 0)
920       {
921         setstart = HEADER_DATA (hdrs[n])->uid;
922         if (started == 0)
923         {
924           mutt_buffer_printf (buf, "%u", HEADER_DATA (hdrs[n])->uid);
925           started = 1;
926         }
927         else
928           mutt_buffer_printf (buf, ",%u", HEADER_DATA (hdrs[n])->uid);
929       }
930       /* tie up if the last message also matches */
931       else if (n == idata->ctx->msgcount-1)
932         mutt_buffer_printf (buf, ":%u", HEADER_DATA (hdrs[n])->uid);
933     }
934     /* End current set if message doesn't match or we've reached the end
935      * of the mailbox via inactive messages following the last match. */
936     else if (setstart && (hdrs[n]->active || n == idata->ctx->msgcount-1))
937     {
938       if (HEADER_DATA (hdrs[n-1])->uid > setstart)
939         mutt_buffer_printf (buf, ":%u", HEADER_DATA (hdrs[n-1])->uid);
940       setstart = 0;
941     }
942   }
943
944   *pos = n;
945
946   return count;
947 }
948
949 /* Prepares commands for all messages matching conditions (must be flushed
950  * with imap_exec)
951  * Params:
952  *   idata: IMAP_DATA containing context containing header set
953  *   pre, post: commands are of the form "%s %s %s %s", tag,
954  *     pre, message set, post
955  *   flag: enum of flag type on which to filter
956  *   changed: include only changed messages in message set
957  *   invert: invert sense of flag, eg M_READ matches unread messages
958  * Returns: number of matched messages, or -1 on failure */
959 int imap_exec_msgset (IMAP_DATA* idata, const char* pre, const char* post,
960                       int flag, int changed, int invert)
961 {
962   HEADER** hdrs = NULL;
963   short oldsort;
964   BUFFER* cmd;
965   int pos;
966   int rc;
967   int count = 0;
968
969   if (! (cmd = mutt_buffer_init (NULL)))
970   {
971     dprint (1, (debugfile, "imap_exec_msgset: unable to allocate buffer\n"));
972     return -1;
973   }
974
975   /* We make a copy of the headers just in case resorting doesn't give
976    exactly the original order (duplicate messages?), because other parts of
977    the ctx are tied to the header order. This may be overkill. */
978   oldsort = Sort;
979   if (Sort != SORT_ORDER)
980   {
981     hdrs = idata->ctx->hdrs;
982     idata->ctx->hdrs = safe_malloc (idata->ctx->msgcount * sizeof (HEADER*));
983     memcpy (idata->ctx->hdrs, hdrs, idata->ctx->msgcount * sizeof (HEADER*));
984
985     Sort = SORT_ORDER;
986     qsort (idata->ctx->hdrs, idata->ctx->msgcount, sizeof (HEADER*),
987            mutt_get_sort_func (SORT_ORDER));
988   }
989
990   pos = 0;
991
992   do
993   {
994     cmd->dptr = cmd->data;
995     mutt_buffer_printf (cmd, "%s ", pre);
996     rc = imap_make_msg_set (idata, cmd, flag, changed, invert, &pos);
997     if (rc > 0)
998     {
999       mutt_buffer_printf (cmd, " %s", post);
1000       if (imap_exec (idata, cmd->data, IMAP_CMD_QUEUE))
1001       {
1002         rc = -1;
1003         goto out;
1004       }
1005       count += rc;
1006     }
1007   }
1008   while (rc > 0);
1009   
1010   rc = count;
1011
1012 out:
1013   mutt_buffer_free (&cmd);
1014   if (oldsort != Sort)
1015   {
1016     Sort = oldsort;
1017     FREE (&idata->ctx->hdrs);
1018     idata->ctx->hdrs = hdrs;
1019   }
1020
1021   return rc;
1022 }
1023
1024 /* returns 0 if mutt's flags match cached server flags */
1025 static int compare_flags (HEADER* h)
1026 {
1027   IMAP_HEADER_DATA* hd = (IMAP_HEADER_DATA*)h->data;
1028
1029   if (h->read != hd->read)
1030     return 1;
1031   if (h->old != hd->old)
1032     return 1;
1033   if (h->flagged != hd->flagged)
1034     return 1;
1035   if (h->replied != hd->replied)
1036     return 1;
1037   if (h->deleted != hd->deleted)
1038     return 1;
1039
1040   return 0;
1041 }
1042
1043 /* Update the IMAP server to reflect the flags a single message.  */
1044 int imap_sync_message (IMAP_DATA *idata, HEADER *hdr, BUFFER *cmd,
1045                        int *err_continue)
1046 {
1047   char flags[LONG_STRING];
1048   char uid[11];
1049
1050   hdr->changed = 0;
1051
1052   if (!compare_flags (hdr))
1053   {
1054     idata->ctx->changed--;
1055     return 0;
1056   }
1057
1058   snprintf (uid, sizeof (uid), "%u", HEADER_DATA(hdr)->uid);
1059   cmd->dptr = cmd->data;
1060   mutt_buffer_addstr (cmd, "UID STORE ");
1061   mutt_buffer_addstr (cmd, uid);
1062
1063   flags[0] = '\0';
1064       
1065   imap_set_flag (idata, M_ACL_SEEN, hdr->read, "\\Seen ",
1066                  flags, sizeof (flags));
1067   imap_set_flag (idata, M_ACL_WRITE, hdr->old,
1068                  "Old ", flags, sizeof (flags));
1069   imap_set_flag (idata, M_ACL_WRITE, hdr->flagged,
1070                  "\\Flagged ", flags, sizeof (flags));
1071   imap_set_flag (idata, M_ACL_WRITE, hdr->replied,
1072                  "\\Answered ", flags, sizeof (flags));
1073   imap_set_flag (idata, M_ACL_DELETE, hdr->deleted,
1074                  "\\Deleted ", flags, sizeof (flags));
1075
1076   /* now make sure we don't lose custom tags */
1077   if (mutt_bit_isset (idata->ctx->rights, M_ACL_WRITE))
1078     imap_add_keywords (flags, hdr, idata->flags, sizeof (flags));
1079
1080   mutt_remove_trailing_ws (flags);
1081
1082   /* UW-IMAP is OK with null flags, Cyrus isn't. The only solution is to
1083    * explicitly revoke all system flags (if we have permission) */
1084   if (!*flags)
1085   {
1086     imap_set_flag (idata, M_ACL_SEEN, 1, "\\Seen ", flags, sizeof (flags));
1087     imap_set_flag (idata, M_ACL_WRITE, 1, "Old ", flags, sizeof (flags));
1088     imap_set_flag (idata, M_ACL_WRITE, 1, "\\Flagged ", flags, sizeof (flags));
1089     imap_set_flag (idata, M_ACL_WRITE, 1, "\\Answered ", flags, sizeof (flags));
1090     imap_set_flag (idata, M_ACL_DELETE, 1, "\\Deleted ", flags, sizeof (flags));
1091
1092     mutt_remove_trailing_ws (flags);
1093
1094     mutt_buffer_addstr (cmd, " -FLAGS.SILENT (");
1095   } else
1096     mutt_buffer_addstr (cmd, " FLAGS.SILENT (");
1097
1098   mutt_buffer_addstr (cmd, flags);
1099   mutt_buffer_addstr (cmd, ")");
1100
1101   /* dumb hack for bad UW-IMAP 4.7 servers spurious FLAGS updates */
1102   hdr->active = 0;
1103
1104   /* after all this it's still possible to have no flags, if you
1105    * have no ACL rights */
1106   if (*flags && (imap_exec (idata, cmd->data, 0) != 0) &&
1107       err_continue && (*err_continue != M_YES))
1108   {
1109     *err_continue = imap_continue ("imap_sync_message: STORE failed",
1110                                    idata->buf);
1111     if (*err_continue != M_YES)
1112       return -1;
1113   }
1114
1115   hdr->active = 1;
1116   idata->ctx->changed--;
1117
1118   return 0;
1119 }
1120
1121 static int sync_helper (IMAP_DATA* idata, int right, int flag, const char* name)
1122 {
1123   int count = 0;
1124   int rc;
1125
1126   char buf[LONG_STRING];
1127
1128   if (!mutt_bit_isset (idata->ctx->rights, right))
1129     return 0;
1130
1131   if (right == M_ACL_WRITE && !imap_has_flag (idata->flags, name))
1132     return 0;
1133
1134   snprintf (buf, sizeof(buf), "+FLAGS.SILENT (%s)", name);
1135   if ((rc = imap_exec_msgset (idata, "UID STORE", buf, flag, 1, 0)) < 0)
1136     return rc;
1137   count += rc;
1138
1139   buf[0] = '-';
1140   if ((rc = imap_exec_msgset (idata, "UID STORE", buf, flag, 1, 1)) < 0)
1141     return rc;
1142   count += rc;
1143
1144   return count;
1145 }
1146
1147 /* update the IMAP server to reflect message changes done within mutt.
1148  * Arguments
1149  *   ctx: the current context
1150  *   expunge: 0 or 1 - do expunge? 
1151  */
1152 int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint)
1153 {
1154   IMAP_DATA* idata;
1155   CONTEXT* appendctx = NULL;
1156   HEADER* h;
1157   HEADER** hdrs = NULL;
1158   int oldsort;
1159   int n;
1160   int rc;
1161   
1162   idata = (IMAP_DATA*) ctx->data;
1163
1164   if (idata->state < IMAP_SELECTED)
1165   {
1166     dprint (2, (debugfile, "imap_sync_mailbox: no mailbox selected\n"));
1167     return -1;
1168   }
1169
1170   /* This function is only called when the calling code expects the context
1171    * to be changed. */
1172   imap_allow_reopen (ctx);
1173
1174   if ((rc = imap_check_mailbox (ctx, index_hint, 0)) != 0)
1175     return rc;
1176
1177   /* if we are expunging anyway, we can do deleted messages very quickly... */
1178   if (expunge && mutt_bit_isset (idata->ctx->rights, M_ACL_DELETE))
1179   {
1180     if ((rc = imap_exec_msgset (idata, "UID STORE", "+FLAGS.SILENT (\\Deleted)",
1181                                 M_DELETED, 1, 0)) < 0)
1182     {
1183       mutt_error (_("Expunge failed"));
1184       mutt_sleep (1);
1185       goto out;
1186     }
1187
1188     if (rc > 0)
1189     {
1190       /* mark these messages as unchanged so second pass ignores them. Done
1191        * here so BOGUS UW-IMAP 4.7 SILENT FLAGS updates are ignored. */
1192       for (n = 0; n < ctx->msgcount; n++)
1193         if (ctx->hdrs[n]->deleted && ctx->hdrs[n]->changed)
1194           ctx->hdrs[n]->active = 0;
1195       mutt_message (_("Marking %d messages deleted..."), rc);
1196     }
1197   }
1198
1199 #if USE_HCACHE
1200   idata->hcache = imap_hcache_open (idata, NULL);
1201 #endif
1202
1203   /* save messages with real (non-flag) changes */
1204   for (n = 0; n < ctx->msgcount; n++)
1205   {
1206     h = ctx->hdrs[n];
1207
1208     if (h->deleted)
1209     {
1210       imap_cache_del (idata, h);
1211 #if USE_HCACHE
1212       imap_hcache_del (idata, HEADER_DATA(h)->uid);
1213 #endif
1214     }
1215     
1216     if (h->active && h->changed)
1217     {
1218       /* if the message has been rethreaded or attachments have been deleted
1219        * we delete the message and reupload it.
1220        * This works better if we're expunging, of course. */
1221       if ((h->env && (h->env->refs_changed || h->env->irt_changed)) ||
1222           h->attach_del)
1223       {
1224         mutt_message (_("Saving changed messages... [%d/%d]"), n+1,
1225                       ctx->msgcount);
1226         if (!appendctx)
1227           appendctx = mx_open_mailbox (ctx->path, M_APPEND | M_QUIET, NULL);
1228         if (!appendctx)
1229           dprint (1, (debugfile, "imap_sync_mailbox: Error opening mailbox in append mode\n"));
1230         else
1231           _mutt_save_message (h, appendctx, 1, 0, 0);
1232       }
1233     }
1234   }
1235
1236 #if USE_HCACHE
1237   imap_hcache_close (idata);
1238 #endif
1239
1240   /* sync +/- flags for the five flags mutt cares about */
1241   rc = 0;
1242
1243   /* presort here to avoid doing 10 resorts in imap_exec_msgset */
1244   oldsort = Sort;
1245   if (Sort != SORT_ORDER)
1246   {
1247     hdrs = ctx->hdrs;
1248     ctx->hdrs = safe_malloc (ctx->msgcount * sizeof (HEADER*));
1249     memcpy (ctx->hdrs, hdrs, ctx->msgcount * sizeof (HEADER*));
1250
1251     Sort = SORT_ORDER;
1252     qsort (ctx->hdrs, ctx->msgcount, sizeof (HEADER*),
1253            mutt_get_sort_func (SORT_ORDER));
1254   }
1255
1256   rc += sync_helper (idata, M_ACL_DELETE, M_DELETED, "\\Deleted");
1257   rc += sync_helper (idata, M_ACL_WRITE, M_FLAG, "\\Flagged");
1258   rc += sync_helper (idata, M_ACL_WRITE, M_OLD, "Old");
1259   rc += sync_helper (idata, M_ACL_SEEN, M_READ, "\\Seen");
1260   rc += sync_helper (idata, M_ACL_WRITE, M_REPLIED, "\\Answered");
1261
1262   if (oldsort != Sort)
1263   {
1264     Sort = oldsort;
1265     FREE (&ctx->hdrs);
1266     ctx->hdrs = hdrs;
1267   }
1268
1269   if (rc && (imap_exec (idata, NULL, 0) != IMAP_CMD_OK))
1270   {
1271     if (ctx->closing)
1272     {
1273       if (mutt_yesorno (_("Error saving flags. Close anyway?"), 0) == M_YES)
1274       {
1275         rc = 0;
1276         idata->state = IMAP_AUTHENTICATED;
1277         goto out;
1278       }
1279     }
1280     else
1281       mutt_error _("Error saving flags");
1282     goto out;
1283   }
1284
1285   for (n = 0; n < ctx->msgcount; n++)
1286     ctx->hdrs[n]->changed = 0;
1287   ctx->changed = 0;
1288
1289   /* We must send an EXPUNGE command if we're not closing. */
1290   if (expunge && !(ctx->closing) &&
1291       mutt_bit_isset(idata->ctx->rights, M_ACL_DELETE))
1292   {
1293     mutt_message _("Expunging messages from server...");
1294     /* Set expunge bit so we don't get spurious reopened messages */
1295     idata->reopen |= IMAP_EXPUNGE_EXPECTED;
1296     if (imap_exec (idata, "EXPUNGE", 0) != 0)
1297     {
1298       imap_error (_("imap_sync_mailbox: EXPUNGE failed"), idata->buf);
1299       rc = -1;
1300       goto out;
1301     }
1302   }
1303
1304   if (expunge && ctx->closing)
1305   {
1306     imap_exec (idata, "CLOSE", IMAP_CMD_QUEUE);
1307     idata->state = IMAP_AUTHENTICATED;
1308   }
1309
1310   if (option (OPTMESSAGECACHECLEAN))
1311     imap_cache_clean (idata);
1312
1313   rc = 0;
1314
1315  out:
1316   if (appendctx)
1317   {
1318     mx_fastclose_mailbox (appendctx);
1319     FREE (&appendctx);
1320   }
1321   return rc;
1322 }
1323
1324 /* imap_close_mailbox: clean up IMAP data in CONTEXT */
1325 int imap_close_mailbox (CONTEXT* ctx)
1326 {
1327   IMAP_DATA* idata;
1328   int i;
1329
1330   idata = (IMAP_DATA*) ctx->data;
1331   /* Check to see if the mailbox is actually open */
1332   if (!idata)
1333     return 0;
1334
1335   if (ctx == idata->ctx)
1336   {
1337     if (idata->status != IMAP_FATAL && idata->state >= IMAP_SELECTED)
1338     {
1339       /* mx_close_mailbox won't sync if there are no deleted messages
1340        * and the mailbox is unchanged, so we may have to close here */
1341       if (!ctx->deleted)
1342         imap_exec (idata, "CLOSE", IMAP_CMD_QUEUE);
1343       idata->state = IMAP_AUTHENTICATED;
1344     }
1345
1346     idata->reopen &= IMAP_REOPEN_ALLOW;
1347     FREE (&(idata->mailbox));
1348     mutt_free_list (&idata->flags);
1349     idata->ctx = NULL;
1350   }
1351
1352   /* free IMAP part of headers */
1353   for (i = 0; i < ctx->msgcount; i++)
1354     /* mailbox may not have fully loaded */
1355     if (ctx->hdrs[i] && ctx->hdrs[i]->data)
1356       imap_free_header_data (&(ctx->hdrs[i]->data));
1357
1358   for (i = 0; i < IMAP_CACHE_LEN; i++)
1359   {
1360     if (idata->cache[i].path)
1361     {
1362       unlink (idata->cache[i].path);
1363       FREE (&idata->cache[i].path);
1364     }
1365   }
1366
1367   mutt_bcache_close (&idata->bcache);
1368
1369   return 0;
1370 }
1371
1372 /* use the NOOP or IDLE command to poll for new mail
1373  *
1374  * return values:
1375  *      M_REOPENED      mailbox has been externally modified
1376  *      M_NEW_MAIL      new mail has arrived!
1377  *      0               no change
1378  *      -1              error
1379  */
1380 int imap_check_mailbox (CONTEXT *ctx, int *index_hint, int force)
1381 {
1382   /* overload keyboard timeout to avoid many mailbox checks in a row.
1383    * Most users don't like having to wait exactly when they press a key. */
1384   IMAP_DATA* idata;
1385   int result = 0;
1386
1387   idata = (IMAP_DATA*) ctx->data;
1388
1389   /* try IDLE first, unless force is set */
1390   if (!force && option (OPTIMAPIDLE) && mutt_bit_isset (idata->capabilities, IDLE)
1391       && (idata->state != IMAP_IDLE || time(NULL) >= idata->lastread + ImapKeepalive))
1392   {
1393     if (imap_cmd_idle (idata) < 0)
1394       return -1;
1395   }
1396   if (idata->state == IMAP_IDLE)
1397   {
1398     while ((result = mutt_socket_poll (idata->conn)) > 0)
1399     {
1400       if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE)
1401       {
1402         dprint (1, (debugfile, "Error reading IDLE response\n"));
1403         return -1;
1404       }
1405     }
1406     if (result < 0)
1407     {
1408       dprint (1, (debugfile, "Poll failed, disabling IDLE\n"));
1409       mutt_bit_unset (idata->capabilities, IDLE);
1410     }
1411   }
1412
1413   if ((force || 
1414        (idata->state != IMAP_IDLE && time(NULL) >= idata->lastread + Timeout))
1415       && imap_exec (idata, "NOOP", 0) != 0)
1416     return -1;
1417
1418   /* We call this even when we haven't run NOOP in case we have pending
1419    * changes to process, since we can reopen here. */
1420   imap_cmd_finish (idata);
1421
1422   if (idata->check_status & IMAP_EXPUNGE_PENDING)
1423     result = M_REOPENED;
1424   else if (idata->check_status & IMAP_NEWMAIL_PENDING)
1425     result = M_NEW_MAIL;
1426   else if (idata->check_status & IMAP_FLAGS_PENDING)
1427     result = M_FLAGS;
1428
1429   idata->check_status = 0;
1430
1431   return result;
1432 }
1433
1434 /* split path into (idata,mailbox name) */
1435 static int imap_get_mailbox (const char* path, IMAP_DATA** hidata, char* buf, size_t blen)
1436 {
1437   IMAP_MBOX mx;
1438
1439   if (imap_parse_path (path, &mx))
1440   {
1441     dprint (1, (debugfile, "imap_get_mailbox: Error parsing %s\n", path));
1442     return -1;
1443   }
1444   if (!(*hidata = imap_conn_find (&(mx.account), option (OPTIMAPPASSIVE) ? M_IMAP_CONN_NONEW : 0))
1445       || (*hidata)->state < IMAP_AUTHENTICATED)
1446   {
1447     FREE (&mx.mbox);
1448     return -1;
1449   }
1450   
1451   imap_fix_path (*hidata, mx.mbox, buf, blen);
1452   if (!*buf)
1453     strfcpy (buf, "INBOX", blen);
1454   FREE (&mx.mbox);
1455
1456   return 0;
1457 }
1458
1459 /* check for new mail in any subscribed mailboxes. Given a list of mailboxes
1460  * rather than called once for each so that it can batch the commands and
1461  * save on round trips. Returns number of mailboxes with new mail. */
1462 int imap_buffy_check (int force)
1463 {
1464   IMAP_DATA* idata;
1465   IMAP_DATA* lastdata = NULL;
1466   BUFFY* mailbox;
1467   char name[LONG_STRING];
1468   char command[LONG_STRING];
1469   char munged[LONG_STRING];
1470   int buffies = 0;
1471
1472   for (mailbox = Incoming; mailbox; mailbox = mailbox->next)
1473   {
1474     /* Init newly-added mailboxes */
1475     if (! mailbox->magic)
1476     {
1477       if (mx_is_imap (mailbox->path))
1478         mailbox->magic = M_IMAP;
1479     }
1480     
1481     if (mailbox->magic != M_IMAP)
1482       continue;
1483
1484     mailbox->new = 0;
1485
1486     if (imap_get_mailbox (mailbox->path, &idata, name, sizeof (name)) < 0)
1487       continue;
1488
1489     /* Don't issue STATUS on the selected mailbox, it will be NOOPed or
1490      * IDLEd elsewhere */
1491     if (!imap_mxcmp (name, idata->mailbox))
1492       continue;
1493
1494     if (!mutt_bit_isset (idata->capabilities, IMAP4REV1) &&
1495         !mutt_bit_isset (idata->capabilities, STATUS))
1496     {
1497       dprint (2, (debugfile, "Server doesn't support STATUS\n"));
1498       continue;
1499     }
1500
1501     if (lastdata && idata != lastdata)
1502     {
1503       /* Send commands to previous server. Sorting the buffy list
1504        * may prevent some infelicitous interleavings */
1505       if (imap_exec (lastdata, NULL, IMAP_CMD_FAIL_OK) == -1)
1506         dprint (1, (debugfile, "Error polling mailboxes\n"));
1507
1508       lastdata = NULL;
1509     }
1510
1511     if (!lastdata)
1512       lastdata = idata;
1513
1514     imap_munge_mbox_name (munged, sizeof (munged), name);
1515     snprintf (command, sizeof (command),
1516               "STATUS %s (UIDNEXT UIDVALIDITY UNSEEN RECENT)", munged);
1517
1518     if (imap_exec (idata, command, IMAP_CMD_QUEUE) < 0)
1519     {
1520       dprint (1, (debugfile, "Error queueing command\n"));
1521       return 0;
1522     }
1523   }
1524
1525   if (lastdata && (imap_exec (lastdata, NULL, IMAP_CMD_FAIL_OK) == -1))
1526   {
1527     dprint (1, (debugfile, "Error polling mailboxes\n"));
1528     return 0;
1529   }
1530
1531   /* collect results */
1532   for (mailbox = Incoming; mailbox; mailbox = mailbox->next)
1533   {
1534     if (mailbox->magic == M_IMAP && mailbox->new)
1535       buffies++;
1536   }
1537
1538   return buffies;
1539 }
1540
1541 /* imap_status: returns count of messages in mailbox, or -1 on error.
1542  * if queue != 0, queue the command and expect it to have been run
1543  * on the next call (for pipelining the postponed count) */
1544 int imap_status (char* path, int queue)
1545 {
1546   static int queued = 0;
1547
1548   IMAP_DATA *idata;
1549   char buf[LONG_STRING];
1550   char mbox[LONG_STRING];
1551   IMAP_STATUS* status;
1552
1553   if (imap_get_mailbox (path, &idata, buf, sizeof (buf)) < 0)
1554     return -1;
1555
1556   if (!imap_mxcmp (buf, idata->mailbox))
1557     /* We are in the folder we're polling - just return the mailbox count */
1558     return idata->ctx->msgcount;
1559   else if (mutt_bit_isset(idata->capabilities,IMAP4REV1) ||
1560            mutt_bit_isset(idata->capabilities,STATUS))
1561   {
1562     imap_munge_mbox_name (mbox, sizeof(mbox), buf);
1563     snprintf (buf, sizeof (buf), "STATUS %s (%s)", mbox, "MESSAGES");
1564     imap_unmunge_mbox_name (mbox);
1565   }
1566   else
1567     /* Server does not support STATUS, and this is not the current mailbox.
1568      * There is no lightweight way to check recent arrivals */
1569     return -1;
1570
1571   if (queue)
1572   {
1573     imap_exec (idata, buf, IMAP_CMD_QUEUE);
1574     queued = 1;
1575     return 0;
1576   }
1577   else if (!queued)
1578     imap_exec (idata, buf, 0);
1579
1580   queued = 0;
1581   if ((status = imap_mboxcache_get (idata, mbox, 0)))
1582     return status->messages;
1583   
1584   return 0;
1585 }
1586
1587 /* return cached mailbox stats or NULL if create is 0 */
1588 IMAP_STATUS* imap_mboxcache_get (IMAP_DATA* idata, const char* mbox, int create)
1589 {
1590   LIST* cur;
1591   IMAP_STATUS* status;
1592   IMAP_STATUS scache;
1593 #ifdef USE_HCACHE
1594   header_cache_t *hc = NULL;
1595   unsigned int *uidvalidity = NULL;
1596   unsigned int *uidnext = NULL;
1597 #endif
1598   
1599   for (cur = idata->mboxcache; cur; cur = cur->next)
1600   {
1601     status = (IMAP_STATUS*)cur->data;
1602
1603     if (!imap_mxcmp (mbox, status->name))
1604       return status;
1605   }
1606   status = NULL;
1607
1608   /* lame */
1609   if (create)
1610   {
1611     memset (&scache, 0, sizeof (scache));
1612     scache.name = (char*)mbox;
1613     idata->mboxcache = mutt_add_list_n (idata->mboxcache, &scache,
1614                                         sizeof (scache));
1615     status = imap_mboxcache_get (idata, mbox, 0);
1616     status->name = safe_strdup (mbox);
1617   }
1618
1619 #ifdef USE_HCACHE
1620   hc = imap_hcache_open (idata, mbox);
1621   if (hc)
1622   {
1623     uidvalidity = mutt_hcache_fetch_raw (hc, "/UIDVALIDITY", imap_hcache_keylen);
1624     uidnext = mutt_hcache_fetch_raw (hc, "/UIDNEXT", imap_hcache_keylen);
1625     mutt_hcache_close (hc);
1626     if (uidvalidity)
1627     {
1628       if (!status)
1629       {
1630         FREE (&uidvalidity);
1631         FREE (&uidnext);
1632         return imap_mboxcache_get (idata, mbox, 1);
1633       }
1634       status->uidvalidity = *uidvalidity;
1635       status->uidnext = uidnext ? *uidnext: 0;
1636       dprint (3, (debugfile, "mboxcache: hcache uidvalidity %d, uidnext %d\n",
1637                   status->uidvalidity, status->uidnext));
1638     }
1639     FREE (&uidvalidity);
1640     FREE (&uidnext);
1641   }
1642 #endif
1643
1644   return status;
1645 }
1646
1647 void imap_mboxcache_free (IMAP_DATA* idata)
1648 {
1649   LIST* cur;
1650   IMAP_STATUS* status;
1651
1652   for (cur = idata->mboxcache; cur; cur = cur->next)
1653   {
1654     status = (IMAP_STATUS*)cur->data;
1655
1656     FREE (&status->name);
1657   }
1658
1659   mutt_free_list (&idata->mboxcache);
1660 }
1661
1662 /* returns number of patterns in the search that should be done server-side
1663  * (eg are full-text) */
1664 static int do_search (const pattern_t* search, int allpats)
1665 {
1666   int rc = 0;
1667   const pattern_t* pat;
1668
1669   for (pat = search; pat; pat = pat->next)
1670   {
1671     switch (pat->op)
1672     {
1673       case M_BODY:
1674       case M_HEADER:
1675       case M_WHOLE_MSG:
1676         if (pat->stringmatch)
1677           rc++;
1678         break;
1679       default:
1680         if (pat->child && do_search (pat->child, 1))
1681           rc++;
1682     }
1683     
1684     if (!allpats)
1685       break;
1686   }
1687   
1688   return rc;
1689 }
1690
1691 /* convert mutt pattern_t to IMAP SEARCH command containing only elements
1692  * that require full-text search (mutt already has what it needs for most
1693  * match types, and does a better job (eg server doesn't support regexps). */
1694 static int imap_compile_search (const pattern_t* pat, BUFFER* buf)
1695 {
1696   if (! do_search (pat, 0))
1697     return 0;
1698
1699   if (pat->not)
1700     mutt_buffer_addstr (buf, "NOT ");
1701
1702   if (pat->child)
1703   {
1704     int clauses;
1705
1706     if ((clauses = do_search (pat->child, 1)) > 0)
1707     {
1708       const pattern_t* clause = pat->child;
1709
1710       mutt_buffer_addch (buf, '(');
1711
1712       while (clauses)
1713       {
1714         if (do_search (clause, 0))
1715         {
1716           if (pat->op == M_OR && clauses > 1)
1717             mutt_buffer_addstr (buf, "OR ");
1718           clauses--;
1719           
1720           if (imap_compile_search (clause, buf) < 0)
1721             return -1;
1722
1723           if (clauses)
1724             mutt_buffer_addch (buf, ' ');
1725           
1726         }
1727         clause = clause->next;
1728       }
1729
1730       mutt_buffer_addch (buf, ')');
1731     }
1732   }
1733   else
1734   {
1735     char term[STRING];
1736     char *delim;
1737
1738     switch (pat->op)
1739     {
1740       case M_HEADER:
1741         mutt_buffer_addstr (buf, "HEADER ");
1742
1743         /* extract header name */
1744         if (! (delim = strchr (pat->p.str, ':')))
1745         {
1746           mutt_error (_("Header search without header name: %s"), pat->p.str);
1747           return -1;
1748         }
1749         *delim = '\0';
1750         imap_quote_string (term, sizeof (term), pat->p.str);
1751         mutt_buffer_addstr (buf, term);
1752         mutt_buffer_addch (buf, ' ');
1753         
1754         /* and field */
1755         *delim = ':';
1756         delim++;
1757         SKIPWS(delim);
1758         imap_quote_string (term, sizeof (term), delim);
1759         mutt_buffer_addstr (buf, term);
1760         break;
1761       case M_BODY:
1762         mutt_buffer_addstr (buf, "BODY ");
1763         imap_quote_string (term, sizeof (term), pat->p.str);
1764         mutt_buffer_addstr (buf, term);
1765         break;
1766       case M_WHOLE_MSG:
1767         mutt_buffer_addstr (buf, "TEXT ");
1768         imap_quote_string (term, sizeof (term), pat->p.str);
1769         mutt_buffer_addstr (buf, term);
1770         break;
1771     }
1772   }
1773
1774   return 0;
1775 }
1776
1777 int imap_search (CONTEXT* ctx, const pattern_t* pat)
1778 {
1779   BUFFER buf;
1780   IMAP_DATA* idata = (IMAP_DATA*)ctx->data;
1781   int i;
1782
1783   for (i = 0; i < ctx->msgcount; i++)
1784     ctx->hdrs[i]->matched = 0;
1785
1786   if (!do_search (pat, 1))
1787     return 0;
1788
1789   memset (&buf, 0, sizeof (buf));
1790   mutt_buffer_addstr (&buf, "UID SEARCH ");
1791   if (imap_compile_search (pat, &buf) < 0)
1792   {
1793     FREE (&buf.data);
1794     return -1;
1795   }
1796   if (imap_exec (idata, buf.data, 0) < 0)
1797   {
1798     FREE (&buf.data);
1799     return -1;
1800   }
1801
1802   FREE (&buf.data);
1803   return 0;
1804 }
1805
1806 int imap_subscribe (char *path, int subscribe)
1807 {
1808   CONNECTION *conn;
1809   IMAP_DATA *idata;
1810   char buf[LONG_STRING];
1811   char mbox[LONG_STRING];
1812   char errstr[STRING];
1813   BUFFER err, token;
1814   IMAP_MBOX mx;
1815
1816   if (!mx_is_imap (path) || imap_parse_path (path, &mx) || !mx.mbox)
1817   {
1818     mutt_error (_("Bad mailbox name"));
1819     return -1;
1820   }
1821   if (!(idata = imap_conn_find (&(mx.account), 0)))
1822     goto fail;
1823   
1824   conn = idata->conn;
1825
1826   imap_fix_path (idata, mx.mbox, buf, sizeof (buf));
1827   if (!*buf)
1828     strfcpy (buf, "INBOX", sizeof (buf));
1829
1830   if (option (OPTIMAPCHECKSUBSCRIBED))
1831   {
1832     memset (&token, 0, sizeof (token));
1833     err.data = errstr;
1834     err.dsize = sizeof (errstr);
1835     snprintf (mbox, sizeof (mbox), "%smailboxes \"%s\"",
1836               subscribe ? "" : "un", path);
1837     if (mutt_parse_rc_line (mbox, &token, &err))
1838       dprint (1, (debugfile, "Error adding subscribed mailbox: %s\n", errstr));
1839     FREE (&token.data);
1840   }
1841   
1842   if (subscribe)
1843     mutt_message (_("Subscribing to %s..."), buf);
1844   else
1845     mutt_message (_("Unsubscribing from %s..."), buf);
1846   imap_munge_mbox_name (mbox, sizeof(mbox), buf);
1847
1848   snprintf (buf, sizeof (buf), "%sSUBSCRIBE %s", subscribe ? "" : "UN", mbox);
1849
1850   if (imap_exec (idata, buf, 0) < 0)
1851     goto fail;
1852
1853   imap_unmunge_mbox_name(mx.mbox);
1854   if (subscribe)
1855     mutt_message (_("Subscribed to %s"), mx.mbox);
1856   else
1857     mutt_message (_("Unsubscribed from %s"), mx.mbox);
1858   FREE (&mx.mbox);
1859   return 0;
1860
1861  fail:
1862   FREE (&mx.mbox);
1863   return -1;
1864 }
1865
1866 /* trim dest to the length of the longest prefix it shares with src,
1867  * returning the length of the trimmed string */
1868 static int
1869 longest_common_prefix (char *dest, const char* src, int start, size_t dlen)
1870 {
1871   int pos = start;
1872   
1873   while (pos < dlen && dest[pos] && dest[pos] == src[pos])
1874     pos++;
1875   dest[pos] = '\0';
1876
1877   return pos;
1878 }
1879
1880 /* look for IMAP URLs to complete from defined mailboxes. Could be extended
1881  * to complete over open connections and account/folder hooks too. */
1882 static int
1883 imap_complete_hosts (char *dest, size_t len)
1884 {
1885   BUFFY* mailbox;
1886   CONNECTION* conn;
1887   int rc = -1;
1888   int matchlen;
1889   
1890   matchlen = mutt_strlen (dest);
1891   for (mailbox = Incoming; mailbox; mailbox = mailbox->next)
1892   {
1893     if (!mutt_strncmp (dest, mailbox->path, matchlen))
1894     {
1895       if (rc)
1896       {
1897         strfcpy (dest, mailbox->path, len);
1898         rc = 0;
1899       }
1900       else
1901         longest_common_prefix (dest, mailbox->path, matchlen, len);
1902     }
1903   }
1904   
1905   for (conn = mutt_socket_head (); conn; conn = conn->next)
1906   {
1907     ciss_url_t url;
1908     char urlstr[LONG_STRING];
1909
1910     if (conn->account.type != M_ACCT_TYPE_IMAP)
1911       continue;
1912
1913     mutt_account_tourl (&conn->account, &url);
1914     /* FIXME: how to handle multiple users on the same host? */
1915     url.user = NULL;
1916     url.path = NULL;
1917     url_ciss_tostring (&url, urlstr, sizeof (urlstr), 0);
1918     if (!mutt_strncmp (dest, urlstr, matchlen))
1919     {
1920       if (rc)
1921       {
1922         strfcpy (dest, urlstr, len);
1923         rc = 0;
1924       }
1925       else
1926         longest_common_prefix (dest, urlstr, matchlen, len);
1927     }
1928   }
1929
1930   return rc;
1931 }
1932
1933 /* imap_complete: given a partial IMAP folder path, return a string which
1934  *   adds as much to the path as is unique */
1935 int imap_complete(char* dest, size_t dlen, char* path) {
1936   CONNECTION* conn;
1937   IMAP_DATA* idata;
1938   char list[LONG_STRING];
1939   char buf[LONG_STRING];
1940   IMAP_LIST listresp;
1941   char completion[LONG_STRING];
1942   int clen, matchlen = 0;
1943   int completions = 0;
1944   IMAP_MBOX mx;
1945   int rc;
1946
1947   if (imap_parse_path (path, &mx))
1948   {
1949     strfcpy (dest, path, dlen);
1950     return imap_complete_hosts (dest, dlen);
1951   }
1952
1953   /* don't open a new socket just for completion. Instead complete over
1954    * known mailboxes/hooks/etc */
1955   if (!(idata = imap_conn_find (&(mx.account), M_IMAP_CONN_NONEW)))
1956   {
1957     FREE (&mx.mbox);
1958     strfcpy (dest, path, dlen);
1959     return imap_complete_hosts (dest, dlen);
1960   }
1961   conn = idata->conn;
1962
1963   /* reformat path for IMAP list, and append wildcard */
1964   /* don't use INBOX in place of "" */
1965   if (mx.mbox && mx.mbox[0])
1966     imap_fix_path (idata, mx.mbox, list, sizeof(list));
1967   else
1968     list[0] = '\0';
1969
1970   /* fire off command */
1971   snprintf (buf, sizeof(buf), "%s \"\" \"%s%%\"",
1972     option (OPTIMAPLSUB) ? "LSUB" : "LIST", list);
1973
1974   imap_cmd_start (idata, buf);
1975
1976   /* and see what the results are */
1977   strfcpy (completion, NONULL(mx.mbox), sizeof(completion));
1978   idata->cmdtype = IMAP_CT_LIST;
1979   idata->cmddata = &listresp;
1980   do
1981   {
1982     listresp.name = NULL;
1983     rc = imap_cmd_step (idata);
1984
1985     if (rc == IMAP_CMD_CONTINUE && listresp.name)
1986     {
1987       /* if the folder isn't selectable, append delimiter to force browse
1988        * to enter it on second tab. */
1989       if (listresp.noselect)
1990       {
1991         clen = strlen(listresp.name);
1992         listresp.name[clen++] = listresp.delim;
1993         listresp.name[clen] = '\0';
1994       }
1995       /* copy in first word */
1996       if (!completions)
1997       {
1998         strfcpy (completion, listresp.name, sizeof(completion));
1999         matchlen = strlen (completion);
2000         completions++;
2001         continue;
2002       }
2003
2004       matchlen = longest_common_prefix (completion, listresp.name, 0, matchlen);
2005       completions++;
2006     }
2007   }
2008   while (rc == IMAP_CMD_CONTINUE);
2009   idata->cmddata = NULL;
2010
2011   if (completions)
2012   {
2013     /* reformat output */
2014     imap_qualify_path (dest, dlen, &mx, completion);
2015     mutt_pretty_mailbox (dest, dlen);
2016
2017     FREE (&mx.mbox);
2018     return 0;
2019   }
2020   
2021   return -1;
2022 }