drop mem_alloc and mem_free, use my own hand crafted optmized macros that
[apps/madmutt.git] / imap / imap.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996-8 Michael R. Elkins <me@mutt.org>
4  * Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
5  * Copyright (C) 1999-2005 Brendan Cully <brendan@kublai.com>
6  *
7  * This file is part of mutt-ng, see http://www.muttng.org/.
8  * It's licensed under the GNU General Public License,
9  * please see the file GPL in the top level source directory.
10  */
11
12 /* Support for IMAP4rev1, with the occasional nod to IMAP 4. */
13
14 #if HAVE_CONFIG_H
15 # include "config.h"
16 #endif
17
18 #include <lib-lib/mem.h>
19
20 #include "mutt.h"
21 #include "ascii.h"
22 #include "buffer.h"
23 #include "mx.h"
24 #include "globals.h"
25 #include "sort.h"
26 #include "browser.h"
27 #include "message.h"
28 #include "imap_private.h"
29 #if defined(USE_SSL) || defined(USE_GNUTLS)
30 # include "mutt_ssl.h"
31 #endif
32 #include "buffy.h"
33
34 #include "lib/mem.h"
35 #include "lib/intl.h"
36 #include "lib/str.h"
37 #include "lib/debug.h"
38
39 #include <unistd.h>
40 #include <ctype.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45
46 /* imap forward declarations */
47 static int imap_get_delim (IMAP_DATA * idata);
48 static char *imap_get_flags (LIST ** hflags, char *s);
49 static int imap_check_acl (IMAP_DATA * idata);
50 static int imap_check_capabilities (IMAP_DATA * idata);
51 static void imap_set_flag (IMAP_DATA * idata, int aclbit, int flag,
52                            const char *str, char *flags, size_t flsize);
53
54 /* imap_access: Check permissions on an IMAP mailbox.
55  * TODO: ACL checks. Right now we assume if it exists we can
56  * mess with it. */
57 int imap_access (const char *path, int flags)
58 {
59   IMAP_DATA *idata;
60   IMAP_MBOX mx;
61   char buf[LONG_STRING];
62   char mailbox[LONG_STRING];
63   char mbox[LONG_STRING];
64
65   if (imap_parse_path (path, &mx))
66     return -1;
67
68   if (!(idata = imap_conn_find (&mx.account,
69                                 option (OPTIMAPPASSIVE) ? M_IMAP_CONN_NONEW :
70                                 0))) {
71     p_delete(&mx.mbox);
72     return -1;
73   }
74
75   imap_fix_path (idata, mx.mbox, mailbox, sizeof (mailbox));
76
77   /* we may already be in the folder we're checking */
78   if (!ascii_strcmp(idata->mailbox, mx.mbox)) {
79     p_delete(&mx.mbox);
80     return 0;
81   }
82
83   p_delete(&mx.mbox);
84   imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
85
86   if (mutt_bit_isset (idata->capabilities, IMAP4REV1))
87     snprintf (buf, sizeof (buf), "STATUS %s (UIDVALIDITY)", mbox);
88   else if (mutt_bit_isset (idata->capabilities, STATUS))
89     snprintf (buf, sizeof (buf), "STATUS %s (UID-VALIDITY)", mbox);
90   else {
91     debug_print (2, ("STATUS not supported?\n"));
92     return -1;
93   }
94
95   if (imap_exec (idata, buf, IMAP_CMD_FAIL_OK) < 0) {
96     debug_print (1, ("Can't check STATUS of %s\n", mbox));
97     return -1;
98   }
99
100   return 0;
101 }
102
103 int imap_create_mailbox (IMAP_DATA * idata, char *mailbox)
104 {
105   char buf[LONG_STRING], mbox[LONG_STRING];
106
107   imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
108   snprintf (buf, sizeof (buf), "CREATE %s", mbox);
109
110   if (imap_exec (idata, buf, 0) != 0)
111     return -1;
112
113   return 0;
114 }
115
116 int imap_rename_mailbox (IMAP_DATA * idata, IMAP_MBOX * mx,
117                          const char *newname)
118 {
119   char oldmbox[LONG_STRING];
120   char newmbox[LONG_STRING];
121   char buf[LONG_STRING];
122
123   imap_munge_mbox_name (oldmbox, sizeof (oldmbox), mx->mbox);
124   imap_munge_mbox_name (newmbox, sizeof (newmbox), newname);
125
126   snprintf (buf, sizeof (buf), "RENAME %s %s", oldmbox, newmbox);
127
128   if (imap_exec (idata, buf, 0) != 0)
129     return -1;
130
131   return 0;
132 }
133
134 int imap_delete_mailbox (CONTEXT * ctx, IMAP_MBOX mx)
135 {
136   char buf[LONG_STRING], mbox[LONG_STRING];
137   IMAP_DATA *idata;
138
139   if (!ctx || !ctx->data) {
140     if (!(idata = imap_conn_find (&mx.account,
141                                   option (OPTIMAPPASSIVE) ? M_IMAP_CONN_NONEW
142                                   : 0))) {
143       p_delete(&mx.mbox);
144       return -1;
145     }
146   }
147   else {
148     idata = ctx->data;
149   }
150
151   imap_munge_mbox_name (mbox, sizeof (mbox), mx.mbox);
152   snprintf (buf, sizeof (buf), "DELETE %s", mbox);
153
154   if (imap_exec ((IMAP_DATA *) idata, buf, 0) != 0)
155     return -1;
156
157   return 0;
158 }
159
160 /* imap_logout_all: close all open connections. Quick and dirty until we can
161  *   make sure we've got all the context we need. */
162 void imap_logout_all (void)
163 {
164   CONNECTION *conn;
165   CONNECTION *tmp;
166
167   conn = mutt_socket_head ();
168
169   while (conn) {
170     tmp = conn->next;
171
172     if (conn->account.type == M_ACCT_TYPE_IMAP && conn->fd >= 0) {
173       mutt_message (_("Closing connection to %s..."), conn->account.host);
174       imap_logout ((IMAP_DATA *) conn->data);
175       mutt_clear_error ();
176       mutt_socket_close (conn);
177       mutt_socket_free (conn);
178     }
179
180     conn = tmp;
181   }
182 }
183
184 /* imap_read_literal: read bytes bytes from server into file. Not explicitly
185  *   buffered, relies on FILE buffering. NOTE: strips \r from \r\n.
186  *   Apparently even literals use \r\n-terminated strings ?! */
187 int imap_read_literal (FILE * fp, IMAP_DATA * idata, long bytes, progress_t* bar)
188 {
189   long pos;
190   char c;
191
192   int r = 0;
193
194   debug_print (2, ("reading %ld bytes\n", bytes));
195
196   for (pos = 0; pos < bytes; pos++) {
197     if (mutt_socket_readchar (idata->conn, &c) != 1) {
198       debug_print (1, ("error during read, %ld bytes read\n", pos));
199       idata->status = IMAP_FATAL;
200
201       return -1;
202     }
203
204 #if 1
205     if (r == 1 && c != '\n')
206       fputc ('\r', fp);
207
208     if (c == '\r') {
209       r = 1;
210       continue;
211     }
212     else
213       r = 0;
214 #endif
215     fputc (c, fp);
216     if (bar && !(pos % 1024))
217       mutt_progress_bar (bar, pos);
218 #ifdef DEBUG
219     if (DebugFile && DebugLevel >= IMAP_LOG_LTRL)
220       fputc (c, DebugFile);
221 #endif
222   }
223
224   return 0;
225 }
226
227 /* imap_expunge_mailbox: Purge IMAP portion of expunged messages from the
228  *   context. Must not be done while something has a handle on any headers
229  *   (eg inside pager or editor). That is, check IMAP_REOPEN_ALLOW. */
230 void imap_expunge_mailbox (IMAP_DATA * idata)
231 {
232   HEADER *h;
233   int i, cacheno;
234
235   for (i = 0; i < idata->ctx->msgcount; i++) {
236     h = idata->ctx->hdrs[i];
237
238     if (h->index == -1) {
239       debug_print (2, ("Expunging message UID %d.\n", HEADER_DATA (h)->uid));
240
241       h->active = 0;
242
243       /* free cached body from disk, if neccessary */
244       cacheno = HEADER_DATA (h)->uid % IMAP_CACHE_LEN;
245       if (idata->cache[cacheno].uid == HEADER_DATA (h)->uid &&
246           idata->cache[cacheno].path) {
247         unlink (idata->cache[cacheno].path);
248         p_delete(&idata->cache[cacheno].path);
249       }
250
251       imap_free_header_data (&h->data);
252     }
253   }
254
255   /* We may be called on to expunge at any time. We can't rely on the caller
256    * to always know to rethread */
257   mx_update_tables (idata->ctx, 0);
258   mutt_sort_headers (idata->ctx, 1);
259 }
260
261 static int imap_get_delim (IMAP_DATA * idata)
262 {
263   char *s;
264   int rc;
265
266   /* assume that the delim is /.  If this fails, we're in bigger trouble
267    * than getting the delim wrong */
268   idata->delim = '/';
269
270   imap_cmd_start (idata, "LIST \"\" \"\"");
271
272   do {
273     if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
274       break;
275
276     s = imap_next_word (idata->cmd.buf);
277     if (ascii_strncasecmp ("LIST", s, 4) == 0) {
278       s = imap_next_word (s);
279       s = imap_next_word (s);
280       if (s && s[0] == '\"' && s[1] && s[2] == '\"')
281         idata->delim = s[1];
282       else if (s && s[0] == '\"' && s[1] && s[1] == '\\' && s[2]
283                && s[3] == '\"')
284         idata->delim = s[2];
285     }
286   }
287   while (rc == IMAP_CMD_CONTINUE);
288
289   if (rc != IMAP_CMD_OK) {
290     debug_print (1, ("failed.\n"));
291     return -1;
292   }
293
294   debug_print (2, ("Delimiter: %c\n", idata->delim));
295
296   return -1;
297 }
298
299 /* get rights for folder, let imap_handle_untagged do the rest */
300 static int imap_check_acl (IMAP_DATA * idata)
301 {
302   char buf[LONG_STRING];
303   char mbox[LONG_STRING];
304
305   imap_munge_mbox_name (mbox, sizeof (mbox), idata->mailbox);
306   snprintf (buf, sizeof (buf), "MYRIGHTS %s", mbox);
307   if (imap_exec (idata, buf, 0) != 0) {
308     imap_error ("imap_check_acl", buf);
309     return -1;
310   }
311   return 0;
312 }
313
314 /* imap_check_capabilities: make sure we can log in to this server. */
315 static int imap_check_capabilities (IMAP_DATA * idata)
316 {
317   if (imap_exec (idata, "CAPABILITY", 0) != 0) {
318     imap_error ("imap_check_capabilities", idata->cmd.buf);
319     return -1;
320   }
321
322   if (!(mutt_bit_isset (idata->capabilities, IMAP4)
323         || mutt_bit_isset (idata->capabilities, IMAP4REV1))) {
324     mutt_error _("This IMAP server is ancient. Mutt does not work with it.");
325
326     mutt_sleep (2);             /* pause a moment to let the user see the error */
327
328     return -1;
329   }
330
331   return 0;
332 }
333
334 /* imap_conn_find: Find an open IMAP connection matching account, or open
335  *   a new one if none can be found. */
336 IMAP_DATA *imap_conn_find (const ACCOUNT * account, int flags)
337 {
338   CONNECTION *conn;
339   IMAP_DATA *idata;
340   ACCOUNT *creds;
341   int new = 0;
342
343   if (!(conn = mutt_conn_find (NULL, account)))
344     return NULL;
345
346   /* if opening a new UNSELECTED connection, preserve existing creds */
347   creds = &(conn->account);
348
349   /* make sure this connection is not in SELECTED state, if neccessary */
350   if (flags & M_IMAP_CONN_NOSELECT)
351     while (conn->data && ((IMAP_DATA *) conn->data)->state == IMAP_SELECTED) {
352       if (!(conn = mutt_conn_find (conn, account)))
353         return NULL;
354       memcpy (&(conn->account), creds, sizeof (ACCOUNT));
355     }
356
357   idata = (IMAP_DATA *) conn->data;
358
359   /* don't open a new connection if one isn't wanted */
360   if (flags & M_IMAP_CONN_NONEW) {
361     if (!idata) {
362       mutt_socket_free (conn);
363       return NULL;
364     }
365     if (idata->state < IMAP_AUTHENTICATED)
366       return NULL;
367   }
368
369   if (!idata) {
370     /* The current connection is a new connection */
371     if (!(idata = imap_new_idata ())) {
372       mutt_socket_free (conn);
373       return NULL;
374     }
375
376     conn->data = idata;
377     idata->conn = conn;
378     new = 1;
379   }
380
381   if (idata->state == IMAP_DISCONNECTED)
382     imap_open_connection (idata);
383   if (idata->state == IMAP_CONNECTED) {
384     if (!imap_authenticate (idata)) {
385       idata->state = IMAP_AUTHENTICATED;
386       if (idata->conn->ssf)
387         debug_print (2, ("Communication encrypted at %d bits\n", idata->conn->ssf));
388     }
389     else
390       mutt_account_unsetpass (&idata->conn->account);
391
392     p_delete(&idata->capstr);
393   }
394   if (new && idata->state == IMAP_AUTHENTICATED) {
395     imap_get_delim (idata);
396     if (option (OPTIMAPCHECKSUBSCRIBED)) {
397       mutt_message _("Checking mailbox subscriptions");
398       imap_exec (idata, "LSUB \"\" \"*\"", 0);
399     }
400   }
401
402   return idata;
403 }
404
405 int imap_open_connection (IMAP_DATA * idata)
406 {
407   char buf[LONG_STRING];
408
409   if (mutt_socket_open (idata->conn) < 0)
410     return -1;
411
412   idata->state = IMAP_CONNECTED;
413
414   if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE) {
415     mutt_socket_close (idata->conn);
416     idata->state = IMAP_DISCONNECTED;
417     return -1;
418   }
419
420   if (ascii_strncasecmp ("* OK", idata->cmd.buf, 4) == 0) {
421     /* TODO: Parse new tagged CAPABILITY data (* OK [CAPABILITY...]) */
422     if (imap_check_capabilities (idata))
423       goto bail;
424 #if defined(USE_SSL) || defined(USE_GNUTLS)
425     /* Attempt STARTTLS if available and desired. */
426     if (!idata->conn->ssf && (option(OPTSSLFORCETLS) || 
427                               mutt_bit_isset (idata->capabilities, STARTTLS))) {
428       int rc;
429
430       if (option (OPTSSLFORCETLS))
431         rc = M_YES;
432       else if ((rc = query_quadoption (OPT_SSLSTARTTLS,
433                                        _("Secure connection with TLS?"))) == -1)
434         goto err_close_conn;
435       if (rc == M_YES) {
436         if ((rc = imap_exec (idata, "STARTTLS", IMAP_CMD_FAIL_OK)) == -1)
437           goto bail;
438         if (rc != -2) {
439 #if defined (USE_SSL) || defined (USE_GNUTLS)
440           if (mutt_ssl_starttls (idata->conn))
441 #endif
442           {
443             mutt_error (_("Could not negotiate TLS connection"));
444             mutt_sleep (1);
445             goto err_close_conn;
446           }
447           else {
448             /* RFC 2595 demands we recheck CAPABILITY after TLS completes. */
449             if (imap_exec (idata, "CAPABILITY", 0))
450               goto bail;
451           }
452         }
453       }
454     }
455
456     if (option(OPTSSLFORCETLS) && ! idata->conn->ssf) {
457       mutt_error _("Encrypted connection unavailable");
458       mutt_sleep (1);
459       goto err_close_conn;
460     }
461 #endif
462   }
463   else if (ascii_strncasecmp ("* PREAUTH", idata->cmd.buf, 9) == 0) {
464     idata->state = IMAP_AUTHENTICATED;
465     if (imap_check_capabilities (idata) != 0)
466       goto bail;
467     p_delete(&idata->capstr);
468   }
469   else {
470     imap_error ("imap_open_connection()", buf);
471     goto bail;
472   }
473
474   return 0;
475
476 err_close_conn:
477   mutt_socket_close (idata->conn);
478   idata->state = IMAP_DISCONNECTED;
479 bail:
480   p_delete(&idata->capstr);
481   return -1;
482 }
483
484 /* imap_get_flags: Make a simple list out of a FLAGS response.
485  *   return stream following FLAGS response */
486 static char *imap_get_flags (LIST ** hflags, char *s)
487 {
488   LIST *flags;
489   char *flag_word;
490   char ctmp;
491
492   /* sanity-check string */
493   if (ascii_strncasecmp ("FLAGS", s, 5) != 0) {
494     debug_print (1, ("not a FLAGS response: %s\n", s));
495     return NULL;
496   }
497   s += 5;
498   SKIPWS (s);
499   if (*s != '(') {
500     debug_print (1, ("bogus FLAGS response: %s\n", s));
501     return NULL;
502   }
503
504   /* create list, update caller's flags handle */
505   flags = mutt_new_list ();
506   *hflags = flags;
507
508   while (*s && *s != ')') {
509     s++;
510     SKIPWS (s);
511     flag_word = s;
512     while (*s && (*s != ')') && !ISSPACE (*s))
513       s++;
514     ctmp = *s;
515     *s = '\0';
516     if (*flag_word)
517       mutt_add_list (flags, flag_word);
518     *s = ctmp;
519   }
520
521   /* note bad flags response */
522   if (*s != ')') {
523     debug_print (1, ("Unterminated FLAGS response: %s\n", s));
524     mutt_free_list (hflags);
525
526     return NULL;
527   }
528
529   s++;
530
531   return s;
532 }
533
534 int imap_open_mailbox (CONTEXT * ctx)
535 {
536   CONNECTION *conn;
537   IMAP_DATA *idata;
538   char buf[LONG_STRING];
539   char bufout[LONG_STRING];
540   int count = 0;
541   IMAP_MBOX mx;
542   int rc;
543
544   if (imap_parse_path (ctx->path, &mx)) {
545     mutt_error (_("%s is an invalid IMAP path"), ctx->path);
546     return -1;
547   }
548
549   /* we require a connection which isn't currently in IMAP_SELECTED state */
550   if (!(idata = imap_conn_find (&(mx.account), M_IMAP_CONN_NOSELECT)))
551     goto fail_noidata;
552   if (idata->state < IMAP_AUTHENTICATED)
553     goto fail;
554
555   conn = idata->conn;
556
557   /* once again the context is new */
558   ctx->data = idata;
559
560   /* Clean up path and replace the one in the ctx */
561   imap_fix_path (idata, mx.mbox, buf, sizeof (buf));
562   p_delete(&(idata->mailbox));
563   idata->mailbox = str_dup (buf);
564   imap_qualify_path (buf, sizeof (buf), &mx, idata->mailbox);
565
566   p_delete(&(ctx->path));
567   ctx->path = str_dup (buf);
568
569   idata->ctx = ctx;
570
571   /* clear mailbox status */
572   idata->status = 0;
573   memset (idata->rights, 0, (RIGHTSMAX + 7) / 8);
574   idata->newMailCount = 0;
575
576   mutt_message (_("Selecting %s..."), idata->mailbox);
577   imap_munge_mbox_name (buf, sizeof (buf), idata->mailbox);
578   snprintf (bufout, sizeof (bufout), "%s %s",
579             ctx->readonly ? "EXAMINE" : "SELECT", buf);
580
581   idata->state = IMAP_SELECTED;
582
583   imap_cmd_start (idata, bufout);
584
585   do {
586     char *pc;
587
588     if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
589       break;
590
591     pc = idata->cmd.buf + 2;
592
593     /* Obtain list of available flags here, may be overridden by a
594      * PERMANENTFLAGS tag in the OK response */
595     if (ascii_strncasecmp ("FLAGS", pc, 5) == 0) {
596       /* don't override PERMANENTFLAGS */
597       if (!idata->flags) {
598         debug_print (2, ("Getting mailbox FLAGS\n"));
599         if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
600           goto fail;
601       }
602     }
603     /* PERMANENTFLAGS are massaged to look like FLAGS, then override FLAGS */
604     else if (ascii_strncasecmp ("OK [PERMANENTFLAGS", pc, 18) == 0) {
605       debug_print (2, ("Getting mailbox PERMANENTFLAGS\n"));
606       /* safe to call on NULL */
607       mutt_free_list (&(idata->flags));
608       /* skip "OK [PERMANENT" so syntax is the same as FLAGS */
609       pc += 13;
610       if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
611         goto fail;
612     }
613 #ifdef USE_HCACHE
614     /* save UIDVALIDITY for the header cache */
615     else if (ascii_strncasecmp ("OK [UIDVALIDITY", pc, 14) == 0) {
616       debug_print (2, ("Getting mailbox UIDVALIDITY\n"));
617       pc += 3;
618       pc = imap_next_word (pc);
619
620       sscanf (pc, "%lu", &(idata->uid_validity));
621     }
622 #endif
623     else {
624       pc = imap_next_word (pc);
625       if (!ascii_strncasecmp ("EXISTS", pc, 6)) {
626         count = idata->newMailCount;
627         idata->newMailCount = 0;
628       }
629     }
630   }
631   while (rc == IMAP_CMD_CONTINUE);
632
633   if (rc == IMAP_CMD_NO) {
634     char *s;
635
636     s = imap_next_word (idata->cmd.buf);        /* skip seq */
637     s = imap_next_word (s);     /* Skip response */
638     mutt_error ("%s", s);
639     mutt_sleep (2);
640     goto fail;
641   }
642
643   if (rc != IMAP_CMD_OK)
644     goto fail;
645
646   /* check for READ-ONLY notification */
647   if (!ascii_strncasecmp
648       (imap_get_qualifier (idata->cmd.buf), "[READ-ONLY]", 11)
649       && !mutt_bit_isset (idata->capabilities, ACL)) {
650     debug_print (2, ("Mailbox is read-only.\n"));
651     ctx->readonly = 1;
652   }
653
654 #ifdef DEBUG
655   /* dump the mailbox flags we've found */
656   if (DebugLevel > 2) {
657     if (!idata->flags)
658       debug_print (3, ("No folder flags found\n"));
659     else {
660       LIST *t = idata->flags;
661
662       debug_print (3, ("Mailbox flags:\n"));
663
664       t = t->next;
665       while (t) {
666         debug_print (3, ("[%s]\n", t->data));
667         t = t->next;
668       }
669     }
670   }
671 #endif
672
673   if (mutt_bit_isset (idata->capabilities, ACL)) {
674     if (imap_check_acl (idata))
675       goto fail;
676     if (!(mutt_bit_isset (idata->rights, ACL_DELETE) ||
677           mutt_bit_isset (idata->rights, ACL_SEEN) ||
678           mutt_bit_isset (idata->rights, ACL_WRITE) ||
679           mutt_bit_isset (idata->rights, ACL_INSERT)))
680       ctx->readonly = 1;
681   }
682   /* assume we have all rights if ACL is unavailable */
683   else {
684     mutt_bit_set (idata->rights, ACL_LOOKUP);
685     mutt_bit_set (idata->rights, ACL_READ);
686     mutt_bit_set (idata->rights, ACL_SEEN);
687     mutt_bit_set (idata->rights, ACL_WRITE);
688     mutt_bit_set (idata->rights, ACL_INSERT);
689     mutt_bit_set (idata->rights, ACL_POST);
690     mutt_bit_set (idata->rights, ACL_CREATE);
691     mutt_bit_set (idata->rights, ACL_DELETE);
692   }
693
694   ctx->hdrmax = count;
695   ctx->hdrs = mem_calloc (count, sizeof (HEADER *));
696   ctx->v2r = mem_calloc (count, sizeof (int));
697   ctx->msgcount = 0;
698   if (count && (imap_read_headers (idata, 0, count - 1) < 0)) {
699     mutt_error _("Error opening mailbox");
700
701     mutt_sleep (1);
702     goto fail;
703   }
704
705   debug_print (2, ("msgcount is %d\n", ctx->msgcount));
706   p_delete(&mx.mbox);
707   return 0;
708
709 fail:
710   if (idata->state == IMAP_SELECTED)
711     idata->state = IMAP_AUTHENTICATED;
712 fail_noidata:
713   p_delete(&mx.mbox);
714   return -1;
715 }
716
717 int imap_open_mailbox_append (CONTEXT * ctx)
718 {
719   CONNECTION *conn;
720   IMAP_DATA *idata;
721   char buf[LONG_STRING];
722   char mailbox[LONG_STRING];
723   IMAP_MBOX mx;
724
725   if (imap_parse_path (ctx->path, &mx))
726     return -1;
727
728   /* in APPEND mode, we appear to hijack an existing IMAP connection -
729    * ctx is brand new and mostly empty */
730
731   if (!(idata = imap_conn_find (&(mx.account), 0))) {
732     p_delete(&mx.mbox);
733     return (-1);
734   }
735   conn = idata->conn;
736
737   ctx->magic = M_IMAP;
738   ctx->data = idata;
739
740   imap_fix_path (idata, mx.mbox, mailbox, sizeof (mailbox));
741
742   p_delete(&mx.mbox);
743
744   /* really we should also check for W_OK */
745   if (!imap_access (ctx->path, F_OK))
746     return 0;
747
748   snprintf (buf, sizeof (buf), _("Create %s?"), mailbox);
749   if (option (OPTCONFIRMCREATE) && mutt_yesorno (buf, 1) < 1)
750     return -1;
751
752   if (imap_create_mailbox (idata, mailbox) < 0)
753     return -1;
754
755   return (0);
756 }
757
758 /* imap_logout: Gracefully log out of server. */
759 void imap_logout (IMAP_DATA * idata)
760 {
761   /* we set status here to let imap_handle_untagged know we _expect_ to
762    * receive a bye response (so it doesn't freak out and close the conn) */
763   idata->status = IMAP_BYE;
764   imap_cmd_start (idata, "LOGOUT");
765   while (imap_cmd_step (idata) == IMAP_CMD_CONTINUE);
766   p_delete(&idata->cmd.buf);
767   p_delete(&idata);
768 }
769
770 /*
771 int imap_close_connection (CONTEXT *ctx)
772 {
773   debug_print (1, (debugfile, "imap_close_connection(): closing connection\n"));
774   if (CTX_DATA->status != IMAP_BYE)
775   {
776     mutt_message _("Closing connection to IMAP server...");
777     imap_logout (CTX_DATA);
778     mutt_clear_error ();
779   }
780   mutt_socket_close (CTX_DATA->conn);
781   CTX_DATA->state = IMAP_DISCONNECTED;
782   CTX_DATA->conn->data = NULL;
783   return 0;
784 }
785 */
786
787 /* imap_set_flag: append str to flags if we currently have permission
788  *   according to aclbit */
789 static void imap_set_flag (IMAP_DATA * idata, int aclbit, int flag,
790                            const char *str, char *flags, size_t flsize)
791 {
792   if (mutt_bit_isset (idata->rights, aclbit))
793     if (flag)
794       str_cat (flags, flsize, str);
795 }
796
797 /* imap_make_msg_set: make an IMAP4rev1 UID message set out of a set of
798  *   headers, given a flag enum to filter on.
799  * Params: idata: IMAP_DATA containing context containing header set
800  *         buf: to write message set into
801  *         buflen: length of buffer
802  *         flag: enum of flag type on which to filter
803  *         changed: include only changed messages in message set
804  * Returns: number of messages in message set (0 if no matches) */
805 int imap_make_msg_set (IMAP_DATA * idata, BUFFER * buf, int flag, int changed)
806 {
807   HEADER **hdrs;                /* sorted local copy */
808   int count = 0;                /* number of messages in message set */
809   int match = 0;                /* whether current message matches flag condition */
810   unsigned int setstart = 0;    /* start of current message range */
811   int n;
812   short oldsort;                /* we clobber reverse, must restore it */
813
814   /* assuming 32-bit UIDs */
815   char uid[12];
816   int started = 0;
817
818   /* make copy of header pointers to sort in natural order */
819   hdrs = mem_calloc (idata->ctx->msgcount, sizeof (HEADER *));
820   memcpy (hdrs, idata->ctx->hdrs, idata->ctx->msgcount * sizeof (HEADER *));
821
822   if (Sort != SORT_ORDER) {
823     oldsort = Sort;
824     Sort = SORT_ORDER;
825     qsort ((void *) hdrs, idata->ctx->msgcount, sizeof (HEADER *),
826            mutt_get_sort_func (SORT_ORDER));
827     Sort = oldsort;
828   }
829
830   for (n = 0; n < idata->ctx->msgcount; n++) {
831     match = 0;
832     /* don't include pending expunged messages */
833     if (hdrs[n]->active)
834       switch (flag) {
835       case M_DELETE:
836         if (hdrs[n]->deleted)
837           match = 1;
838         break;
839       case M_TAG:
840         if (hdrs[n]->tagged)
841           match = 1;
842         break;
843       }
844
845     if (match && (!changed || hdrs[n]->changed)) {
846       count++;
847       if (setstart == 0) {
848         setstart = HEADER_DATA (hdrs[n])->uid;
849         if (started == 0) {
850           snprintf (uid, sizeof (uid), "%u", HEADER_DATA (hdrs[n])->uid);
851           mutt_buffer_addstr (buf, uid);
852           started = 1;
853         }
854         else {
855           snprintf (uid, sizeof (uid), ",%u", HEADER_DATA (hdrs[n])->uid);
856           mutt_buffer_addstr (buf, uid);
857         }
858       }
859       /* tie up if the last message also matches */
860       else if (n == idata->ctx->msgcount - 1) {
861         snprintf (uid, sizeof (uid), ":%u", HEADER_DATA (hdrs[n])->uid);
862         mutt_buffer_addstr (buf, uid);
863       }
864     }
865     /* this message is not expunged and doesn't match. End current set. */
866     else if (setstart && hdrs[n]->active) {
867       if (HEADER_DATA (hdrs[n - 1])->uid > setstart) {
868         snprintf (uid, sizeof (uid), ":%u", HEADER_DATA (hdrs[n - 1])->uid);
869         mutt_buffer_addstr (buf, uid);
870       }
871       setstart = 0;
872     }
873   }
874
875   p_delete(&hdrs);
876
877   return count;
878 }
879
880 /* Update the IMAP server to reflect the flags a single message.  */
881
882 int imap_sync_message (IMAP_DATA *idata, HEADER *hdr, BUFFER *cmd,
883                        int *err_continue)
884 {
885   char flags[LONG_STRING];
886   char uid[11];
887
888   hdr->changed = 0;
889
890   snprintf (uid, sizeof (uid), "%u", HEADER_DATA(hdr)->uid);
891   cmd->dptr = cmd->data;
892   mutt_buffer_addstr (cmd, "UID STORE ");
893   mutt_buffer_addstr (cmd, uid);
894
895   flags[0] = '\0';
896       
897   imap_set_flag (idata, ACL_SEEN, hdr->read, "\\Seen ",
898                  flags, sizeof (flags));
899   imap_set_flag (idata, ACL_WRITE, hdr->flagged,
900                  "\\Flagged ", flags, sizeof (flags));
901   imap_set_flag (idata, ACL_WRITE, hdr->replied,
902                  "\\Answered ", flags, sizeof (flags));
903   imap_set_flag (idata, ACL_DELETE, hdr->deleted,
904                  "\\Deleted ", flags, sizeof (flags));
905
906   /* now make sure we don't lose custom tags */
907   if (mutt_bit_isset (idata->rights, ACL_WRITE))
908     imap_add_keywords (flags, hdr, idata->flags, sizeof (flags));
909
910   str_skip_trailws (flags);
911
912   /* UW-IMAP is OK with null flags, Cyrus isn't. The only solution is to
913    * explicitly revoke all system flags (if we have permission) */
914   if (!*flags)
915   {
916     imap_set_flag (idata, ACL_SEEN, 1, "\\Seen ", flags, sizeof (flags));
917     imap_set_flag (idata, ACL_WRITE, 1, "\\Flagged ", flags, sizeof (flags));
918     imap_set_flag (idata, ACL_WRITE, 1, "\\Answered ", flags, sizeof (flags));
919     imap_set_flag (idata, ACL_DELETE, 1, "\\Deleted ", flags, sizeof (flags));
920
921     str_skip_trailws (flags);
922
923     mutt_buffer_addstr (cmd, " -FLAGS.SILENT (");
924   } else
925     mutt_buffer_addstr (cmd, " FLAGS.SILENT (");
926
927   mutt_buffer_addstr (cmd, flags);
928   mutt_buffer_addstr (cmd, ")");
929
930   /* dumb hack for bad UW-IMAP 4.7 servers spurious FLAGS updates */
931   hdr->active = 0;
932
933   /* after all this it's still possible to have no flags, if you
934    * have no ACL rights */
935   if (*flags && (imap_exec (idata, cmd->data, 0) != 0) &&
936       err_continue && (*err_continue != M_YES))
937   {
938     *err_continue = imap_continue ("imap_sync_message: STORE failed",
939                                    idata->cmd.buf);
940     if (*err_continue != M_YES)
941       return -1;
942   }
943
944   hdr->active = 1;
945   idata->ctx->changed--;
946
947   return 0;
948 }
949
950 /* update the IMAP server to reflect message changes done within mutt.
951  * Arguments
952  *   ctx: the current context
953  *   expunge: 0 or 1 - do expunge? 
954  */
955
956 int imap_sync_mailbox (CONTEXT * ctx, int expunge, int *index_hint)
957 {
958   IMAP_DATA *idata;
959   CONTEXT *appendctx = NULL;
960   BUFFER cmd;
961   int deleted;
962   int n;
963   int err_continue = M_NO;      /* continue on error? */
964   int rc;
965
966   idata = (IMAP_DATA *) ctx->data;
967
968   if (idata->state != IMAP_SELECTED) {
969     debug_print (2, ("no mailbox selected\n"));
970     return -1;
971   }
972
973   /* This function is only called when the calling code expects the context
974    * to be changed. */
975   imap_allow_reopen (ctx);
976
977   if ((rc = imap_check_mailbox (ctx, index_hint, 0)) != 0)
978     return rc;
979
980   memset (&cmd, 0, sizeof (cmd));
981
982   /* if we are expunging anyway, we can do deleted messages very quickly... */
983   if (expunge && mutt_bit_isset (idata->rights, ACL_DELETE)) {
984     mutt_buffer_addstr (&cmd, "UID STORE ");
985     deleted = imap_make_msg_set (idata, &cmd, M_DELETE, 1);
986
987     /* if we have a message set, then let's delete */
988     if (deleted) {
989       mutt_message (_("Marking %d messages deleted..."), deleted);
990       mutt_buffer_addstr (&cmd, " +FLAGS.SILENT (\\Deleted)");
991       /* mark these messages as unchanged so second pass ignores them. Done
992        * here so BOGUS UW-IMAP 4.7 SILENT FLAGS updates are ignored. */
993       for (n = 0; n < ctx->msgcount; n++)
994         if (ctx->hdrs[n]->deleted && ctx->hdrs[n]->changed)
995           ctx->hdrs[n]->active = 0;
996       if (imap_exec (idata, cmd.data, 0) != 0) {
997         mutt_error (_("Expunge failed"));
998         mutt_sleep (1);
999         rc = -1;
1000         goto out;
1001       }
1002     }
1003   }
1004
1005   /* save status changes */
1006   for (n = 0; n < ctx->msgcount; n++) {
1007     if (ctx->hdrs[n]->active && ctx->hdrs[n]->changed) {
1008
1009       mutt_message (_("Saving message status flags... [%d/%d]"), n + 1,
1010                     ctx->msgcount);
1011
1012       /* if the message has been rethreaded or attachments have been deleted
1013        * we delete the message and reupload it.
1014        * This works better if we're expunging, of course. */
1015       if ((ctx->hdrs[n]->env && (ctx->hdrs[n]->env->refs_changed || ctx->hdrs[n]->env->irt_changed)) ||
1016           ctx->hdrs[n]->attach_del) {
1017         debug_print (3, ("Attachments to be deleted, falling back to _mutt_save_message\n"));
1018         if (!appendctx)
1019           appendctx = mx_open_mailbox (ctx->path, M_APPEND | M_QUIET, NULL);
1020         if (!appendctx) {
1021           debug_print (1, ("Error opening mailbox in append mode\n"));
1022         }
1023         else
1024           _mutt_save_message (ctx->hdrs[n], appendctx, 1, 0, 0);
1025       }
1026
1027       if (imap_sync_message (idata, ctx->hdrs[n], &cmd, &err_continue) < 0) {
1028         rc = -1;
1029         goto out;
1030       }
1031     }
1032   }
1033   ctx->changed = 0;
1034
1035   /* We must send an EXPUNGE command if we're not closing. */
1036   if (expunge && !(ctx->closing) &&
1037       mutt_bit_isset (idata->rights, ACL_DELETE)) {
1038     mutt_message _("Expunging messages from server...");
1039
1040     /* Set expunge bit so we don't get spurious reopened messages */
1041     idata->reopen |= IMAP_EXPUNGE_EXPECTED;
1042     if (imap_exec (idata, "EXPUNGE", 0) != 0) {
1043       imap_error (_("imap_sync_mailbox: EXPUNGE failed"), idata->cmd.buf);
1044       rc = imap_reconnect (ctx);
1045       goto out;
1046     }
1047   }
1048
1049   if (expunge && ctx->closing) {
1050     if (imap_exec (idata, "CLOSE", 0))
1051       mutt_error (_("CLOSE failed"));
1052     idata->state = IMAP_AUTHENTICATED;
1053   }
1054
1055   rc = 0;
1056 out:
1057   if (cmd.data)
1058     p_delete(&cmd.data);
1059   if (appendctx) {
1060     mx_fastclose_mailbox (appendctx);
1061     p_delete(&appendctx);
1062   }
1063   return rc;
1064 }
1065
1066 /* imap_close_mailbox: clean up IMAP data in CONTEXT */
1067 void imap_close_mailbox (CONTEXT * ctx)
1068 {
1069   IMAP_DATA *idata;
1070   int i;
1071
1072   idata = (IMAP_DATA *) ctx->data;
1073   /* Check to see if the mailbox is actually open */
1074   if (!idata)
1075     return;
1076
1077   if (ctx == idata->ctx) {
1078     if (idata->state != IMAP_FATAL && idata->state == IMAP_SELECTED) {
1079       /* mx_close_mailbox won't sync if there are no deleted messages
1080       * and the mailbox is unchanged, so we may have to close here */
1081       if (!ctx->deleted && imap_exec (idata, "CLOSE", 0))
1082         mutt_error (_("CLOSE failed"));
1083       idata->state = IMAP_AUTHENTICATED;
1084     }
1085
1086     idata->reopen &= IMAP_REOPEN_ALLOW;
1087     p_delete(&(idata->mailbox));
1088     mutt_free_list (&idata->flags);
1089     idata->ctx = NULL;
1090   }
1091
1092   /* free IMAP part of headers */
1093   for (i = 0; i < ctx->msgcount; i++)
1094     imap_free_header_data (&(ctx->hdrs[i]->data));
1095
1096   for (i = 0; i < IMAP_CACHE_LEN; i++) {
1097     if (idata->cache[i].path) {
1098       unlink (idata->cache[i].path);
1099       p_delete(&idata->cache[i].path);
1100     }
1101   }
1102 }
1103
1104 /* use the NOOP command to poll for new mail
1105  *
1106  * return values:
1107  *      M_REOPENED      mailbox has been externally modified
1108  *      M_NEW_MAIL      new mail has arrived!
1109  *      0               no change
1110  *      -1              error
1111  */
1112 int imap_check_mailbox (CONTEXT * ctx, int *index_hint, int force)
1113 {
1114   /* overload keyboard timeout to avoid many mailbox checks in a row.
1115    * Most users don't like having to wait exactly when they press a key. */
1116   IMAP_DATA *idata;
1117   int result = 0;
1118
1119   idata = (IMAP_DATA *) ctx->data;
1120
1121   if ((force || time (NULL) >= idata->lastread + Timeout)
1122       && imap_exec (idata, "NOOP", 0) != 0)
1123     return -1;
1124
1125   /* We call this even when we haven't run NOOP in case we have pending
1126    * changes to process, since we can reopen here. */
1127   imap_cmd_finish (idata);
1128
1129   if (idata->check_status & IMAP_EXPUNGE_PENDING)
1130     result = M_REOPENED;
1131   else if (idata->check_status & IMAP_NEWMAIL_PENDING)
1132     result = M_NEW_MAIL;
1133   else if (idata->check_status & IMAP_FLAGS_PENDING)
1134     result = M_FLAGS;
1135
1136   idata->check_status = 0;
1137
1138   return result;
1139 }
1140
1141 /*
1142  * count messages:
1143  *      new == 1:  recent
1144  *      new == 2:  unseen
1145  *      otherwise: total
1146  * return:
1147  *   0+   number of messages in mailbox
1148  *  -1    error while polling mailboxes
1149  */
1150 int imap_mailbox_check (char *path, int new)
1151 {
1152   CONNECTION *conn;
1153   IMAP_DATA *idata;
1154   char buf[LONG_STRING];
1155   char mbox[LONG_STRING];
1156   char mbox_unquoted[LONG_STRING];
1157   char *s;
1158   int msgcount = 0;
1159   int connflags = 0;
1160   IMAP_MBOX mx;
1161   int rc;
1162
1163   if (imap_parse_path (path, &mx))
1164     return -1;
1165
1166   /* If imap_passive is set, don't open a connection to check for new mail */
1167   if (option (OPTIMAPPASSIVE))
1168     connflags = M_IMAP_CONN_NONEW;
1169
1170   if (!(idata = imap_conn_find (&(mx.account), connflags))) {
1171     p_delete(&mx.mbox);
1172     return -1;
1173   }
1174   conn = idata->conn;
1175
1176   imap_fix_path (idata, mx.mbox, buf, sizeof (buf));
1177   p_delete(&mx.mbox);
1178
1179   imap_munge_mbox_name (mbox, sizeof (mbox), buf);
1180   strfcpy (mbox_unquoted, buf, sizeof (mbox_unquoted));
1181
1182   /* The draft IMAP implementor's guide warns againts using the STATUS
1183    * command on a mailbox that you have selected 
1184    */
1185
1186   if (str_cmp (mbox_unquoted, idata->mailbox) == 0
1187       || (ascii_strcasecmp (mbox_unquoted, "INBOX") == 0
1188           && str_casecmp (mbox_unquoted, idata->mailbox) == 0)) {
1189     strfcpy (buf, "NOOP", sizeof (buf));
1190   }
1191   else if (mutt_bit_isset (idata->capabilities, IMAP4REV1) ||
1192            mutt_bit_isset (idata->capabilities, STATUS)) {
1193     snprintf (buf, sizeof (buf), "STATUS %s (%s)", mbox,
1194               new == 1 ? "RECENT" : (new == 2 ? "UNSEEN" : "MESSAGES"));
1195   }
1196   else
1197     /* Server does not support STATUS, and this is not the current mailbox.
1198      * There is no lightweight way to check recent arrivals */
1199     return -1;
1200
1201   imap_cmd_start (idata, buf);
1202
1203   do {
1204     if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
1205       break;
1206
1207     s = imap_next_word (idata->cmd.buf);
1208     if (ascii_strncasecmp ("STATUS", s, 6) == 0) {
1209       s = imap_next_word (s);
1210       /* The mailbox name may or may not be quoted here. We could try to 
1211        * munge the server response and compare with quoted (or vise versa)
1212        * but it is probably more efficient to just strncmp against both. */
1213       if (str_ncmp (mbox_unquoted, s, str_len (mbox_unquoted)) == 0
1214           || str_ncmp (mbox, s, str_len (mbox)) == 0) {
1215         s = imap_next_word (s);
1216         s = imap_next_word (s);
1217         if (isdigit ((unsigned char) *s)) {
1218           if (*s != '0') {
1219             msgcount = atoi (s);
1220             debug_print (2, ("%d new messages in %s\n", msgcount, path));
1221           }
1222         }
1223       }
1224       else
1225         debug_print (1, ("STATUS response doesn't match requested mailbox.\n"));
1226     }
1227   }
1228   while (rc == IMAP_CMD_CONTINUE);
1229
1230   return msgcount;
1231 }
1232
1233 /* returns number of patterns in the search that should be done server-side
1234  * (eg are full-text) */
1235 static int do_search (const pattern_t* search, int allpats)
1236 {
1237   int rc = 0;
1238   const pattern_t* pat;
1239
1240   for (pat = search; pat; pat = pat->next) {
1241     switch (pat->op) {
1242       case M_BODY:
1243       case M_HEADER:
1244       case M_WHOLE_MSG:
1245         if (pat->stringmatch)
1246           rc++;
1247         break;
1248       default:
1249       if (pat->child && do_search (pat->child, 1))
1250         rc++;
1251     }
1252
1253     if (!allpats)
1254       break;
1255   }
1256
1257   return rc;
1258 }
1259
1260 /* convert mutt pattern_t to IMAP SEARCH command containing only elements
1261 * that require full-text search (mutt already has what it needs for most
1262 * match types, and does a better job (eg server doesn't support regexps). */
1263 static int imap_compile_search (const pattern_t* pat, BUFFER* buf)
1264 {
1265   if (! do_search (pat, 0))
1266     return 0;
1267
1268   if (pat->not)
1269     mutt_buffer_addstr (buf, "NOT ");
1270
1271   if (pat->child) {
1272     int clauses;
1273
1274     if ((clauses = do_search (pat->child, 1)) > 0) {
1275       const pattern_t* clause = pat->child;
1276
1277       mutt_buffer_addch (buf, '(');
1278
1279       while (clauses) {
1280         if (do_search (clause, 0)) {
1281           if (pat->op == M_OR && clauses > 1)
1282             mutt_buffer_addstr (buf, "OR ");
1283           clauses--;
1284           if (imap_compile_search (clause, buf) < 0)
1285             return -1;
1286
1287           if (clauses)
1288             mutt_buffer_addch (buf, ' ');
1289           
1290           clause = clause->next;
1291         }
1292       }
1293
1294       mutt_buffer_addch (buf, ')');
1295     }
1296   } else {
1297     char term[STRING];
1298     char *delim;
1299
1300     switch (pat->op) {
1301       case M_HEADER:
1302         mutt_buffer_addstr (buf, "HEADER ");
1303
1304         /* extract header name */
1305         if (! (delim = strchr (pat->str, ':'))) {
1306           mutt_error (_("Header search without header name: %s"), pat->str);
1307           return -1;
1308         }
1309         *delim = '\0';
1310         imap_quote_string (term, sizeof (term), pat->str);
1311         mutt_buffer_addstr (buf, term);
1312         mutt_buffer_addch (buf, ' ');
1313
1314         /* and field */
1315         *delim = ':';
1316         delim++;
1317         SKIPWS(delim);
1318         imap_quote_string (term, sizeof (term), delim);
1319         mutt_buffer_addstr (buf, term);
1320         break;
1321
1322       case M_BODY:
1323         mutt_buffer_addstr (buf, "BODY ");
1324         imap_quote_string (term, sizeof (term), pat->str);
1325         mutt_buffer_addstr (buf, term);
1326         break;
1327
1328       case M_WHOLE_MSG:
1329         mutt_buffer_addstr (buf, "TEXT ");
1330         imap_quote_string (term, sizeof (term), pat->str);
1331         mutt_buffer_addstr (buf, term);
1332       break;
1333     }
1334   }
1335
1336   return 0;
1337 }
1338
1339 int imap_search (CONTEXT* ctx, const pattern_t* pat) {
1340   BUFFER buf;
1341   IMAP_DATA* idata = (IMAP_DATA*)ctx->data;
1342   int i;
1343
1344   for (i = 0; i < ctx->msgcount; i++)
1345     ctx->hdrs[i]->matched = 0;
1346
1347   if (!do_search (pat, 1))
1348     return 0;
1349
1350   memset (&buf, 0, sizeof (buf));
1351   mutt_buffer_addstr (&buf, "UID SEARCH ");
1352   if (imap_compile_search (pat, &buf) < 0) {
1353     p_delete(&buf.data);
1354     return -1;
1355   }
1356   if (imap_exec (idata, buf.data, 0) < 0) {
1357     p_delete(&buf.data);
1358     return -1;
1359   }
1360
1361   p_delete(&buf.data);
1362   return 0;
1363 }
1364
1365 /* all this listing/browsing is a mess. I don't like that name is a pointer
1366  *   into idata->buf (used to be a pointer into the passed in buffer, just
1367  *   as bad), nor do I like the fact that the fetch is done here. This
1368  *   code can't possibly handle non-LIST untagged responses properly.
1369  *   FIXME. ?! */
1370 int imap_parse_list_response (IMAP_DATA * idata, char **name, int *noselect,
1371                               int *noinferiors, char *delim)
1372 {
1373   char *s;
1374   long bytes;
1375   int rc;
1376
1377   *name = NULL;
1378
1379   rc = imap_cmd_step (idata);
1380   if (rc == IMAP_CMD_OK)
1381     return 0;
1382   if (rc != IMAP_CMD_CONTINUE)
1383     return -1;
1384
1385   s = imap_next_word (idata->cmd.buf);
1386   if ((ascii_strncasecmp ("LIST", s, 4) == 0) ||
1387       (ascii_strncasecmp ("LSUB", s, 4) == 0)) {
1388     *noselect = 0;
1389     *noinferiors = 0;
1390
1391     s = imap_next_word (s);     /* flags */
1392     if (*s == '(') {
1393       char *ep;
1394
1395       s++;
1396       ep = s;
1397       while (*ep && *ep != ')')
1398         ep++;
1399       do {
1400         if (!ascii_strncasecmp (s, "\\NoSelect", 9))
1401           *noselect = 1;
1402         if (!ascii_strncasecmp (s, "\\NoInferiors", 12))
1403           *noinferiors = 1;
1404         /* See draft-gahrns-imap-child-mailbox-?? */
1405         if (!ascii_strncasecmp (s, "\\HasNoChildren", 14))
1406           *noinferiors = 1;
1407         if (*s != ')')
1408           s++;
1409         while (*s && *s != '\\' && *s != ')')
1410           s++;
1411       } while (s != ep);
1412     }
1413     else
1414       return 0;
1415     s = imap_next_word (s);     /* delim */
1416     /* Reset the delimiter, this can change */
1417     if (ascii_strncasecmp (s, "NIL", 3)) {
1418       if (s && s[0] == '\"' && s[1] && s[2] == '\"')
1419         *delim = s[1];
1420       else if (s && s[0] == '\"' && s[1] && s[1] == '\\' && s[2]
1421                && s[3] == '\"')
1422         *delim = s[2];
1423     }
1424     s = imap_next_word (s);     /* name */
1425     if (s && *s == '{') {       /* Literal */
1426       if (imap_get_literal_count (idata->cmd.buf, &bytes) < 0)
1427         return -1;
1428       if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE)
1429         return -1;
1430       *name = idata->cmd.buf;
1431     }
1432     else
1433       *name = s;
1434   }
1435
1436   return 0;
1437 }
1438
1439 int imap_subscribe (char *path, int subscribe)
1440 {
1441   CONNECTION *conn;
1442   IMAP_DATA *idata;
1443   char buf[LONG_STRING];
1444   char mbox[LONG_STRING];
1445   char errstr[STRING];
1446   BUFFER err, token;
1447   IMAP_MBOX mx;
1448
1449   if (mx_get_magic (path) != M_IMAP || imap_parse_path (path, &mx) < 0) {
1450     mutt_error (_("Bad mailbox name"));
1451     return -1;
1452   }
1453
1454   if (!(idata = imap_conn_find (&(mx.account), 0)))
1455     goto fail;
1456
1457   conn = idata->conn;
1458
1459   imap_fix_path (idata, mx.mbox, buf, sizeof (buf));
1460
1461   if (option (OPTIMAPCHECKSUBSCRIBED)) {
1462     memset (&token, 0, sizeof (token));
1463     err.data = errstr;
1464     err.dsize = sizeof (errstr);
1465     snprintf (mbox, sizeof (mbox), "%smailboxes \"%s\"",
1466               subscribe ? "" : "un", path);
1467     if (mutt_parse_rc_line (mbox, &token, &err))
1468       debug_print (1, ("Error adding subscribed mailbox: %s\n", errstr));
1469     p_delete(&token.data);
1470   }
1471
1472   if (subscribe)
1473     mutt_message (_("Subscribing to %s..."), buf);
1474   else
1475     mutt_message (_("Unsubscribing to %s..."), buf);
1476   imap_munge_mbox_name (mbox, sizeof (mbox), buf);
1477
1478   snprintf (buf, sizeof (buf), "%sSUBSCRIBE %s", subscribe ? "" : "UN", mbox);
1479
1480   if (imap_exec (idata, buf, 0) < 0)
1481     goto fail;
1482
1483   p_delete(&mx.mbox);
1484   return 0;
1485
1486 fail:
1487   p_delete(&mx.mbox);
1488   return -1;
1489 }
1490
1491 /* trim dest to the length of the longest prefix it shares with src,
1492  * returning the length of the trimmed string */
1493 static int longest_common_prefix (char *dest, const char* src,
1494                                   int start, size_t dlen) {
1495   int pos = start;
1496
1497   while (pos < dlen && dest[pos] && dest[pos] == src[pos])
1498     pos++;
1499   dest[pos] = '\0';
1500
1501   return pos;
1502 }
1503
1504 /* look for IMAP URLs to complete from defined mailboxes. Could be extended
1505  * to complete over open connections and account/folder hooks too. */
1506 static int imap_complete_hosts (char *dest, size_t len) {
1507   BUFFY* mailbox;
1508   CONNECTION* conn;
1509   int rc = -1;
1510   int matchlen;
1511   int i = 0;
1512
1513   matchlen = str_len (dest);
1514   if (list_empty (Incoming))
1515     return (-1);
1516   for (i = 0; i < Incoming->length; i++) {
1517     mailbox = (BUFFY*) Incoming->data[i];
1518     if (!str_ncmp (dest, mailbox->path, matchlen)) {
1519       if (rc) {
1520         strfcpy (dest, mailbox->path, len);
1521         rc = 0;
1522       } else
1523         longest_common_prefix (dest, mailbox->path, matchlen, len);
1524     }
1525   }
1526
1527   for (conn = mutt_socket_head (); conn && conn->next; conn = conn->next) {
1528     ciss_url_t url;
1529     char urlstr[LONG_STRING];
1530
1531     if (conn->account.type != M_ACCT_TYPE_IMAP)
1532       continue;
1533
1534     mutt_account_tourl (&conn->account, &url);
1535     /* FIXME: how to handle multiple users on the same host? */
1536     url.user = NULL;
1537     url.path = NULL;
1538     url_ciss_tostring (&url, urlstr, sizeof (urlstr), 0);
1539     if (!str_ncmp (dest, urlstr, matchlen)) {
1540       if (rc) {
1541         strfcpy (dest, urlstr, len);
1542         rc = 0;
1543       } else
1544         longest_common_prefix (dest, urlstr, matchlen, len);
1545     }
1546   }
1547
1548   return rc;
1549 }
1550
1551 /* imap_complete: given a partial IMAP folder path, return a string which
1552  *   adds as much to the path as is unique */
1553 int imap_complete (char *dest, size_t dlen, char *path) {
1554   CONNECTION *conn;
1555   IMAP_DATA *idata;
1556   char list[LONG_STRING];
1557   char buf[LONG_STRING];
1558   char *list_word = NULL;
1559   int noselect, noinferiors;
1560   char delim;
1561   char completion[LONG_STRING];
1562   int clen, matchlen = 0;
1563   int completions = 0;
1564   IMAP_MBOX mx;
1565
1566   if (imap_parse_path (path, &mx) || !mx.mbox) {
1567     strfcpy (dest, path, dlen);
1568     return imap_complete_hosts (dest, dlen);
1569   }
1570
1571   /* don't open a new socket just for completion. Instead complete over
1572    * known mailboxes/hooks/etc */
1573   if (!(idata = imap_conn_find (&(mx.account), M_IMAP_CONN_NONEW))) {
1574     p_delete(&mx.mbox);
1575     strfcpy (dest, path, dlen);
1576     return imap_complete_hosts (dest, dlen);
1577   }
1578   conn = idata->conn;
1579
1580   /* reformat path for IMAP list, and append wildcard */
1581   /* don't use INBOX in place of "" */
1582   if (mx.mbox && mx.mbox[0])
1583     imap_fix_path (idata, mx.mbox, list, sizeof (list));
1584   else
1585     list[0] = '\0';
1586
1587   /* fire off command */
1588   snprintf (buf, sizeof (buf), "%s \"\" \"%s%%\"",
1589             option (OPTIMAPLSUB) ? "LSUB" : "LIST", list);
1590
1591   imap_cmd_start (idata, buf);
1592
1593   /* and see what the results are */
1594   strfcpy (completion, NONULL (mx.mbox), sizeof (completion));
1595   do {
1596     if (imap_parse_list_response (idata, &list_word, &noselect, &noinferiors,
1597                                   &delim))
1598       break;
1599
1600     if (list_word) {
1601       /* store unquoted */
1602       imap_unmunge_mbox_name (list_word);
1603
1604       /* if the folder isn't selectable, append delimiter to force browse
1605        * to enter it on second tab. */
1606       if (noselect) {
1607         clen = str_len (list_word);
1608         list_word[clen++] = delim;
1609         list_word[clen] = '\0';
1610       }
1611       /* copy in first word */
1612       if (!completions) {
1613         strfcpy (completion, list_word, sizeof (completion));
1614         matchlen = str_len (completion);
1615         completions++;
1616         continue;
1617       }
1618
1619       matchlen = longest_common_prefix (completion, list_word, 0, matchlen);
1620       completions++;
1621     }
1622   }
1623   while (ascii_strncmp (idata->cmd.seq, idata->cmd.buf, SEQLEN));
1624
1625   if (completions) {
1626     /* reformat output */
1627     imap_qualify_path (dest, dlen, &mx, completion);
1628     mutt_pretty_mailbox (dest);
1629
1630     p_delete(&mx.mbox);
1631     return 0;
1632   }
1633
1634   return -1;
1635 }
1636
1637 /* reconnect if connection was lost */
1638 int imap_reconnect (CONTEXT * ctx)
1639 {
1640   IMAP_DATA *imap_data;
1641
1642   if (!ctx)
1643     return (-1);
1644
1645   imap_data = (IMAP_DATA *) ctx->data;
1646
1647   if (imap_data) {
1648     if (imap_data->status == IMAP_CONNECTED)
1649       return -1;
1650   }
1651
1652   if (query_quadoption
1653       (OPT_IMAPRECONNECT,
1654        _("Connection lost. Reconnect to IMAP server?")) != M_YES)
1655     return -1;
1656
1657   mx_open_mailbox (ctx->path, 0, ctx);
1658   return 0;
1659 }