2 * Copyright (C) 1996-8 Michael R. Elkins <me@mutt.org>
3 * Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
4 * Copyright (C) 1999-2009 Brendan Cully <brendan@kublai.com>
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 strfcpy (mailbox, "INBOX", sizeof (mailbox));
82 /* we may already be in the folder we're checking */
83 if (!ascii_strcmp(idata->mailbox, mx.mbox))
90 if (imap_mboxcache_get (idata, mailbox, 0))
92 dprint (3, (debugfile, "imap_access: found %s in cache\n", mailbox));
96 imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
98 if (mutt_bit_isset (idata->capabilities, IMAP4REV1))
99 snprintf (buf, sizeof (buf), "STATUS %s (UIDVALIDITY)", mbox);
100 else if (mutt_bit_isset (idata->capabilities, STATUS))
101 snprintf (buf, sizeof (buf), "STATUS %s (UID-VALIDITY)", mbox);
104 dprint (2, (debugfile, "imap_access: STATUS not supported?\n"));
108 if ((rc = imap_exec (idata, buf, IMAP_CMD_FAIL_OK)) < 0)
110 dprint (1, (debugfile, "imap_access: Can't check STATUS of %s\n", mbox));
117 int imap_create_mailbox (IMAP_DATA* idata, char* mailbox)
119 char buf[LONG_STRING], mbox[LONG_STRING];
121 imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
122 snprintf (buf, sizeof (buf), "CREATE %s", mbox);
124 if (imap_exec (idata, buf, 0) != 0)
126 mutt_error (_("CREATE failed: %s"), imap_cmd_trailer (idata));
133 int imap_rename_mailbox (IMAP_DATA* idata, IMAP_MBOX* mx, const char* newname)
135 char oldmbox[LONG_STRING];
136 char newmbox[LONG_STRING];
137 char buf[LONG_STRING];
139 imap_munge_mbox_name (oldmbox, sizeof (oldmbox), mx->mbox);
140 imap_munge_mbox_name (newmbox, sizeof (newmbox), newname);
142 snprintf (buf, sizeof (buf), "RENAME %s %s", oldmbox, newmbox);
144 if (imap_exec (idata, buf, 0) != 0)
150 int imap_delete_mailbox (CONTEXT* ctx, IMAP_MBOX mx)
152 char buf[LONG_STRING], mbox[LONG_STRING];
155 if (!ctx || !ctx->data) {
156 if (!(idata = imap_conn_find (&mx.account,
157 option (OPTIMAPPASSIVE) ? M_IMAP_CONN_NONEW : 0)))
166 imap_munge_mbox_name (mbox, sizeof (mbox), mx.mbox);
167 snprintf (buf, sizeof (buf), "DELETE %s", mbox);
169 if (imap_exec ((IMAP_DATA*) idata, buf, 0) != 0)
175 /* imap_logout_all: close all open connections. Quick and dirty until we can
176 * make sure we've got all the context we need. */
177 void imap_logout_all (void)
182 conn = mutt_socket_head ();
188 if (conn->account.type == M_ACCT_TYPE_IMAP && conn->fd >= 0)
190 mutt_message (_("Closing connection to %s..."), conn->account.host);
191 imap_logout ((IMAP_DATA**) (void*) &conn->data);
193 mutt_socket_close (conn);
194 mutt_socket_free (conn);
201 /* imap_read_literal: read bytes bytes from server into file. Not explicitly
202 * buffered, relies on FILE buffering. NOTE: strips \r from \r\n.
203 * Apparently even literals use \r\n-terminated strings ?! */
204 int imap_read_literal (FILE* fp, IMAP_DATA* idata, long bytes, progress_t* pbar)
211 dprint (2, (debugfile, "imap_read_literal: reading %ld bytes\n", bytes));
213 for (pos = 0; pos < bytes; pos++)
215 if (mutt_socket_readchar (idata->conn, &c) != 1)
217 dprint (1, (debugfile, "imap_read_literal: error during read, %ld bytes read\n", pos));
218 idata->status = IMAP_FATAL;
224 if (r == 1 && c != '\n')
237 if (pbar && !(pos % 1024))
238 mutt_progress_update (pbar, pos, -1);
240 if (debuglevel >= IMAP_LOG_LTRL)
241 fputc (c, debugfile);
248 /* imap_expunge_mailbox: Purge IMAP portion of expunged messages from the
249 * context. Must not be done while something has a handle on any headers
250 * (eg inside pager or editor). That is, check IMAP_REOPEN_ALLOW. */
251 void imap_expunge_mailbox (IMAP_DATA* idata)
257 idata->hcache = imap_hcache_open (idata, NULL);
260 for (i = 0; i < idata->ctx->msgcount; i++)
262 h = idata->ctx->hdrs[i];
266 dprint (2, (debugfile, "Expunging message UID %d.\n", HEADER_DATA (h)->uid));
269 idata->ctx->size -= h->content->length;
271 imap_cache_del (idata, h);
273 imap_hcache_del (idata, HEADER_DATA(h)->uid);
276 /* free cached body from disk, if necessary */
277 cacheno = HEADER_DATA(h)->uid % IMAP_CACHE_LEN;
278 if (idata->cache[cacheno].uid == HEADER_DATA(h)->uid &&
279 idata->cache[cacheno].path)
281 unlink (idata->cache[cacheno].path);
282 FREE (&idata->cache[cacheno].path);
285 imap_free_header_data (&h->data);
290 imap_hcache_close (idata);
293 /* We may be called on to expunge at any time. We can't rely on the caller
294 * to always know to rethread */
295 mx_update_tables (idata->ctx, 0);
296 mutt_sort_headers (idata->ctx, 1);
299 /* imap_check_capabilities: make sure we can log in to this server. */
300 static int imap_check_capabilities (IMAP_DATA* idata)
302 if (imap_exec (idata, "CAPABILITY", 0) != 0)
304 imap_error ("imap_check_capabilities", idata->buf);
308 if (!(mutt_bit_isset(idata->capabilities,IMAP4)
309 ||mutt_bit_isset(idata->capabilities,IMAP4REV1)))
311 mutt_error _("This IMAP server is ancient. Mutt does not work with it.");
312 mutt_sleep (2); /* pause a moment to let the user see the error */
320 /* imap_conn_find: Find an open IMAP connection matching account, or open
321 * a new one if none can be found. */
322 IMAP_DATA* imap_conn_find (const ACCOUNT* account, int flags)
324 CONNECTION* conn = NULL;
325 ACCOUNT* creds = NULL;
326 IMAP_DATA* idata = NULL;
329 while ((conn = mutt_conn_find (conn, account)))
332 creds = &conn->account;
334 memcpy (&conn->account, creds, sizeof (ACCOUNT));
336 idata = (IMAP_DATA*)conn->data;
337 if (flags & M_IMAP_CONN_NONEW)
341 /* This should only happen if we've come to the end of the list */
342 mutt_socket_free (conn);
345 else if (idata->state < IMAP_AUTHENTICATED)
348 if (flags & M_IMAP_CONN_NOSELECT && idata && idata->state >= IMAP_SELECTED)
350 if (idata && idata->status == IMAP_FATAL)
355 return NULL; /* this happens when the initial connection fails */
359 /* The current connection is a new connection */
360 if (! (idata = imap_new_idata ()))
362 mutt_socket_free (conn);
371 if (idata->state == IMAP_DISCONNECTED)
372 imap_open_connection (idata);
373 if (idata->state == IMAP_CONNECTED)
375 if (!imap_authenticate (idata))
377 idata->state = IMAP_AUTHENTICATED;
379 if (idata->conn->ssf)
380 dprint (2, (debugfile, "Communication encrypted at %d bits\n",
384 mutt_account_unsetpass (&idata->conn->account);
386 FREE (&idata->capstr);
388 if (new && idata->state == IMAP_AUTHENTICATED)
390 /* capabilities may have changed */
391 imap_exec (idata, "CAPABILITY", IMAP_CMD_QUEUE);
392 /* get root delimiter, '/' as default */
394 imap_exec (idata, "LIST \"\" \"\"", IMAP_CMD_QUEUE);
395 if (option (OPTIMAPCHECKSUBSCRIBED))
396 imap_exec (idata, "LSUB \"\" \"*\"", IMAP_CMD_QUEUE);
397 /* we may need the root delimiter before we open a mailbox */
398 imap_exec (idata, NULL, IMAP_CMD_FAIL_OK);
404 int imap_open_connection (IMAP_DATA* idata)
406 char buf[LONG_STRING];
408 if (mutt_socket_open (idata->conn) < 0)
411 idata->state = IMAP_CONNECTED;
413 if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE)
415 imap_close_connection (idata);
419 if (ascii_strncasecmp ("* OK", idata->buf, 4) == 0)
421 if (ascii_strncasecmp ("* OK [CAPABILITY", idata->buf, 16)
422 && imap_check_capabilities (idata))
425 /* Attempt STARTTLS if available and desired. */
426 if (!idata->conn->ssf && (option(OPTSSLFORCETLS) ||
427 mutt_bit_isset (idata->capabilities, STARTTLS)))
431 if (option(OPTSSLFORCETLS))
433 else if ((rc = query_quadoption (OPT_SSLSTARTTLS,
434 _("Secure connection with TLS?"))) == -1)
437 if ((rc = imap_exec (idata, "STARTTLS", IMAP_CMD_FAIL_OK)) == -1)
441 if (mutt_ssl_starttls (idata->conn))
443 mutt_error (_("Could not negotiate TLS connection"));
449 /* RFC 2595 demands we recheck CAPABILITY after TLS completes. */
450 if (imap_exec (idata, "CAPABILITY", 0))
457 if (option(OPTSSLFORCETLS) && ! idata->conn->ssf)
459 mutt_error _("Encrypted connection unavailable");
465 else if (ascii_strncasecmp ("* PREAUTH", idata->buf, 9) == 0)
467 idata->state = IMAP_AUTHENTICATED;
468 if (imap_check_capabilities (idata) != 0)
470 FREE (&idata->capstr);
474 imap_error ("imap_open_connection()", buf);
482 imap_close_connection (idata);
485 FREE (&idata->capstr);
489 void imap_close_connection(IMAP_DATA* idata)
491 mutt_socket_close (idata->conn);
492 idata->state = IMAP_DISCONNECTED;
493 idata->seqno = idata->nextcmd = idata->lastcmd = idata->status = 0;
494 memset (idata->cmds, 0, sizeof (IMAP_COMMAND) * idata->cmdslots);
497 /* imap_get_flags: Make a simple list out of a FLAGS response.
498 * return stream following FLAGS response */
499 static char* imap_get_flags (LIST** hflags, char* s)
505 /* sanity-check string */
506 if (ascii_strncasecmp ("FLAGS", s, 5) != 0)
508 dprint (1, (debugfile, "imap_get_flags: not a FLAGS response: %s\n",
516 dprint (1, (debugfile, "imap_get_flags: bogus FLAGS response: %s\n",
521 /* create list, update caller's flags handle */
522 flags = mutt_new_list();
525 while (*s && *s != ')')
530 while (*s && (*s != ')') && !ISSPACE (*s))
535 mutt_add_list (flags, flag_word);
539 /* note bad flags response */
542 dprint (1, (debugfile,
543 "imap_get_flags: Unterminated FLAGS response: %s\n", s));
544 mutt_free_list (hflags);
554 int imap_open_mailbox (CONTEXT* ctx)
559 char buf[LONG_STRING];
560 char bufout[LONG_STRING];
565 if (imap_parse_path (ctx->path, &mx))
567 mutt_error (_("%s is an invalid IMAP path"), ctx->path);
571 /* we require a connection which isn't currently in IMAP_SELECTED state */
572 if (!(idata = imap_conn_find (&(mx.account), M_IMAP_CONN_NOSELECT)))
574 if (idata->state < IMAP_AUTHENTICATED)
579 /* once again the context is new */
581 ctx->mx_close = imap_close_mailbox;
583 /* Clean up path and replace the one in the ctx */
584 imap_fix_path (idata, mx.mbox, buf, sizeof (buf));
586 strfcpy (buf, "INBOX", sizeof (buf));
587 FREE(&(idata->mailbox));
588 idata->mailbox = safe_strdup (buf);
589 imap_qualify_path (buf, sizeof (buf), &mx, idata->mailbox);
592 ctx->path = safe_strdup (buf);
596 /* clear mailbox status */
598 memset (idata->ctx->rights, 0, sizeof (idata->ctx->rights));
599 idata->newMailCount = 0;
601 mutt_message (_("Selecting %s..."), idata->mailbox);
602 imap_munge_mbox_name (buf, sizeof(buf), idata->mailbox);
604 /* pipeline ACL test */
605 if (mutt_bit_isset (idata->capabilities, ACL))
607 snprintf (bufout, sizeof (bufout), "MYRIGHTS %s", buf);
608 imap_exec (idata, bufout, IMAP_CMD_QUEUE);
610 /* assume we have all rights if ACL is unavailable */
613 mutt_bit_set (idata->ctx->rights, M_ACL_LOOKUP);
614 mutt_bit_set (idata->ctx->rights, M_ACL_READ);
615 mutt_bit_set (idata->ctx->rights, M_ACL_SEEN);
616 mutt_bit_set (idata->ctx->rights, M_ACL_WRITE);
617 mutt_bit_set (idata->ctx->rights, M_ACL_INSERT);
618 mutt_bit_set (idata->ctx->rights, M_ACL_POST);
619 mutt_bit_set (idata->ctx->rights, M_ACL_CREATE);
620 mutt_bit_set (idata->ctx->rights, M_ACL_DELETE);
622 /* pipeline the postponed count if possible */
624 if (mx_is_imap (Postponed) && !imap_parse_path (Postponed, &pmx)
625 && mutt_account_match (&pmx.account, &mx.account))
626 imap_status (Postponed, 1);
629 snprintf (bufout, sizeof (bufout), "%s %s",
630 ctx->readonly ? "EXAMINE" : "SELECT", buf);
632 idata->state = IMAP_SELECTED;
634 imap_cmd_start (idata, bufout);
636 status = imap_mboxcache_get (idata, idata->mailbox, 1);
642 if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
647 /* Obtain list of available flags here, may be overridden by a
648 * PERMANENTFLAGS tag in the OK response */
649 if (ascii_strncasecmp ("FLAGS", pc, 5) == 0)
651 /* don't override PERMANENTFLAGS */
654 dprint (3, (debugfile, "Getting mailbox FLAGS\n"));
655 if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
659 /* PERMANENTFLAGS are massaged to look like FLAGS, then override FLAGS */
660 else if (ascii_strncasecmp ("OK [PERMANENTFLAGS", pc, 18) == 0)
662 dprint (3, (debugfile, "Getting mailbox PERMANENTFLAGS\n"));
663 /* safe to call on NULL */
664 mutt_free_list (&(idata->flags));
665 /* skip "OK [PERMANENT" so syntax is the same as FLAGS */
667 if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
670 /* save UIDVALIDITY for the header cache */
671 else if (ascii_strncasecmp ("OK [UIDVALIDITY", pc, 14) == 0)
673 dprint (3, (debugfile, "Getting mailbox UIDVALIDITY\n"));
675 pc = imap_next_word (pc);
676 idata->uid_validity = strtol (pc, NULL, 10);
677 status->uidvalidity = idata->uid_validity;
679 else if (ascii_strncasecmp ("OK [UIDNEXT", pc, 11) == 0)
681 dprint (3, (debugfile, "Getting mailbox UIDNEXT\n"));
683 pc = imap_next_word (pc);
684 idata->uidnext = strtol (pc, NULL, 10);
685 status->uidnext = idata->uidnext;
689 pc = imap_next_word (pc);
690 if (!ascii_strncasecmp ("EXISTS", pc, 6))
692 count = idata->newMailCount;
693 idata->newMailCount = 0;
697 while (rc == IMAP_CMD_CONTINUE);
699 if (rc == IMAP_CMD_NO)
702 s = imap_next_word (idata->buf); /* skip seq */
703 s = imap_next_word (s); /* Skip response */
704 mutt_error ("%s", s);
709 if (rc != IMAP_CMD_OK)
712 /* check for READ-ONLY notification */
713 if (!ascii_strncasecmp (imap_get_qualifier (idata->buf), "[READ-ONLY]", 11) \
714 && !mutt_bit_isset (idata->capabilities, ACL))
716 dprint (2, (debugfile, "Mailbox is read-only.\n"));
721 /* dump the mailbox flags we've found */
725 dprint (3, (debugfile, "No folder flags found\n"));
728 LIST* t = idata->flags;
730 dprint (3, (debugfile, "Mailbox flags: "));
735 dprint (3, (debugfile, "[%s] ", t->data));
738 dprint (3, (debugfile, "\n"));
743 if (!(mutt_bit_isset(idata->ctx->rights, M_ACL_DELETE) ||
744 mutt_bit_isset(idata->ctx->rights, M_ACL_SEEN) ||
745 mutt_bit_isset(idata->ctx->rights, M_ACL_WRITE) ||
746 mutt_bit_isset(idata->ctx->rights, M_ACL_INSERT)))
750 ctx->hdrs = safe_calloc (count, sizeof (HEADER *));
751 ctx->v2r = safe_calloc (count, sizeof (int));
754 if (count && (imap_read_headers (idata, 0, count-1) < 0))
756 mutt_error _("Error opening mailbox");
761 dprint (2, (debugfile, "imap_open_mailbox: msgcount is %d\n", ctx->msgcount));
766 if (idata->state == IMAP_SELECTED)
767 idata->state = IMAP_AUTHENTICATED;
773 int imap_open_mailbox_append (CONTEXT *ctx)
777 char buf[LONG_STRING];
778 char mailbox[LONG_STRING];
782 if (imap_parse_path (ctx->path, &mx))
785 /* in APPEND mode, we appear to hijack an existing IMAP connection -
786 * ctx is brand new and mostly empty */
788 if (!(idata = imap_conn_find (&(mx.account), 0)))
799 imap_fix_path (idata, mx.mbox, mailbox, sizeof (mailbox));
801 strfcpy (mailbox, "INBOX", sizeof (mailbox));
804 /* really we should also check for W_OK */
805 if ((rc = imap_access (ctx->path, F_OK)) == 0)
811 snprintf (buf, sizeof (buf), _("Create %s?"), mailbox);
812 if (option (OPTCONFIRMCREATE) && mutt_yesorno (buf, 1) < 1)
815 if (imap_create_mailbox (idata, mailbox) < 0)
821 /* imap_logout: Gracefully log out of server. */
822 void imap_logout (IMAP_DATA** idata)
824 /* we set status here to let imap_handle_untagged know we _expect_ to
825 * receive a bye response (so it doesn't freak out and close the conn) */
826 (*idata)->status = IMAP_BYE;
827 imap_cmd_start (*idata, "LOGOUT");
828 while (imap_cmd_step (*idata) == IMAP_CMD_CONTINUE)
831 imap_free_idata (idata);
834 /* imap_set_flag: append str to flags if we currently have permission
835 * according to aclbit */
836 static void imap_set_flag (IMAP_DATA* idata, int aclbit, int flag,
837 const char *str, char *flags, size_t flsize)
839 if (mutt_bit_isset (idata->ctx->rights, aclbit))
840 if (flag && imap_has_flag (idata->flags, str))
841 safe_strcat (flags, flsize, str);
844 /* imap_has_flag: do a caseless comparison of the flag against a flag list,
845 * return 1 if found or flag list has '\*', 0 otherwise */
846 int imap_has_flag (LIST* flag_list, const char* flag)
851 flag_list = flag_list->next;
854 if (!ascii_strncasecmp (flag_list->data, flag, strlen (flag_list->data)))
857 if (!ascii_strncmp (flag_list->data, "\\*", strlen (flag_list->data)))
860 flag_list = flag_list->next;
866 /* Note: headers must be in SORT_ORDER. See imap_exec_msgset for args.
867 * Pos is an opaque pointer a la strtok. It should be 0 at first call. */
868 static int imap_make_msg_set (IMAP_DATA* idata, BUFFER* buf, int flag,
869 int changed, int invert, int* pos)
871 HEADER** hdrs = idata->ctx->hdrs;
872 int count = 0; /* number of messages in message set */
873 int match = 0; /* whether current message matches flag condition */
874 unsigned int setstart = 0; /* start of current message range */
878 hdrs = idata->ctx->hdrs;
881 n < idata->ctx->msgcount && buf->dptr - buf->data < IMAP_MAX_CMDLEN;
885 /* don't include pending expunged messages */
890 if (hdrs[n]->deleted != HEADER_DATA(hdrs[n])->deleted)
891 match = invert ^ hdrs[n]->deleted;
894 if (hdrs[n]->flagged != HEADER_DATA(hdrs[n])->flagged)
895 match = invert ^ hdrs[n]->flagged;
898 if (hdrs[n]->old != HEADER_DATA(hdrs[n])->old)
899 match = invert ^ hdrs[n]->old;
902 if (hdrs[n]->read != HEADER_DATA(hdrs[n])->read)
903 match = invert ^ hdrs[n]->read;
906 if (hdrs[n]->replied != HEADER_DATA(hdrs[n])->replied)
907 match = invert ^ hdrs[n]->replied;
916 if (match && (!changed || hdrs[n]->changed))
921 setstart = HEADER_DATA (hdrs[n])->uid;
924 mutt_buffer_printf (buf, "%u", HEADER_DATA (hdrs[n])->uid);
928 mutt_buffer_printf (buf, ",%u", HEADER_DATA (hdrs[n])->uid);
930 /* tie up if the last message also matches */
931 else if (n == idata->ctx->msgcount-1)
932 mutt_buffer_printf (buf, ":%u", HEADER_DATA (hdrs[n])->uid);
934 /* End current set if message doesn't match or we've reached the end
935 * of the mailbox via inactive messages following the last match. */
936 else if (setstart && (hdrs[n]->active || n == idata->ctx->msgcount-1))
938 if (HEADER_DATA (hdrs[n-1])->uid > setstart)
939 mutt_buffer_printf (buf, ":%u", HEADER_DATA (hdrs[n-1])->uid);
949 /* Prepares commands for all messages matching conditions (must be flushed
952 * idata: IMAP_DATA containing context containing header set
953 * pre, post: commands are of the form "%s %s %s %s", tag,
954 * pre, message set, post
955 * flag: enum of flag type on which to filter
956 * changed: include only changed messages in message set
957 * invert: invert sense of flag, eg M_READ matches unread messages
958 * Returns: number of matched messages, or -1 on failure */
959 int imap_exec_msgset (IMAP_DATA* idata, const char* pre, const char* post,
960 int flag, int changed, int invert)
962 HEADER** hdrs = NULL;
969 if (! (cmd = mutt_buffer_init (NULL)))
971 dprint (1, (debugfile, "imap_exec_msgset: unable to allocate buffer\n"));
975 /* We make a copy of the headers just in case resorting doesn't give
976 exactly the original order (duplicate messages?), because other parts of
977 the ctx are tied to the header order. This may be overkill. */
979 if (Sort != SORT_ORDER)
981 hdrs = idata->ctx->hdrs;
982 idata->ctx->hdrs = safe_malloc (idata->ctx->msgcount * sizeof (HEADER*));
983 memcpy (idata->ctx->hdrs, hdrs, idata->ctx->msgcount * sizeof (HEADER*));
986 qsort (idata->ctx->hdrs, idata->ctx->msgcount, sizeof (HEADER*),
987 mutt_get_sort_func (SORT_ORDER));
994 cmd->dptr = cmd->data;
995 mutt_buffer_printf (cmd, "%s ", pre);
996 rc = imap_make_msg_set (idata, cmd, flag, changed, invert, &pos);
999 mutt_buffer_printf (cmd, " %s", post);
1000 if (imap_exec (idata, cmd->data, IMAP_CMD_QUEUE))
1013 mutt_buffer_free (&cmd);
1014 if (oldsort != Sort)
1017 FREE (&idata->ctx->hdrs);
1018 idata->ctx->hdrs = hdrs;
1024 /* returns 0 if mutt's flags match cached server flags */
1025 static int compare_flags (HEADER* h)
1027 IMAP_HEADER_DATA* hd = (IMAP_HEADER_DATA*)h->data;
1029 if (h->read != hd->read)
1031 if (h->old != hd->old)
1033 if (h->flagged != hd->flagged)
1035 if (h->replied != hd->replied)
1037 if (h->deleted != hd->deleted)
1043 /* Update the IMAP server to reflect the flags a single message. */
1044 int imap_sync_message (IMAP_DATA *idata, HEADER *hdr, BUFFER *cmd,
1047 char flags[LONG_STRING];
1052 if (!compare_flags (hdr))
1054 idata->ctx->changed--;
1058 snprintf (uid, sizeof (uid), "%u", HEADER_DATA(hdr)->uid);
1059 cmd->dptr = cmd->data;
1060 mutt_buffer_addstr (cmd, "UID STORE ");
1061 mutt_buffer_addstr (cmd, uid);
1065 imap_set_flag (idata, M_ACL_SEEN, hdr->read, "\\Seen ",
1066 flags, sizeof (flags));
1067 imap_set_flag (idata, M_ACL_WRITE, hdr->old,
1068 "Old ", flags, sizeof (flags));
1069 imap_set_flag (idata, M_ACL_WRITE, hdr->flagged,
1070 "\\Flagged ", flags, sizeof (flags));
1071 imap_set_flag (idata, M_ACL_WRITE, hdr->replied,
1072 "\\Answered ", flags, sizeof (flags));
1073 imap_set_flag (idata, M_ACL_DELETE, hdr->deleted,
1074 "\\Deleted ", flags, sizeof (flags));
1076 /* now make sure we don't lose custom tags */
1077 if (mutt_bit_isset (idata->ctx->rights, M_ACL_WRITE))
1078 imap_add_keywords (flags, hdr, idata->flags, sizeof (flags));
1080 mutt_remove_trailing_ws (flags);
1082 /* UW-IMAP is OK with null flags, Cyrus isn't. The only solution is to
1083 * explicitly revoke all system flags (if we have permission) */
1086 imap_set_flag (idata, M_ACL_SEEN, 1, "\\Seen ", flags, sizeof (flags));
1087 imap_set_flag (idata, M_ACL_WRITE, 1, "Old ", flags, sizeof (flags));
1088 imap_set_flag (idata, M_ACL_WRITE, 1, "\\Flagged ", flags, sizeof (flags));
1089 imap_set_flag (idata, M_ACL_WRITE, 1, "\\Answered ", flags, sizeof (flags));
1090 imap_set_flag (idata, M_ACL_DELETE, 1, "\\Deleted ", flags, sizeof (flags));
1092 mutt_remove_trailing_ws (flags);
1094 mutt_buffer_addstr (cmd, " -FLAGS.SILENT (");
1096 mutt_buffer_addstr (cmd, " FLAGS.SILENT (");
1098 mutt_buffer_addstr (cmd, flags);
1099 mutt_buffer_addstr (cmd, ")");
1101 /* dumb hack for bad UW-IMAP 4.7 servers spurious FLAGS updates */
1104 /* after all this it's still possible to have no flags, if you
1105 * have no ACL rights */
1106 if (*flags && (imap_exec (idata, cmd->data, 0) != 0) &&
1107 err_continue && (*err_continue != M_YES))
1109 *err_continue = imap_continue ("imap_sync_message: STORE failed",
1111 if (*err_continue != M_YES)
1116 idata->ctx->changed--;
1121 static int sync_helper (IMAP_DATA* idata, int right, int flag, const char* name)
1126 char buf[LONG_STRING];
1128 if (!mutt_bit_isset (idata->ctx->rights, right))
1131 if (right == M_ACL_WRITE && !imap_has_flag (idata->flags, name))
1134 snprintf (buf, sizeof(buf), "+FLAGS.SILENT (%s)", name);
1135 if ((rc = imap_exec_msgset (idata, "UID STORE", buf, flag, 1, 0)) < 0)
1140 if ((rc = imap_exec_msgset (idata, "UID STORE", buf, flag, 1, 1)) < 0)
1147 /* update the IMAP server to reflect message changes done within mutt.
1149 * ctx: the current context
1150 * expunge: 0 or 1 - do expunge?
1152 int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint)
1155 CONTEXT* appendctx = NULL;
1157 HEADER** hdrs = NULL;
1162 idata = (IMAP_DATA*) ctx->data;
1164 if (idata->state < IMAP_SELECTED)
1166 dprint (2, (debugfile, "imap_sync_mailbox: no mailbox selected\n"));
1170 /* This function is only called when the calling code expects the context
1172 imap_allow_reopen (ctx);
1174 if ((rc = imap_check_mailbox (ctx, index_hint, 0)) != 0)
1177 /* if we are expunging anyway, we can do deleted messages very quickly... */
1178 if (expunge && mutt_bit_isset (idata->ctx->rights, M_ACL_DELETE))
1180 if ((rc = imap_exec_msgset (idata, "UID STORE", "+FLAGS.SILENT (\\Deleted)",
1181 M_DELETED, 1, 0)) < 0)
1183 mutt_error (_("Expunge failed"));
1190 /* mark these messages as unchanged so second pass ignores them. Done
1191 * here so BOGUS UW-IMAP 4.7 SILENT FLAGS updates are ignored. */
1192 for (n = 0; n < ctx->msgcount; n++)
1193 if (ctx->hdrs[n]->deleted && ctx->hdrs[n]->changed)
1194 ctx->hdrs[n]->active = 0;
1195 mutt_message (_("Marking %d messages deleted..."), rc);
1200 idata->hcache = imap_hcache_open (idata, NULL);
1203 /* save messages with real (non-flag) changes */
1204 for (n = 0; n < ctx->msgcount; n++)
1210 imap_cache_del (idata, h);
1212 imap_hcache_del (idata, HEADER_DATA(h)->uid);
1216 if (h->active && h->changed)
1218 /* if the message has been rethreaded or attachments have been deleted
1219 * we delete the message and reupload it.
1220 * This works better if we're expunging, of course. */
1221 if ((h->env && (h->env->refs_changed || h->env->irt_changed)) ||
1224 mutt_message (_("Saving changed messages... [%d/%d]"), n+1,
1227 appendctx = mx_open_mailbox (ctx->path, M_APPEND | M_QUIET, NULL);
1229 dprint (1, (debugfile, "imap_sync_mailbox: Error opening mailbox in append mode\n"));
1231 _mutt_save_message (h, appendctx, 1, 0, 0);
1237 imap_hcache_close (idata);
1240 /* sync +/- flags for the five flags mutt cares about */
1243 /* presort here to avoid doing 10 resorts in imap_exec_msgset */
1245 if (Sort != SORT_ORDER)
1248 ctx->hdrs = safe_malloc (ctx->msgcount * sizeof (HEADER*));
1249 memcpy (ctx->hdrs, hdrs, ctx->msgcount * sizeof (HEADER*));
1252 qsort (ctx->hdrs, ctx->msgcount, sizeof (HEADER*),
1253 mutt_get_sort_func (SORT_ORDER));
1256 rc += sync_helper (idata, M_ACL_DELETE, M_DELETED, "\\Deleted");
1257 rc += sync_helper (idata, M_ACL_WRITE, M_FLAG, "\\Flagged");
1258 rc += sync_helper (idata, M_ACL_WRITE, M_OLD, "Old");
1259 rc += sync_helper (idata, M_ACL_SEEN, M_READ, "\\Seen");
1260 rc += sync_helper (idata, M_ACL_WRITE, M_REPLIED, "\\Answered");
1262 if (oldsort != Sort)
1269 if (rc && (imap_exec (idata, NULL, 0) != IMAP_CMD_OK))
1273 if (mutt_yesorno (_("Error saving flags. Close anyway?"), 0) == M_YES)
1276 idata->state = IMAP_AUTHENTICATED;
1281 mutt_error _("Error saving flags");
1285 for (n = 0; n < ctx->msgcount; n++)
1286 ctx->hdrs[n]->changed = 0;
1289 /* We must send an EXPUNGE command if we're not closing. */
1290 if (expunge && !(ctx->closing) &&
1291 mutt_bit_isset(idata->ctx->rights, M_ACL_DELETE))
1293 mutt_message _("Expunging messages from server...");
1294 /* Set expunge bit so we don't get spurious reopened messages */
1295 idata->reopen |= IMAP_EXPUNGE_EXPECTED;
1296 if (imap_exec (idata, "EXPUNGE", 0) != 0)
1298 imap_error (_("imap_sync_mailbox: EXPUNGE failed"), idata->buf);
1304 if (expunge && ctx->closing)
1306 imap_exec (idata, "CLOSE", IMAP_CMD_QUEUE);
1307 idata->state = IMAP_AUTHENTICATED;
1310 if (option (OPTMESSAGECACHECLEAN))
1311 imap_cache_clean (idata);
1318 mx_fastclose_mailbox (appendctx);
1324 /* imap_close_mailbox: clean up IMAP data in CONTEXT */
1325 int imap_close_mailbox (CONTEXT* ctx)
1330 idata = (IMAP_DATA*) ctx->data;
1331 /* Check to see if the mailbox is actually open */
1335 if (ctx == idata->ctx)
1337 if (idata->status != IMAP_FATAL && idata->state >= IMAP_SELECTED)
1339 /* mx_close_mailbox won't sync if there are no deleted messages
1340 * and the mailbox is unchanged, so we may have to close here */
1342 imap_exec (idata, "CLOSE", IMAP_CMD_QUEUE);
1343 idata->state = IMAP_AUTHENTICATED;
1346 idata->reopen &= IMAP_REOPEN_ALLOW;
1347 FREE (&(idata->mailbox));
1348 mutt_free_list (&idata->flags);
1352 /* free IMAP part of headers */
1353 for (i = 0; i < ctx->msgcount; i++)
1354 /* mailbox may not have fully loaded */
1355 if (ctx->hdrs[i] && ctx->hdrs[i]->data)
1356 imap_free_header_data (&(ctx->hdrs[i]->data));
1358 for (i = 0; i < IMAP_CACHE_LEN; i++)
1360 if (idata->cache[i].path)
1362 unlink (idata->cache[i].path);
1363 FREE (&idata->cache[i].path);
1367 mutt_bcache_close (&idata->bcache);
1372 /* use the NOOP or IDLE command to poll for new mail
1375 * M_REOPENED mailbox has been externally modified
1376 * M_NEW_MAIL new mail has arrived!
1380 int imap_check_mailbox (CONTEXT *ctx, int *index_hint, int force)
1382 /* overload keyboard timeout to avoid many mailbox checks in a row.
1383 * Most users don't like having to wait exactly when they press a key. */
1387 idata = (IMAP_DATA*) ctx->data;
1389 /* try IDLE first, unless force is set */
1390 if (!force && option (OPTIMAPIDLE) && mutt_bit_isset (idata->capabilities, IDLE)
1391 && (idata->state != IMAP_IDLE || time(NULL) >= idata->lastread + ImapKeepalive))
1393 if (imap_cmd_idle (idata) < 0)
1396 if (idata->state == IMAP_IDLE)
1398 while ((result = mutt_socket_poll (idata->conn)) > 0)
1400 if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE)
1402 dprint (1, (debugfile, "Error reading IDLE response\n"));
1408 dprint (1, (debugfile, "Poll failed, disabling IDLE\n"));
1409 mutt_bit_unset (idata->capabilities, IDLE);
1414 (idata->state != IMAP_IDLE && time(NULL) >= idata->lastread + Timeout))
1415 && imap_exec (idata, "NOOP", 0) != 0)
1418 /* We call this even when we haven't run NOOP in case we have pending
1419 * changes to process, since we can reopen here. */
1420 imap_cmd_finish (idata);
1422 if (idata->check_status & IMAP_EXPUNGE_PENDING)
1423 result = M_REOPENED;
1424 else if (idata->check_status & IMAP_NEWMAIL_PENDING)
1425 result = M_NEW_MAIL;
1426 else if (idata->check_status & IMAP_FLAGS_PENDING)
1429 idata->check_status = 0;
1434 /* split path into (idata,mailbox name) */
1435 static int imap_get_mailbox (const char* path, IMAP_DATA** hidata, char* buf, size_t blen)
1439 if (imap_parse_path (path, &mx))
1441 dprint (1, (debugfile, "imap_get_mailbox: Error parsing %s\n", path));
1444 if (!(*hidata = imap_conn_find (&(mx.account), option (OPTIMAPPASSIVE) ? M_IMAP_CONN_NONEW : 0))
1445 || (*hidata)->state < IMAP_AUTHENTICATED)
1451 imap_fix_path (*hidata, mx.mbox, buf, blen);
1453 strfcpy (buf, "INBOX", blen);
1459 /* check for new mail in any subscribed mailboxes. Given a list of mailboxes
1460 * rather than called once for each so that it can batch the commands and
1461 * save on round trips. Returns number of mailboxes with new mail. */
1462 int imap_buffy_check (int force)
1465 IMAP_DATA* lastdata = NULL;
1467 char name[LONG_STRING];
1468 char command[LONG_STRING];
1469 char munged[LONG_STRING];
1472 for (mailbox = Incoming; mailbox; mailbox = mailbox->next)
1474 /* Init newly-added mailboxes */
1475 if (! mailbox->magic)
1477 if (mx_is_imap (mailbox->path))
1478 mailbox->magic = M_IMAP;
1481 if (mailbox->magic != M_IMAP)
1486 if (imap_get_mailbox (mailbox->path, &idata, name, sizeof (name)) < 0)
1489 /* Don't issue STATUS on the selected mailbox, it will be NOOPed or
1490 * IDLEd elsewhere */
1491 if (!imap_mxcmp (name, idata->mailbox))
1494 if (!mutt_bit_isset (idata->capabilities, IMAP4REV1) &&
1495 !mutt_bit_isset (idata->capabilities, STATUS))
1497 dprint (2, (debugfile, "Server doesn't support STATUS\n"));
1501 if (lastdata && idata != lastdata)
1503 /* Send commands to previous server. Sorting the buffy list
1504 * may prevent some infelicitous interleavings */
1505 if (imap_exec (lastdata, NULL, IMAP_CMD_FAIL_OK) == -1)
1506 dprint (1, (debugfile, "Error polling mailboxes\n"));
1514 imap_munge_mbox_name (munged, sizeof (munged), name);
1515 snprintf (command, sizeof (command),
1516 "STATUS %s (UIDNEXT UIDVALIDITY UNSEEN RECENT)", munged);
1518 if (imap_exec (idata, command, IMAP_CMD_QUEUE) < 0)
1520 dprint (1, (debugfile, "Error queueing command\n"));
1525 if (lastdata && (imap_exec (lastdata, NULL, IMAP_CMD_FAIL_OK) == -1))
1527 dprint (1, (debugfile, "Error polling mailboxes\n"));
1531 /* collect results */
1532 for (mailbox = Incoming; mailbox; mailbox = mailbox->next)
1534 if (mailbox->magic == M_IMAP && mailbox->new)
1541 /* imap_status: returns count of messages in mailbox, or -1 on error.
1542 * if queue != 0, queue the command and expect it to have been run
1543 * on the next call (for pipelining the postponed count) */
1544 int imap_status (char* path, int queue)
1546 static int queued = 0;
1549 char buf[LONG_STRING];
1550 char mbox[LONG_STRING];
1551 IMAP_STATUS* status;
1553 if (imap_get_mailbox (path, &idata, buf, sizeof (buf)) < 0)
1556 if (!imap_mxcmp (buf, idata->mailbox))
1557 /* We are in the folder we're polling - just return the mailbox count */
1558 return idata->ctx->msgcount;
1559 else if (mutt_bit_isset(idata->capabilities,IMAP4REV1) ||
1560 mutt_bit_isset(idata->capabilities,STATUS))
1562 imap_munge_mbox_name (mbox, sizeof(mbox), buf);
1563 snprintf (buf, sizeof (buf), "STATUS %s (%s)", mbox, "MESSAGES");
1564 imap_unmunge_mbox_name (mbox);
1567 /* Server does not support STATUS, and this is not the current mailbox.
1568 * There is no lightweight way to check recent arrivals */
1573 imap_exec (idata, buf, IMAP_CMD_QUEUE);
1578 imap_exec (idata, buf, 0);
1581 if ((status = imap_mboxcache_get (idata, mbox, 0)))
1582 return status->messages;
1587 /* return cached mailbox stats or NULL if create is 0 */
1588 IMAP_STATUS* imap_mboxcache_get (IMAP_DATA* idata, const char* mbox, int create)
1591 IMAP_STATUS* status;
1594 header_cache_t *hc = NULL;
1595 unsigned int *uidvalidity = NULL;
1596 unsigned int *uidnext = NULL;
1599 for (cur = idata->mboxcache; cur; cur = cur->next)
1601 status = (IMAP_STATUS*)cur->data;
1603 if (!imap_mxcmp (mbox, status->name))
1611 memset (&scache, 0, sizeof (scache));
1612 scache.name = (char*)mbox;
1613 idata->mboxcache = mutt_add_list_n (idata->mboxcache, &scache,
1615 status = imap_mboxcache_get (idata, mbox, 0);
1616 status->name = safe_strdup (mbox);
1620 hc = imap_hcache_open (idata, mbox);
1623 uidvalidity = mutt_hcache_fetch_raw (hc, "/UIDVALIDITY", imap_hcache_keylen);
1624 uidnext = mutt_hcache_fetch_raw (hc, "/UIDNEXT", imap_hcache_keylen);
1625 mutt_hcache_close (hc);
1630 FREE (&uidvalidity);
1632 return imap_mboxcache_get (idata, mbox, 1);
1634 status->uidvalidity = *uidvalidity;
1635 status->uidnext = uidnext ? *uidnext: 0;
1636 dprint (3, (debugfile, "mboxcache: hcache uidvalidity %d, uidnext %d\n",
1637 status->uidvalidity, status->uidnext));
1639 FREE (&uidvalidity);
1647 void imap_mboxcache_free (IMAP_DATA* idata)
1650 IMAP_STATUS* status;
1652 for (cur = idata->mboxcache; cur; cur = cur->next)
1654 status = (IMAP_STATUS*)cur->data;
1656 FREE (&status->name);
1659 mutt_free_list (&idata->mboxcache);
1662 /* returns number of patterns in the search that should be done server-side
1663 * (eg are full-text) */
1664 static int do_search (const pattern_t* search, int allpats)
1667 const pattern_t* pat;
1669 for (pat = search; pat; pat = pat->next)
1676 if (pat->stringmatch)
1680 if (pat->child && do_search (pat->child, 1))
1691 /* convert mutt pattern_t to IMAP SEARCH command containing only elements
1692 * that require full-text search (mutt already has what it needs for most
1693 * match types, and does a better job (eg server doesn't support regexps). */
1694 static int imap_compile_search (const pattern_t* pat, BUFFER* buf)
1696 if (! do_search (pat, 0))
1700 mutt_buffer_addstr (buf, "NOT ");
1706 if ((clauses = do_search (pat->child, 1)) > 0)
1708 const pattern_t* clause = pat->child;
1710 mutt_buffer_addch (buf, '(');
1714 if (do_search (clause, 0))
1716 if (pat->op == M_OR && clauses > 1)
1717 mutt_buffer_addstr (buf, "OR ");
1720 if (imap_compile_search (clause, buf) < 0)
1724 mutt_buffer_addch (buf, ' ');
1727 clause = clause->next;
1730 mutt_buffer_addch (buf, ')');
1741 mutt_buffer_addstr (buf, "HEADER ");
1743 /* extract header name */
1744 if (! (delim = strchr (pat->p.str, ':')))
1746 mutt_error (_("Header search without header name: %s"), pat->p.str);
1750 imap_quote_string (term, sizeof (term), pat->p.str);
1751 mutt_buffer_addstr (buf, term);
1752 mutt_buffer_addch (buf, ' ');
1758 imap_quote_string (term, sizeof (term), delim);
1759 mutt_buffer_addstr (buf, term);
1762 mutt_buffer_addstr (buf, "BODY ");
1763 imap_quote_string (term, sizeof (term), pat->p.str);
1764 mutt_buffer_addstr (buf, term);
1767 mutt_buffer_addstr (buf, "TEXT ");
1768 imap_quote_string (term, sizeof (term), pat->p.str);
1769 mutt_buffer_addstr (buf, term);
1777 int imap_search (CONTEXT* ctx, const pattern_t* pat)
1780 IMAP_DATA* idata = (IMAP_DATA*)ctx->data;
1783 for (i = 0; i < ctx->msgcount; i++)
1784 ctx->hdrs[i]->matched = 0;
1786 if (!do_search (pat, 1))
1789 memset (&buf, 0, sizeof (buf));
1790 mutt_buffer_addstr (&buf, "UID SEARCH ");
1791 if (imap_compile_search (pat, &buf) < 0)
1796 if (imap_exec (idata, buf.data, 0) < 0)
1806 int imap_subscribe (char *path, int subscribe)
1810 char buf[LONG_STRING];
1811 char mbox[LONG_STRING];
1812 char errstr[STRING];
1816 if (!mx_is_imap (path) || imap_parse_path (path, &mx) || !mx.mbox)
1818 mutt_error (_("Bad mailbox name"));
1821 if (!(idata = imap_conn_find (&(mx.account), 0)))
1826 imap_fix_path (idata, mx.mbox, buf, sizeof (buf));
1828 strfcpy (buf, "INBOX", sizeof (buf));
1830 if (option (OPTIMAPCHECKSUBSCRIBED))
1832 memset (&token, 0, sizeof (token));
1834 err.dsize = sizeof (errstr);
1835 snprintf (mbox, sizeof (mbox), "%smailboxes \"%s\"",
1836 subscribe ? "" : "un", path);
1837 if (mutt_parse_rc_line (mbox, &token, &err))
1838 dprint (1, (debugfile, "Error adding subscribed mailbox: %s\n", errstr));
1843 mutt_message (_("Subscribing to %s..."), buf);
1845 mutt_message (_("Unsubscribing from %s..."), buf);
1846 imap_munge_mbox_name (mbox, sizeof(mbox), buf);
1848 snprintf (buf, sizeof (buf), "%sSUBSCRIBE %s", subscribe ? "" : "UN", mbox);
1850 if (imap_exec (idata, buf, 0) < 0)
1853 imap_unmunge_mbox_name(mx.mbox);
1855 mutt_message (_("Subscribed to %s"), mx.mbox);
1857 mutt_message (_("Unsubscribed from %s"), mx.mbox);
1866 /* trim dest to the length of the longest prefix it shares with src,
1867 * returning the length of the trimmed string */
1869 longest_common_prefix (char *dest, const char* src, int start, size_t dlen)
1873 while (pos < dlen && dest[pos] && dest[pos] == src[pos])
1880 /* look for IMAP URLs to complete from defined mailboxes. Could be extended
1881 * to complete over open connections and account/folder hooks too. */
1883 imap_complete_hosts (char *dest, size_t len)
1890 matchlen = mutt_strlen (dest);
1891 for (mailbox = Incoming; mailbox; mailbox = mailbox->next)
1893 if (!mutt_strncmp (dest, mailbox->path, matchlen))
1897 strfcpy (dest, mailbox->path, len);
1901 longest_common_prefix (dest, mailbox->path, matchlen, len);
1905 for (conn = mutt_socket_head (); conn; conn = conn->next)
1908 char urlstr[LONG_STRING];
1910 if (conn->account.type != M_ACCT_TYPE_IMAP)
1913 mutt_account_tourl (&conn->account, &url);
1914 /* FIXME: how to handle multiple users on the same host? */
1917 url_ciss_tostring (&url, urlstr, sizeof (urlstr), 0);
1918 if (!mutt_strncmp (dest, urlstr, matchlen))
1922 strfcpy (dest, urlstr, len);
1926 longest_common_prefix (dest, urlstr, matchlen, len);
1933 /* imap_complete: given a partial IMAP folder path, return a string which
1934 * adds as much to the path as is unique */
1935 int imap_complete(char* dest, size_t dlen, char* path) {
1938 char list[LONG_STRING];
1939 char buf[LONG_STRING];
1941 char completion[LONG_STRING];
1942 int clen, matchlen = 0;
1943 int completions = 0;
1947 if (imap_parse_path (path, &mx))
1949 strfcpy (dest, path, dlen);
1950 return imap_complete_hosts (dest, dlen);
1953 /* don't open a new socket just for completion. Instead complete over
1954 * known mailboxes/hooks/etc */
1955 if (!(idata = imap_conn_find (&(mx.account), M_IMAP_CONN_NONEW)))
1958 strfcpy (dest, path, dlen);
1959 return imap_complete_hosts (dest, dlen);
1963 /* reformat path for IMAP list, and append wildcard */
1964 /* don't use INBOX in place of "" */
1965 if (mx.mbox && mx.mbox[0])
1966 imap_fix_path (idata, mx.mbox, list, sizeof(list));
1970 /* fire off command */
1971 snprintf (buf, sizeof(buf), "%s \"\" \"%s%%\"",
1972 option (OPTIMAPLSUB) ? "LSUB" : "LIST", list);
1974 imap_cmd_start (idata, buf);
1976 /* and see what the results are */
1977 strfcpy (completion, NONULL(mx.mbox), sizeof(completion));
1978 idata->cmdtype = IMAP_CT_LIST;
1979 idata->cmddata = &listresp;
1982 listresp.name = NULL;
1983 rc = imap_cmd_step (idata);
1985 if (rc == IMAP_CMD_CONTINUE && listresp.name)
1987 /* if the folder isn't selectable, append delimiter to force browse
1988 * to enter it on second tab. */
1989 if (listresp.noselect)
1991 clen = strlen(listresp.name);
1992 listresp.name[clen++] = listresp.delim;
1993 listresp.name[clen] = '\0';
1995 /* copy in first word */
1998 strfcpy (completion, listresp.name, sizeof(completion));
1999 matchlen = strlen (completion);
2004 matchlen = longest_common_prefix (completion, listresp.name, 0, matchlen);
2008 while (rc == IMAP_CMD_CONTINUE);
2009 idata->cmddata = NULL;
2013 /* reformat output */
2014 imap_qualify_path (dest, dlen, &mx, completion);
2015 mutt_pretty_mailbox (dest, dlen);