From e3da34fb74ef9deab3e6e3d1f155fc2402be2114 Mon Sep 17 00:00:00 2001 From: Thomas Roessler Date: Tue, 22 Feb 2000 16:53:44 +0000 Subject: [PATCH] Brendan Cully's latest IMAP browser fixes. --- browser.c | 14 +++++--- doc/manual.sgml.head | 8 ++--- imap/browse.c | 83 ++++++++++++++++++++++++++++++++++---------- 3 files changed, 77 insertions(+), 28 deletions(-) diff --git a/browser.c b/browser.c index 67b4ac43..7e88c859 100644 --- a/browser.c +++ b/browser.c @@ -209,9 +209,9 @@ folder_format_str (char *dest, size_t destlen, char op, const char *src, #ifdef USE_IMAP if (folder->ff->imap) { - sprintf (permission, "IMAP %c%c", - folder->ff->inferiors ? '+' : ' ', - folder->ff->selectable ? 'S' : ' '); + /* mark folders with subfolders AND mail */ + sprintf (permission, "IMAP %c", + (folder->ff->inferiors && folder->ff->selectable) ? '+' : ' '); snprintf (tmp, sizeof (tmp), "%%%ss", fmt); snprintf (dest, destlen, tmp, permission); } @@ -688,8 +688,12 @@ void _mutt_select_file (char *f, size_t flen, int buffy, strfcpy (LastDir, state.entry[menu->current].name, sizeof (LastDir)); /* tack on delimiter here */ - if ((state.entry[menu->current].delim != '\0') && - (n = strlen (LastDir)+1) < sizeof (LastDir)) + n = strlen (LastDir)+1; + + /* special case "" needs no delimiter */ + if ((strlen (strchr (LastDir, '}')) > 0) && + (state.entry[menu->current].delim != '\0') && + (n < sizeof (LastDir))) { LastDir[n] = '\0'; LastDir[n-1] = state.entry[menu->current].delim; diff --git a/doc/manual.sgml.head b/doc/manual.sgml.head index 9b935f34..b09e52c6 100644 --- a/doc/manual.sgml.head +++ b/doc/manual.sgml.head @@ -2041,11 +2041,9 @@ server. This is mostly the same as the local file browser, with the following differences: In lieu of file permissions, mutt displays the string "IMAP", - possibly followed by the symbol "S", indicating that the entry is - selectable (contains messages), and/or the symbol "+", indicating - that the entry may contain subfolders. If your server is like the - UW-IMAP server, you won't see both symbols, but if you are using a - Cyrus-like server folders will often contain both messages and + possibly followed by the symbol the symbol "+", indicating + that the entry contains both messages and subfolders. On + Cyrus-like servers folders will often contain both messages and subfolders. For the case where an entry can contain both messages and subfolders, the selection key (bound to enter by default) diff --git a/imap/browse.c b/imap/browse.c index f49fa372..0d9a0c8c 100644 --- a/imap/browse.c +++ b/imap/browse.c @@ -1,6 +1,6 @@ /* * Copyright (C) 1996-9 Brandon Long - * Copyright (C) 1999 Brendan Cully + * Copyright (C) 1999-2000 Brendan Cully * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -79,24 +79,29 @@ int imap_init_browse (char *path, struct browser_state *state) idata->conn = conn; } if (imap_open_connection (idata, conn)) - return (-1); + return -1; } if (mx.mbox[0] == '\0') { home_namespace = 1; - mbox[0] = 0; /* Do not replace "" with "INBOX" here */ + mbox[0] = '\0'; /* Do not replace "" with "INBOX" here */ mx.mbox = ImapHomeNamespace; nns = 0; if (mutt_bit_isset(idata->capabilities,NAMESPACE)) { + mutt_message _("Getting namespaces..."); if (get_namespace (idata, nsbuf, sizeof (nsbuf), nsi, sizeof (nsi), &nns) != 0) - return (-1); + return -1; if (verify_namespace (conn, nsi, nns) != 0) - return (-1); + return -1; } - if (!mx.mbox) /* Any explicitly set imap_home_namespace wins */ + /* What if you have a shared namespace of ""? You'll never be + * able to browse it. This isn't conjecture: connect to the Cyrus + * reference server (cyrus.andrew.cmu.edu) as anonymous. argh! */ +#if 0 + if (!mx.mbox) /* Any explicitly set imap_home_namespace wins */ { for (i = 0; i < nns; i++) if (nsi[i].listable && @@ -107,10 +112,14 @@ int imap_init_browse (char *path, struct browser_state *state) break; } } + else + dprint (4, (debugfile, "Home namespace: %s\n", mx.mbox)); +#endif } - mutt_message _("Contacted server, getting folder list..."); + mutt_message _("Getting folder list..."); + /* skip check for parents when at the root */ if (mx.mbox && mx.mbox[0] != '\0') { imap_fix_path (idata, mx.mbox, mbox, sizeof (mbox)); @@ -118,7 +127,7 @@ int imap_init_browse (char *path, struct browser_state *state) dprint (3, (debugfile, "imap_init_browse: mbox: %s\n", mbox)); - /* if our target exists, has inferiors and isn't selectable, enter it if we + /* if our target exists and has inferiors, enter it if we * aren't already going to */ if (mbox[n-1] != idata->delim) { @@ -136,7 +145,7 @@ int imap_init_browse (char *path, struct browser_state *state) { imap_unquote_string (cur_folder); - if (noselect && !noinferiors && cur_folder[0] && + if (!noinferiors && cur_folder[0] && (n = strlen (mbox)) < LONG_STRING-1) { mbox[n++] = idata->delim; @@ -150,7 +159,9 @@ int imap_init_browse (char *path, struct browser_state *state) /* if we're descending a folder, mark it as current in browser_state */ if (mbox[n-1] == idata->delim) { - showparents = 1; + /* don't show parents in the home namespace */ + if (!home_namespace) + showparents = 1; imap_qualify_path (buf, sizeof (buf), &mx, mbox, NULL); state->folder = safe_strdup (buf); n--; @@ -159,12 +170,17 @@ int imap_init_browse (char *path, struct browser_state *state) /* Find superiors to list * Note: UW-IMAP servers return folder + delimiter when asked to list * folder + delimiter. Cyrus servers don't. So we ask for folder, - * and tack on delimiter ourselves. */ + * and tack on delimiter ourselves. + * Further note: UW-IMAP servers return nothing when asked for + * NAMESPACES without delimiters at the end. Argh! */ for (n--; n >= 0 && mbox[n] != idata->delim ; n--); if (n > 0) /* "aaaa/bbbb/" -> "aaaa" */ { + /* forget the check, it is too delicate (see above). Have we ever + * had the parent not exist? */ ctmp = mbox[n]; mbox[n] = '\0'; +#if 0 /* List it to see if it can be selected */ dprint (2, (debugfile, "imap_init_browse: listing possible parent %s\n", mbox)); imap_make_sequence (seq, sizeof (seq)); @@ -173,6 +189,10 @@ int imap_init_browse (char *path, struct browser_state *state) /* add this entry as a superior, if we aren't tab-completing */ if (showparents && add_list_result (conn, seq, buf, state, 1)) return -1; +#else + dprint (2, (debugfile, "imap_init_browse: adding parent %s\n", mbox)); + imap_add_folder (idata->delim, mbox, 1, 0, state, 1); +#endif /* if our target isn't a folder, we are in our superior */ if (!state->folder) { @@ -213,6 +233,7 @@ int imap_init_browse (char *path, struct browser_state *state) /* Listing the home namespace, so INBOX should be included. Home * namespace is not "", so we have to list it explicitly. We ask the * server to see if it has descendants. */ + dprint (4, (debugfile, "imap_init_browse: adding INBOX\n")); imap_make_sequence (seq, sizeof (seq)); snprintf (buf, sizeof (buf), "%s LIST \"\" \"INBOX\"\r\n", seq); if (add_list_result (conn, seq, buf, state, 0)) @@ -232,9 +253,12 @@ int imap_init_browse (char *path, struct browser_state *state) if (home_namespace) { /* List additional namespaces */ for (i = 0; i < nns; i++) - if (nsi[i].listable && !nsi[i].home_namespace) + if (nsi[i].listable && !nsi[i].home_namespace) { imap_add_folder(nsi[i].delim, nsi[i].prefix, nsi[i].noselect, - nsi[i].noinferiors, state, 0); + nsi[i].noinferiors, state, 0); + dprint (4, (debugfile, "imap_init_browse: adding namespace: %s\n", + nsi[i].prefix)); + } } mutt_clear_error (); @@ -322,6 +346,13 @@ static void imap_add_folder (char delim, char *folder, int noselect, imap_qualify_path (tmp, sizeof (tmp), &mx, folder, NULL); (state->entry)[state->entrylen].name = safe_strdup (tmp); + /* mark desc with delim in browser if it can have subfolders */ + if (!isparent && !noinferiors && strlen (relpath) < sizeof (relpath) - 1) + { + relpath[strlen (relpath) + 1] = '\0'; + relpath[strlen (relpath)] = delim; + } + (state->entry)[state->entrylen].desc = safe_strdup (relpath); (state->entry)[state->entrylen].imap = 1; @@ -381,6 +412,8 @@ static int get_namespace (IMAP_DATA *idata, char *nsbuf, int nsblen, s++; /* skip ( */ /* copy namespace */ n = 0; + delim = '\0'; + if (*s == '\"') { s++; @@ -401,17 +434,25 @@ static int get_namespace (IMAP_DATA *idata, char *nsbuf, int nsblen, ns[n] = '\0'; /* delim? */ s = imap_next_word (s); - if (*s && *s == '\"') + /* delimiter is meaningless if namespace is "". Why does + * Cyrus provide one?! */ + if (n && *s && *s == '\"') { if (s[1] && s[2] == '\"') delim = s[1]; else if (s[1] && s[1] == '\\' && s[2] && s[3] == '\"') delim = s[2]; } - /* Save result (if space) */ - if ((nsbused < nsblen) && (*nns < nsilen)) + /* skip "" namespaces, they are already listed at the root */ + if ((ns[0] != '\0') && (nsbused < nsblen) && (*nns < nsilen)) { + dprint (4, (debugfile, "get_namespace: adding %s\n", ns)); nsi->type = type; + /* Cyrus doesn't append the delimiter to the namespace, + * but UW-IMAP does. We'll strip it here and add it back + * as if it were a normal directory, from the browser */ + if (n && (ns[n-1] == delim)) + ns[--n] = '\0'; strncpy(nsbuf+nsbused,ns,nsblen-nsbused-1); nsi->prefix = nsbuf+nsbused; nsbused += n+1; @@ -452,8 +493,14 @@ static int verify_namespace (CONNECTION *conn, IMAP_NAMESPACE_INFO *nsi, /* Cyrus gives back nothing if the % isn't added. This may return lots * of data in some cases, I guess, but I currently feel that's better * than invisible namespaces */ - snprintf (buf, sizeof (buf), "%s %s \"\" \"%s%c%%\"\r\n", seq, - option (OPTIMAPLSUB) ? "LSUB" : "LIST", nsi->prefix, nsi->delim); + if (nsi->delim) + snprintf (buf, sizeof (buf), "%s %s \"\" \"%s%c%%\"\r\n", seq, + option (OPTIMAPLSUB) ? "LSUB" : "LIST", nsi->prefix, + nsi->delim); + else + snprintf (buf, sizeof (buf), "%s %s \"\" \"%s%%\"\r\n", seq, + option (OPTIMAPLSUB) ? "LSUB" : "LIST", nsi->prefix); + mutt_socket_write (conn, buf); nsi->listable = 0; -- 2.50.1