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