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>
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.
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.
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.
21 /* Support for IMAP4rev1, with the occasional nod to IMAP 4. */
34 #include "imap_private.h"
36 # include "mutt_ssl.h"
47 #include <sys/types.h>
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);
56 /* imap_access: Check permissions on an IMAP mailbox.
57 * TODO: ACL checks. Right now we assume if it exists we can
59 int imap_access (const char* path, int flags)
63 char buf[LONG_STRING];
64 char mailbox[LONG_STRING];
65 char mbox[LONG_STRING];
68 if (imap_parse_path (path, &mx))
71 if (!(idata = imap_conn_find (&mx.account,
72 option (OPTIMAPPASSIVE) ? M_IMAP_CONN_NONEW : 0)))
78 imap_fix_path (idata, mx.mbox, mailbox, sizeof (mailbox));
80 /* we may already be in the folder we're checking */
81 if (!ascii_strcmp(idata->mailbox, mx.mbox))
88 if (imap_mboxcache_get (idata, mailbox, 0))
90 dprint (3, (debugfile, "imap_access: found %s in cache\n", mailbox));
94 imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
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);
102 dprint (2, (debugfile, "imap_access: STATUS not supported?\n"));
106 if ((rc = imap_exec (idata, buf, IMAP_CMD_FAIL_OK)) < 0)
108 dprint (1, (debugfile, "imap_access: Can't check STATUS of %s\n", mbox));
115 int imap_create_mailbox (IMAP_DATA* idata, char* mailbox)
117 char buf[LONG_STRING], mbox[LONG_STRING];
119 imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
120 snprintf (buf, sizeof (buf), "CREATE %s", mbox);
122 if (imap_exec (idata, buf, 0) != 0)
128 int imap_rename_mailbox (IMAP_DATA* idata, IMAP_MBOX* mx, const char* newname)
130 char oldmbox[LONG_STRING];
131 char newmbox[LONG_STRING];
132 char buf[LONG_STRING];
134 imap_munge_mbox_name (oldmbox, sizeof (oldmbox), mx->mbox);
135 imap_munge_mbox_name (newmbox, sizeof (newmbox), newname);
137 snprintf (buf, sizeof (buf), "RENAME %s %s", oldmbox, newmbox);
139 if (imap_exec (idata, buf, 0) != 0)
145 int imap_delete_mailbox (CONTEXT* ctx, IMAP_MBOX mx)
147 char buf[LONG_STRING], mbox[LONG_STRING];
150 if (!ctx || !ctx->data) {
151 if (!(idata = imap_conn_find (&mx.account,
152 option (OPTIMAPPASSIVE) ? M_IMAP_CONN_NONEW : 0)))
161 imap_munge_mbox_name (mbox, sizeof (mbox), mx.mbox);
162 snprintf (buf, sizeof (buf), "DELETE %s", mbox);
164 if (imap_exec ((IMAP_DATA*) idata, buf, 0) != 0)
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)
177 conn = mutt_socket_head ();
183 if (conn->account.type == M_ACCT_TYPE_IMAP && conn->fd >= 0)
185 mutt_message (_("Closing connection to %s..."), conn->account.host);
186 imap_logout ((IMAP_DATA*) conn->data);
188 mutt_socket_close (conn);
189 mutt_socket_free (conn);
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)
206 dprint (2, (debugfile, "imap_read_literal: reading %ld bytes\n", bytes));
208 for (pos = 0; pos < bytes; pos++)
210 if (mutt_socket_readchar (idata->conn, &c) != 1)
212 dprint (1, (debugfile, "imap_read_literal: error during read, %ld bytes read\n", pos));
213 idata->status = IMAP_FATAL;
219 if (r == 1 && c != '\n')
232 if (pbar && !(pos % 1024))
233 mutt_progress_update (pbar, pos, -1);
235 if (debuglevel >= IMAP_LOG_LTRL)
236 fputc (c, debugfile);
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)
252 idata->hcache = imap_hcache_open (idata, NULL);
255 for (i = 0; i < idata->ctx->msgcount; i++)
257 h = idata->ctx->hdrs[i];
261 dprint (2, (debugfile, "Expunging message UID %d.\n", HEADER_DATA (h)->uid));
264 idata->ctx->size -= h->content->length;
266 imap_cache_del (idata, h);
268 imap_hcache_del (idata, HEADER_DATA(h)->uid);
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)
276 unlink (idata->cache[cacheno].path);
277 FREE (&idata->cache[cacheno].path);
280 imap_free_header_data (&h->data);
285 imap_hcache_close (idata);
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);
294 /* imap_check_capabilities: make sure we can log in to this server. */
295 static int imap_check_capabilities (IMAP_DATA* idata)
297 if (imap_exec (idata, "CAPABILITY", 0) != 0)
299 imap_error ("imap_check_capabilities", idata->buf);
303 if (!(mutt_bit_isset(idata->capabilities,IMAP4)
304 ||mutt_bit_isset(idata->capabilities,IMAP4REV1)))
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 */
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)
319 CONNECTION* conn = NULL;
320 ACCOUNT* creds = NULL;
321 IMAP_DATA* idata = NULL;
324 while ((conn = mutt_conn_find (conn, account)))
327 creds = &conn->account;
329 memcpy (&conn->account, creds, sizeof (ACCOUNT));
331 idata = (IMAP_DATA*)conn->data;
332 if (flags & M_IMAP_CONN_NONEW)
336 /* This should only happen if we've come to the end of the list */
337 mutt_socket_free (conn);
340 else if (idata->state < IMAP_AUTHENTICATED)
343 if (flags & M_IMAP_CONN_NOSELECT && idata && idata->state >= IMAP_SELECTED)
345 if (idata && idata->status == IMAP_FATAL)
350 return NULL; /* this happens when the initial connection fails */
354 /* The current connection is a new connection */
355 if (! (idata = imap_new_idata ()))
357 mutt_socket_free (conn);
366 if (idata->state == IMAP_DISCONNECTED)
367 imap_open_connection (idata);
368 if (idata->state == IMAP_CONNECTED)
370 if (!imap_authenticate (idata))
372 idata->state = IMAP_AUTHENTICATED;
374 if (idata->conn->ssf)
375 dprint (2, (debugfile, "Communication encrypted at %d bits\n",
379 mutt_account_unsetpass (&idata->conn->account);
381 FREE (&idata->capstr);
383 if (new && idata->state == IMAP_AUTHENTICATED)
385 /* capabilities may have changed */
386 imap_cmd_queue (idata, "CAPABILITY");
387 /* get root delimiter, '/' as default */
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);
399 int imap_open_connection (IMAP_DATA* idata)
401 char buf[LONG_STRING];
403 if (mutt_socket_open (idata->conn) < 0)
406 idata->state = IMAP_CONNECTED;
408 if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE)
410 imap_close_connection (idata);
414 if (ascii_strncasecmp ("* OK", idata->buf, 4) == 0)
416 if (ascii_strncasecmp ("* OK [CAPABILITY", idata->buf, 16)
417 && imap_check_capabilities (idata))
420 /* Attempt STARTTLS if available and desired. */
421 if (!idata->conn->ssf && (option(OPTSSLFORCETLS) ||
422 mutt_bit_isset (idata->capabilities, STARTTLS)))
426 if (option(OPTSSLFORCETLS))
428 else if ((rc = query_quadoption (OPT_SSLSTARTTLS,
429 _("Secure connection with TLS?"))) == -1)
432 if ((rc = imap_exec (idata, "STARTTLS", IMAP_CMD_FAIL_OK)) == -1)
436 if (mutt_ssl_starttls (idata->conn))
438 mutt_error (_("Could not negotiate TLS connection"));
444 /* RFC 2595 demands we recheck CAPABILITY after TLS completes. */
445 if (imap_exec (idata, "CAPABILITY", 0))
452 if (option(OPTSSLFORCETLS) && ! idata->conn->ssf)
454 mutt_error _("Encrypted connection unavailable");
460 else if (ascii_strncasecmp ("* PREAUTH", idata->buf, 9) == 0)
462 idata->state = IMAP_AUTHENTICATED;
463 if (imap_check_capabilities (idata) != 0)
465 FREE (&idata->capstr);
469 imap_error ("imap_open_connection()", buf);
477 imap_close_connection (idata);
480 FREE (&idata->capstr);
484 void imap_close_connection(IMAP_DATA* idata)
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);
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)
500 /* sanity-check string */
501 if (ascii_strncasecmp ("FLAGS", s, 5) != 0)
503 dprint (1, (debugfile, "imap_get_flags: not a FLAGS response: %s\n",
511 dprint (1, (debugfile, "imap_get_flags: bogus FLAGS response: %s\n",
516 /* create list, update caller's flags handle */
517 flags = mutt_new_list();
520 while (*s && *s != ')')
525 while (*s && (*s != ')') && !ISSPACE (*s))
530 mutt_add_list (flags, flag_word);
534 /* note bad flags response */
537 dprint (1, (debugfile,
538 "imap_get_flags: Unterminated FLAGS response: %s\n", s));
539 mutt_free_list (hflags);
549 int imap_open_mailbox (CONTEXT* ctx)
554 char buf[LONG_STRING];
555 char bufout[LONG_STRING];
560 if (imap_parse_path (ctx->path, &mx))
562 mutt_error (_("%s is an invalid IMAP path"), ctx->path);
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)))
569 if (idata->state < IMAP_AUTHENTICATED)
574 /* once again the context is new */
576 ctx->mx_close = imap_close_mailbox;
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);
585 ctx->path = safe_strdup (buf);
589 /* clear mailbox status */
591 memset (idata->ctx->rights, 0, sizeof (idata->ctx->rights));
592 idata->newMailCount = 0;
594 mutt_message (_("Selecting %s..."), idata->mailbox);
595 imap_munge_mbox_name (buf, sizeof(buf), idata->mailbox);
597 /* pipeline ACL test */
598 if (mutt_bit_isset (idata->capabilities, ACL))
600 snprintf (bufout, sizeof (bufout), "MYRIGHTS %s", buf);
601 imap_cmd_queue (idata, bufout);
603 /* assume we have all rights if ACL is unavailable */
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);
615 /* pipeline the postponed count if possible */
617 if (mx_is_imap (Postponed) && !imap_parse_path (Postponed, &pmx)
618 && mutt_account_match (&pmx.account, &mx.account))
619 imap_status (Postponed, 1);
622 snprintf (bufout, sizeof (bufout), "%s %s",
623 ctx->readonly ? "EXAMINE" : "SELECT", buf);
625 idata->state = IMAP_SELECTED;
627 imap_cmd_start (idata, bufout);
629 status = imap_mboxcache_get (idata, idata->mailbox, 1);
635 if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
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)
644 /* don't override PERMANENTFLAGS */
647 dprint (2, (debugfile, "Getting mailbox FLAGS\n"));
648 if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
652 /* PERMANENTFLAGS are massaged to look like FLAGS, then override FLAGS */
653 else if (ascii_strncasecmp ("OK [PERMANENTFLAGS", pc, 18) == 0)
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 */
660 if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
663 /* save UIDVALIDITY for the header cache */
664 else if (ascii_strncasecmp ("OK [UIDVALIDITY", pc, 14) == 0)
666 dprint (2, (debugfile, "Getting mailbox UIDVALIDITY\n"));
668 pc = imap_next_word (pc);
669 idata->uid_validity = strtol (pc, NULL, 10);
670 status->uidvalidity = idata->uid_validity;
672 else if (ascii_strncasecmp ("OK [UIDNEXT", pc, 11) == 0)
674 dprint (2, (debugfile, "Getting mailbox UIDNEXT\n"));
676 pc = imap_next_word (pc);
677 idata->uidnext = strtol (pc, NULL, 10);
678 status->uidnext = idata->uidnext;
682 pc = imap_next_word (pc);
683 if (!ascii_strncasecmp ("EXISTS", pc, 6))
685 count = idata->newMailCount;
686 idata->newMailCount = 0;
690 while (rc == IMAP_CMD_CONTINUE);
692 if (rc == IMAP_CMD_NO)
695 s = imap_next_word (idata->buf); /* skip seq */
696 s = imap_next_word (s); /* Skip response */
697 mutt_error ("%s", s);
702 if (rc != IMAP_CMD_OK)
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))
709 dprint (2, (debugfile, "Mailbox is read-only.\n"));
714 /* dump the mailbox flags we've found */
718 dprint (3, (debugfile, "No folder flags found\n"));
721 LIST* t = idata->flags;
723 dprint (3, (debugfile, "Mailbox flags: "));
728 dprint (3, (debugfile, "[%s] ", t->data));
731 dprint (3, (debugfile, "\n"));
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)))
743 ctx->hdrs = safe_calloc (count, sizeof (HEADER *));
744 ctx->v2r = safe_calloc (count, sizeof (int));
747 if (count && (imap_read_headers (idata, 0, count-1) < 0))
749 mutt_error _("Error opening mailbox");
754 dprint (2, (debugfile, "imap_open_mailbox: msgcount is %d\n", ctx->msgcount));
759 if (idata->state == IMAP_SELECTED)
760 idata->state = IMAP_AUTHENTICATED;
766 int imap_open_mailbox_append (CONTEXT *ctx)
770 char buf[LONG_STRING];
771 char mailbox[LONG_STRING];
775 if (imap_parse_path (ctx->path, &mx))
778 /* in APPEND mode, we appear to hijack an existing IMAP connection -
779 * ctx is brand new and mostly empty */
781 if (!(idata = imap_conn_find (&(mx.account), 0)))
792 imap_fix_path (idata, mx.mbox, mailbox, sizeof (mailbox));
795 /* really we should also check for W_OK */
796 if ((rc = imap_access (ctx->path, F_OK)) == 0)
802 snprintf (buf, sizeof (buf), _("Create %s?"), mailbox);
803 if (option (OPTCONFIRMCREATE) && mutt_yesorno (buf, 1) < 1)
806 if (imap_create_mailbox (idata, mailbox) < 0)
812 /* imap_logout: Gracefully log out of server. */
813 void imap_logout (IMAP_DATA* idata)
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)
823 mutt_bcache_close (&idata->bcache);
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)
832 if (mutt_bit_isset (idata->ctx->rights, aclbit))
833 if (flag && imap_has_flag (idata->flags, str))
834 safe_strcat (flags, flsize, str);
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)
844 flag_list = flag_list->next;
847 if (!ascii_strncasecmp (flag_list->data, flag, strlen (flag_list->data)))
850 if (!ascii_strncmp (flag_list->data, "\\*", strlen (flag_list->data)))
853 flag_list = flag_list->next;
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,
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 */
875 short oldsort; /* we clobber reverse, must restore it */
878 if (Sort != SORT_ORDER)
880 hdrs = safe_calloc (idata->ctx->msgcount, sizeof (HEADER*));
881 memcpy (hdrs, idata->ctx->hdrs, idata->ctx->msgcount * sizeof (HEADER*));
885 qsort ((void*) hdrs, idata->ctx->msgcount, sizeof (HEADER*),
886 mutt_get_sort_func (SORT_ORDER));
890 hdrs = idata->ctx->hdrs;
892 for (n = 0; n < idata->ctx->msgcount; n++)
895 /* don't include pending expunged messages */
900 if (hdrs[n]->deleted != HEADER_DATA(hdrs[n])->deleted)
901 match = invert ^ hdrs[n]->deleted;
904 if (hdrs[n]->flagged != HEADER_DATA(hdrs[n])->flagged)
905 match = invert ^ hdrs[n]->flagged;
908 if (hdrs[n]->old != HEADER_DATA(hdrs[n])->old)
909 match = invert ^ hdrs[n]->old;
912 if (hdrs[n]->read != HEADER_DATA(hdrs[n])->read)
913 match = invert ^ hdrs[n]->read;
916 if (hdrs[n]->replied != HEADER_DATA(hdrs[n])->replied)
917 match = invert ^ hdrs[n]->replied;
926 if (match && (!changed || hdrs[n]->changed))
931 setstart = HEADER_DATA (hdrs[n])->uid;
934 mutt_buffer_printf (buf, "%u", HEADER_DATA (hdrs[n])->uid);
938 mutt_buffer_printf (buf, ",%u", HEADER_DATA (hdrs[n])->uid);
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);
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))
948 if (HEADER_DATA (hdrs[n-1])->uid > setstart)
949 mutt_buffer_printf (buf, ":%u", HEADER_DATA (hdrs[n-1])->uid);
954 if (Sort != SORT_ORDER)
960 /* returns 0 if mutt's flags match cached server flags */
961 static int compare_flags (HEADER* h)
963 IMAP_HEADER_DATA* hd = (IMAP_HEADER_DATA*)h->data;
965 if (h->read != hd->read)
967 if (h->old != hd->old)
969 if (h->flagged != hd->flagged)
971 if (h->replied != hd->replied)
973 if (h->deleted != hd->deleted)
979 /* Update the IMAP server to reflect the flags a single message. */
981 int imap_sync_message (IMAP_DATA *idata, HEADER *hdr, BUFFER *cmd,
984 char flags[LONG_STRING];
989 if (!compare_flags (hdr))
991 idata->ctx->changed--;
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);
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));
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));
1017 mutt_remove_trailing_ws (flags);
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) */
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));
1029 mutt_remove_trailing_ws (flags);
1031 mutt_buffer_addstr (cmd, " -FLAGS.SILENT (");
1033 mutt_buffer_addstr (cmd, " FLAGS.SILENT (");
1035 mutt_buffer_addstr (cmd, flags);
1036 mutt_buffer_addstr (cmd, ")");
1038 /* dumb hack for bad UW-IMAP 4.7 servers spurious FLAGS updates */
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))
1046 *err_continue = imap_continue ("imap_sync_message: STORE failed",
1048 if (*err_continue != M_YES)
1053 idata->ctx->changed--;
1058 static int sync_helper (IMAP_DATA* idata, BUFFER* buf, int right, int flag,
1063 if (!mutt_bit_isset (idata->ctx->rights, right))
1066 if (right == M_ACL_WRITE && !imap_has_flag (idata->flags, name))
1069 buf->dptr = buf->data;
1070 mutt_buffer_addstr (buf, "UID STORE ");
1071 if (imap_make_msg_set (idata, buf, flag, 1, 0))
1074 mutt_buffer_printf (buf, " +FLAGS.SILENT (%s)", name);
1075 imap_cmd_queue (idata, buf->data);
1077 buf->dptr = buf->data;
1078 mutt_buffer_addstr (buf, "UID STORE ");
1079 if (imap_make_msg_set (idata, buf, flag, 1, 1))
1082 mutt_buffer_printf (buf, " -FLAGS.SILENT (%s)", name);
1083 imap_cmd_queue (idata, buf->data);
1089 /* update the IMAP server to reflect message changes done within mutt.
1091 * ctx: the current context
1092 * expunge: 0 or 1 - do expunge?
1094 int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint)
1097 CONTEXT* appendctx = NULL;
1100 HEADER** hdrs = NULL;
1106 idata = (IMAP_DATA*) ctx->data;
1108 if (idata->state < IMAP_SELECTED)
1110 dprint (2, (debugfile, "imap_sync_mailbox: no mailbox selected\n"));
1114 /* This function is only called when the calling code expects the context
1116 imap_allow_reopen (ctx);
1118 if ((rc = imap_check_mailbox (ctx, index_hint, 0)) != 0)
1121 memset (&cmd, 0, sizeof (cmd));
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))
1126 mutt_buffer_addstr (&cmd, "UID STORE ");
1127 deleted = imap_make_msg_set (idata, &cmd, M_DELETED, 1, 0);
1129 /* if we have a message set, then let's delete */
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)
1141 mutt_error (_("Expunge failed"));
1150 idata->hcache = imap_hcache_open (idata, NULL);
1153 /* save messages with real (non-flag) changes */
1154 for (n = 0; n < ctx->msgcount; n++)
1160 imap_cache_del (idata, h);
1162 imap_hcache_del (idata, HEADER_DATA(h)->uid);
1166 if (h->active && h->changed)
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)) ||
1174 mutt_message (_("Saving changed messages... [%d/%d]"), n+1,
1177 appendctx = mx_open_mailbox (ctx->path, M_APPEND | M_QUIET, NULL);
1180 dprint (1, (debugfile, "imap_sync_mailbox: Error opening mailbox in append mode\n"));
1183 _mutt_save_message (h, appendctx, 1, 0, 0);
1189 imap_hcache_close (idata);
1192 /* sync +/- flags for the five flags mutt cares about */
1195 /* presort here to avoid doing 10 resorts in imap_make_msg_set */
1197 if (Sort != SORT_ORDER)
1200 ctx->hdrs = safe_malloc (ctx->msgcount * sizeof (HEADER*));
1201 memcpy (ctx->hdrs, hdrs, ctx->msgcount * sizeof (HEADER*));
1205 qsort (ctx->hdrs, ctx->msgcount, sizeof (HEADER*),
1206 mutt_get_sort_func (SORT_ORDER));
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");
1215 if (oldsort != Sort)
1224 if ((rc = imap_exec (idata, NULL, 0)) != IMAP_CMD_OK)
1228 if (mutt_yesorno (_("Error saving flags. Close anyway?"), 0) == M_YES)
1231 idata->state = IMAP_AUTHENTICATED;
1236 mutt_error _("Error saving flags");
1240 for (n = 0; n < ctx->msgcount; n++)
1241 ctx->hdrs[n]->changed = 0;
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))
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)
1253 imap_error (_("imap_sync_mailbox: EXPUNGE failed"), idata->buf);
1259 if (expunge && ctx->closing)
1261 imap_cmd_queue (idata, "CLOSE");
1262 idata->state = IMAP_AUTHENTICATED;
1265 if (option (OPTMESSAGECACHECLEAN))
1266 imap_cache_clean (idata);
1275 mx_fastclose_mailbox (appendctx);
1281 /* imap_close_mailbox: clean up IMAP data in CONTEXT */
1282 int imap_close_mailbox (CONTEXT* ctx)
1287 idata = (IMAP_DATA*) ctx->data;
1288 /* Check to see if the mailbox is actually open */
1292 if (ctx == idata->ctx)
1294 if (idata->status != IMAP_FATAL && idata->state >= IMAP_SELECTED)
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 */
1299 imap_cmd_queue (idata, "CLOSE");
1300 if (idata->state == IMAP_IDLE)
1302 mutt_buffer_addstr (idata->cmdbuf, "DONE\r\n");
1303 idata->state = IMAP_SELECTED;
1305 idata->state = IMAP_AUTHENTICATED;
1308 idata->reopen &= IMAP_REOPEN_ALLOW;
1309 FREE (&(idata->mailbox));
1310 mutt_free_list (&idata->flags);
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));
1320 for (i = 0; i < IMAP_CACHE_LEN; i++)
1322 if (idata->cache[i].path)
1324 unlink (idata->cache[i].path);
1325 FREE (&idata->cache[i].path);
1329 mutt_bcache_close (&idata->bcache);
1334 /* use the NOOP or IDLE command to poll for new mail
1337 * M_REOPENED mailbox has been externally modified
1338 * M_NEW_MAIL new mail has arrived!
1342 int imap_check_mailbox (CONTEXT *ctx, int *index_hint, int force)
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. */
1349 idata = (IMAP_DATA*) ctx->data;
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))
1355 imap_cmd_start (idata, "IDLE");
1356 idata->state = IMAP_IDLE;
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)
1364 dprint (1, (debugfile, "Error starting IDLE\n"));
1365 idata->state = IMAP_SELECTED;
1369 if (idata->state == IMAP_IDLE)
1371 while ((result = mutt_socket_poll (idata->conn)) > 0)
1373 if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE)
1375 dprint (1, (debugfile, "Error reading IDLE response\n"));
1381 dprint (1, (debugfile, "Poll failed, disabling IDLE\n"));
1382 mutt_bit_unset (idata->capabilities, IDLE);
1387 (idata->state != IMAP_IDLE && time(NULL) >= idata->lastread + Timeout))
1388 && imap_exec (idata, "NOOP", 0) != 0)
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);
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)
1402 idata->check_status = 0;
1407 /* split path into (idata,mailbox name) */
1408 static int imap_get_mailbox (const char* path, IMAP_DATA** hidata, char* buf, size_t blen)
1412 if (imap_parse_path (path, &mx))
1414 dprint (1, (debugfile, "imap_get_mailbox: Error parsing %s\n", path));
1417 if (!(*hidata = imap_conn_find (&(mx.account), option (OPTIMAPPASSIVE) ? M_IMAP_CONN_NONEW : 0))
1418 || (*hidata)->state < IMAP_AUTHENTICATED)
1424 imap_fix_path (*hidata, mx.mbox, buf, blen);
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)
1436 IMAP_DATA* lastdata = NULL;
1438 char name[LONG_STRING];
1439 char command[LONG_STRING];
1440 char munged[LONG_STRING];
1443 for (mailbox = Incoming; mailbox; mailbox = mailbox->next)
1445 /* Init newly-added mailboxes */
1446 if (! mailbox->magic)
1448 if (mx_is_imap (mailbox->path))
1449 mailbox->magic = M_IMAP;
1452 if (mailbox->magic != M_IMAP)
1457 if (imap_get_mailbox (mailbox->path, &idata, name, sizeof (name)) < 0)
1460 /* Don't issue STATUS on the selected mailbox, it will be NOOPed or
1461 * IDLEd elsewhere */
1462 if (!imap_mxcmp (name, idata->mailbox))
1465 if (!mutt_bit_isset (idata->capabilities, IMAP4REV1) &&
1466 !mutt_bit_isset (idata->capabilities, STATUS))
1468 dprint (2, (debugfile, "Server doesn't support STATUS\n"));
1472 if (lastdata && idata != lastdata)
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"));
1485 imap_munge_mbox_name (munged, sizeof (munged), name);
1486 snprintf (command, sizeof (command),
1487 "STATUS %s (UIDNEXT UIDVALIDITY UNSEEN RECENT)", munged);
1489 if (imap_cmd_queue (idata, command) < 0)
1491 /* pipeline must be full, drain it */
1492 dprint (2, (debugfile, "IMAP command pipeline full, draining\n"));
1494 if (imap_exec (idata, NULL, IMAP_CMD_FAIL_OK) == -1)
1495 dprint (1, (debugfile, "Error polling mailboxes\n"));
1497 if (imap_cmd_queue (idata, command) < 0) {
1499 dprint (1, (debugfile, "Error queueing command\n"));
1505 if (lastdata && (imap_exec (lastdata, NULL, IMAP_CMD_FAIL_OK) == -1))
1507 dprint (1, (debugfile, "Error polling mailboxes\n"));
1511 /* collect results */
1512 for (mailbox = Incoming; mailbox; mailbox = mailbox->next)
1514 if (mailbox->magic == M_IMAP && mailbox->new)
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)
1526 static int queued = 0;
1529 char buf[LONG_STRING];
1530 char mbox[LONG_STRING];
1531 IMAP_STATUS* status;
1533 if (imap_get_mailbox (path, &idata, buf, sizeof (buf)) < 0)
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))
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);
1547 /* Server does not support STATUS, and this is not the current mailbox.
1548 * There is no lightweight way to check recent arrivals */
1553 imap_cmd_queue (idata, buf);
1558 imap_exec (idata, buf, 0);
1561 if ((status = imap_mboxcache_get (idata, mbox, 0)))
1562 return status->messages;
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)
1571 IMAP_STATUS* status;
1574 header_cache_t *hc = NULL;
1575 unsigned int *uidvalidity = NULL;
1576 unsigned int *uidnext = NULL;
1579 for (cur = idata->mboxcache; cur; cur = cur->next)
1581 status = (IMAP_STATUS*)cur->data;
1583 if (!imap_mxcmp (mbox, status->name))
1591 memset (&scache, 0, sizeof (scache));
1592 scache.name = (char*)mbox;
1593 idata->mboxcache = mutt_add_list_n (idata->mboxcache, &scache,
1595 status = imap_mboxcache_get (idata, mbox, 0);
1596 status->name = safe_strdup (mbox);
1600 hc = imap_hcache_open (idata, mbox);
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);
1610 FREE (&uidvalidity);
1612 return imap_mboxcache_get (idata, mbox, 1);
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));
1619 FREE (&uidvalidity);
1627 void imap_mboxcache_free (IMAP_DATA* idata)
1630 IMAP_STATUS* status;
1632 for (cur = idata->mboxcache; cur; cur = cur->next)
1634 status = (IMAP_STATUS*)cur->data;
1636 FREE (&status->name);
1639 mutt_free_list (&idata->mboxcache);
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)
1647 const pattern_t* pat;
1649 for (pat = search; pat; pat = pat->next)
1656 if (pat->stringmatch)
1660 if (pat->child && do_search (pat->child, 1))
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)
1676 if (! do_search (pat, 0))
1680 mutt_buffer_addstr (buf, "NOT ");
1686 if ((clauses = do_search (pat->child, 1)) > 0)
1688 const pattern_t* clause = pat->child;
1690 mutt_buffer_addch (buf, '(');
1694 if (do_search (clause, 0))
1696 if (pat->op == M_OR && clauses > 1)
1697 mutt_buffer_addstr (buf, "OR ");
1700 if (imap_compile_search (clause, buf) < 0)
1704 mutt_buffer_addch (buf, ' ');
1706 clause = clause->next;
1710 mutt_buffer_addch (buf, ')');
1721 mutt_buffer_addstr (buf, "HEADER ");
1723 /* extract header name */
1724 if (! (delim = strchr (pat->p.str, ':')))
1726 mutt_error (_("Header search without header name: %s"), pat->p.str);
1730 imap_quote_string (term, sizeof (term), pat->p.str);
1731 mutt_buffer_addstr (buf, term);
1732 mutt_buffer_addch (buf, ' ');
1738 imap_quote_string (term, sizeof (term), delim);
1739 mutt_buffer_addstr (buf, term);
1742 mutt_buffer_addstr (buf, "BODY ");
1743 imap_quote_string (term, sizeof (term), pat->p.str);
1744 mutt_buffer_addstr (buf, term);
1747 mutt_buffer_addstr (buf, "TEXT ");
1748 imap_quote_string (term, sizeof (term), pat->p.str);
1749 mutt_buffer_addstr (buf, term);
1757 int imap_search (CONTEXT* ctx, const pattern_t* pat)
1760 IMAP_DATA* idata = (IMAP_DATA*)ctx->data;
1763 for (i = 0; i < ctx->msgcount; i++)
1764 ctx->hdrs[i]->matched = 0;
1766 if (!do_search (pat, 1))
1769 memset (&buf, 0, sizeof (buf));
1770 mutt_buffer_addstr (&buf, "UID SEARCH ");
1771 if (imap_compile_search (pat, &buf) < 0)
1776 if (imap_exec (idata, buf.data, 0) < 0)
1786 int imap_subscribe (char *path, int subscribe)
1790 char buf[LONG_STRING];
1791 char mbox[LONG_STRING];
1792 char errstr[STRING];
1796 if (!mx_is_imap (path) || imap_parse_path (path, &mx) || !mx.mbox)
1798 mutt_error (_("Bad mailbox name"));
1801 if (!(idata = imap_conn_find (&(mx.account), 0)))
1806 imap_fix_path (idata, mx.mbox, buf, sizeof (buf));
1808 if (option (OPTIMAPCHECKSUBSCRIBED))
1810 memset (&token, 0, sizeof (token));
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));
1821 mutt_message (_("Subscribing to %s..."), buf);
1823 mutt_message (_("Unsubscribing from %s..."), buf);
1824 imap_munge_mbox_name (mbox, sizeof(mbox), buf);
1826 snprintf (buf, sizeof (buf), "%sSUBSCRIBE %s", subscribe ? "" : "UN", mbox);
1828 if (imap_exec (idata, buf, 0) < 0)
1831 imap_unmunge_mbox_name(mx.mbox);
1833 mutt_message (_("Subscribed to %s"), mx.mbox);
1835 mutt_message (_("Unsubscribed from %s"), mx.mbox);
1844 /* trim dest to the length of the longest prefix it shares with src,
1845 * returning the length of the trimmed string */
1847 longest_common_prefix (char *dest, const char* src, int start, size_t dlen)
1851 while (pos < dlen && dest[pos] && dest[pos] == src[pos])
1858 /* look for IMAP URLs to complete from defined mailboxes. Could be extended
1859 * to complete over open connections and account/folder hooks too. */
1861 imap_complete_hosts (char *dest, size_t len)
1868 matchlen = mutt_strlen (dest);
1869 for (mailbox = Incoming; mailbox; mailbox = mailbox->next)
1871 if (!mutt_strncmp (dest, mailbox->path, matchlen))
1875 strfcpy (dest, mailbox->path, len);
1879 longest_common_prefix (dest, mailbox->path, matchlen, len);
1883 for (conn = mutt_socket_head (); conn; conn = conn->next)
1886 char urlstr[LONG_STRING];
1888 if (conn->account.type != M_ACCT_TYPE_IMAP)
1891 mutt_account_tourl (&conn->account, &url);
1892 /* FIXME: how to handle multiple users on the same host? */
1895 url_ciss_tostring (&url, urlstr, sizeof (urlstr), 0);
1896 if (!mutt_strncmp (dest, urlstr, matchlen))
1900 strfcpy (dest, urlstr, len);
1904 longest_common_prefix (dest, urlstr, matchlen, len);
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) {
1916 char list[LONG_STRING];
1917 char buf[LONG_STRING];
1919 char completion[LONG_STRING];
1920 int clen, matchlen = 0;
1921 int completions = 0;
1925 if (imap_parse_path (path, &mx))
1927 strfcpy (dest, path, dlen);
1928 return imap_complete_hosts (dest, dlen);
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)))
1936 strfcpy (dest, path, dlen);
1937 return imap_complete_hosts (dest, dlen);
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));
1948 /* fire off command */
1949 snprintf (buf, sizeof(buf), "%s \"\" \"%s%%\"",
1950 option (OPTIMAPLSUB) ? "LSUB" : "LIST", list);
1952 imap_cmd_start (idata, buf);
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;
1960 listresp.name = NULL;
1961 rc = imap_cmd_step (idata);
1963 if (rc == IMAP_CMD_CONTINUE && listresp.name)
1965 /* if the folder isn't selectable, append delimiter to force browse
1966 * to enter it on second tab. */
1967 if (listresp.noselect)
1969 clen = strlen(listresp.name);
1970 listresp.name[clen++] = listresp.delim;
1971 listresp.name[clen] = '\0';
1973 /* copy in first word */
1976 strfcpy (completion, listresp.name, sizeof(completion));
1977 matchlen = strlen (completion);
1982 matchlen = longest_common_prefix (completion, listresp.name, 0, matchlen);
1986 while (rc == IMAP_CMD_CONTINUE);
1987 idata->cmddata = NULL;
1991 /* reformat output */
1992 imap_qualify_path (dest, dlen, &mx, completion);
1993 mutt_pretty_mailbox (dest);