]> granicus.if.org Git - mutt/commitdiff
Brendan Cully's patch from <20000212185021.A7365@xanadu.kublai.com>.
authorThomas Roessler <roessler@does-not-exist.org>
Mon, 14 Feb 2000 16:07:54 +0000 (16:07 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Mon, 14 Feb 2000 16:07:54 +0000 (16:07 +0000)
12 files changed:
.cvsignore
Makefile.am
browser.c
browser.h
configure.in
doc/manual.sgml.head
imap/Makefile.am
imap/auth.c
imap/auth_gss.c [new file with mode: 0644]
imap/browse.c
imap/imap.c
mx.c

index 5148a94ed26f9c543f0bbe7a0161be00591a661a..b9529254141d8b4e4a2d7c82e020cbf65846e0c1 100644 (file)
@@ -9,6 +9,7 @@ configure
 config.cache
 config.log
 config.status
+keymap_alldefs.h
 keymap_defs.h
 makedoc
 mutt_dotlock
index f4ef76f77eec7fa800a363c57c6b8320719d9171..1d74d241d162a1ce1c5dee9f626c97d15dab0284 100644 (file)
@@ -38,7 +38,9 @@ mutt_SOURCES = $(BUILT_SOURCES) \
 
 muttbug_SOURCES = muttbug.sh.in
 
-mutt_LDADD = @MUTT_LIB_OBJECTS@ @LIBOBJS@ $(LIBIMAP) $(GSSLIBS) $(INTLLIBS) 
+mutt_LDADD = @MUTT_LIB_OBJECTS@ @LIBOBJS@ $(LIBIMAP) $(MUTTLIBS) \
+       $(INTLLIBS) 
+
 mutt_DEPENDENCIES = @MUTT_LIB_OBJECTS@ @LIBOBJS@ $(LIBIMAPDEPS) $(INTLDEPS)
 
 makedoc_SOURCES = makedoc.c
@@ -47,7 +49,9 @@ CPP=@CPP@
 
 DEFS=-DSHAREDIR=\"$(sharedir)\" -DSYSCONFDIR=\"$(sysconfdir)\" \
        -DBINDIR=\"$(bindir)\" -DHAVE_CONFIG_H=1
-INCLUDES=-I. $(IMAP_INCLUDES) -I$(includedir)
+
+# top_srcdir is for building outside of the source tree
+INCLUDES=-I$(top_srcdir) -I. $(IMAP_INCLUDES) -I$(includedir)
 
 non_us_sources = pgp.c pgpinvoke.c pgpkey.c pgplib.c sha1dgst.c \
        gnupgparse.c sha.h sha_locl.h \
index d1ae8decb6d6e45945a7ebf1a472fe9bfb7e1e4c..67b4ac43ae821246ee23012333a613b1fdd012ac 100644 (file)
--- a/browser.c
+++ b/browser.c
@@ -172,7 +172,7 @@ folder_format_str (char *dest, size_t destlen, char op, const char *src,
       
     case 'f':
 #ifdef USE_IMAP
-      if (mx_is_imap (folder->ff->name))
+      if (folder->ff->imap)
         strfcpy (fn, NONULL(folder->ff->desc), sizeof (fn));
       else
 #endif
@@ -207,10 +207,13 @@ folder_format_str (char *dest, size_t destlen, char op, const char *src,
       else
       {
 #ifdef USE_IMAP
-       if (mx_is_imap (folder->ff->name))
+       if (folder->ff->imap)
        {
+         sprintf (permission, "IMAP %c%c",
+                  folder->ff->inferiors ? '+' : ' ',
+                  folder->ff->selectable ? 'S' : ' ');
           snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
-          snprintf (dest, destlen, tmp, "IMAP");
+          snprintf (dest, destlen, tmp, permission);
        }                                        
 #endif
       }
@@ -328,9 +331,8 @@ static void add_folder (MUTTMENU *m, struct browser_state *state,
   (state->entry)[state->entrylen].name = safe_strdup (name);
   (state->entry)[state->entrylen].desc = safe_strdup (name);
 #ifdef USE_IMAP
-  (state->entry)[state->entrylen].notfolder = 0;
+  (state->entry)[state->entrylen].imap = 0;
 #endif
-
   (state->entrylen)++;
 }
 
@@ -421,7 +423,7 @@ static int examine_mailboxes (MUTTMENU *menu, struct browser_state *state)
   do
   {
 #ifdef USE_IMAP
-    if (tmp->path[0] == '{')
+    if (mx_is_imap (tmp->path))
     {
       add_folder (menu, state, tmp->path, NULL, tmp->new);
       continue;
@@ -623,7 +625,7 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
            (S_ISLNK (state.entry[menu->current].mode) &&
            link_is_dir (LastDir, state.entry[menu->current].name)) 
 #ifdef USE_IMAP
-           || state.entry[menu->current].notfolder
+           || state.entry[menu->current].inferiors
 #endif
            )
        {
@@ -645,7 +647,7 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
 
          if ((mx_get_magic (buf) <= 0)
 #ifdef USE_IMAP
-           || state.entry[menu->current].notfolder
+           || state.entry[menu->current].inferiors
 #endif
            )
          {
@@ -681,8 +683,17 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
 #ifdef USE_IMAP
            else if (state.imap_browse)
            {
+             int n;
+             
               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))
+             {
+               LastDir[n] = '\0';
+               LastDir[n-1] = state.entry[menu->current].delim;
+             }
            }
 #endif
            else
@@ -806,7 +817,7 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
        break;
 
       case OP_DELETE_MAILBOX:
-       if (!mx_is_imap (state.entry[menu->current].name))
+       if (!state.entry[menu->current].imap)
          mutt_error (_("Delete is only supported for IMAP mailboxes"));
        else
         {
@@ -1058,6 +1069,16 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
          break;
        }
 
+#ifdef USE_IMAP
+       if (state.entry[menu->current].selectable)
+       {
+         strfcpy (f, state.entry[menu->current].name, flen);
+         destroy_state (&state);
+         mutt_menuDestroy (&menu);
+         return;
+       }
+       else
+#endif
         if (S_ISDIR (state.entry[menu->current].mode) ||
            (S_ISLNK (state.entry[menu->current].mode) &&
            link_is_dir (LastDir, state.entry[menu->current].name)))
index 48805abb616462eacb6a328e4b2ff24d54ad3f97..8fe7187f47854ecb92a73caa2875caa0f762d6cf 100644 (file)
--- a/browser.h
+++ b/browser.h
@@ -30,7 +30,11 @@ struct folder_file
   char *name;
   char *desc;
 #ifdef USE_IMAP
-  short notfolder;
+  char delim;
+  
+  unsigned imap : 1;
+  unsigned selectable : 1;
+  unsigned inferiors : 1;
 #endif
   unsigned tagged : 1;
   unsigned is_new : 1;
index eef1e1dd7f844f5a12e72023198ae1bb1a3a5fe4..82a43ddf0abb701a944960a1a207239e1e78e7a0 100644 (file)
@@ -65,7 +65,7 @@ if test -f $srcdir/EXPORTABLE ; then
 else
        SUBVERSION="i"
 
-       AC_ARG_ENABLE(pgp, [  --disable-pgp               Disable PGP support],
+       AC_ARG_ENABLE(pgp, [  --disable-pgp              Disable PGP support],
        [       if test x$enableval = xno ; then
                        HAVE_PGP=no
                fi
@@ -79,7 +79,7 @@ else
                OPS="$OPS \$(srcdir)/OPS.PGP"
        fi
 
-       AC_ARG_WITH(mixmaster, [  --with-mixmaster[=PATH]       include Mixmaster support],
+       AC_ARG_WITH(mixmaster, [  --with-mixmaster[=PATH]    Include Mixmaster support],
                [if test -x "$withval" ; then
                        MIXMASTER="$withval"
                 else
@@ -103,7 +103,7 @@ if test $ISPELL != no; then
        AC_DEFINE_UNQUOTED(ISPELL, "$ISPELL")
 fi
 
-AC_ARG_WITH(slang, [  --with-slang[=DIR]         use S-Lang instead of ncurses],
+AC_ARG_WITH(slang, [  --with-slang[=DIR]         Use S-Lang instead of ncurses],
        [AC_CACHE_CHECK([if this is a BSD system], mutt_cv_bsdish,
                [AC_TRY_RUN([#include <sys/param.h>
 
@@ -151,7 +151,6 @@ main ()
                fi
        fi
        AC_MSG_RESULT($mutt_cv_slang)
-       LIBS="$LIBS -lslang -lm"
        if test $mutt_cv_bsdish = yes; then
                AC_CHECK_LIB(termlib, main)
        fi
@@ -159,17 +158,16 @@ main ()
        AC_DEFINE(HAVE_COLOR)
        MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS resize.o"
        
-       dnl --- try to link a sample program to check if we're ok
+       dnl --- now that we've found it, check the link
        
-       AC_MSG_CHECKING(if I can compile a test SLang program)
-       AC_TRY_LINK([], [SLtt_get_terminfo ();],
-               [AC_MSG_RESULT(yes)],
-               [AC_MSG_ERROR(unable to compile.  check config.log)])
+       AC_CHECK_LIB(slang, SLtt_get_terminfo,
+               [MUTTLIBS="$MUTTLIBS -lslang -lm"],
+               [AC_MSG_ERROR(unable to compile.  check config.log)], -lm)
 
        ],
 
        [mutt_cv_curses=/usr
-       AC_ARG_WITH(curses, [  --with-curses=DIR          ncurses is installed in ],
+       AC_ARG_WITH(curses, [  --with-curses=DIR          Where ncurses is installed ],
                [if test $withval != yes; then
                        mutt_cv_curses=$withval
                fi
@@ -180,13 +178,13 @@ main ()
 
        AC_CHECK_LIB(ncurses, initscr,
 
-               [LIBS="$LIBS -lncurses"
+               [MUTTLIBS="$MUTTLIBS -lncurses"
                if test x$mutt_cv_curses = x/usr -a -d /usr/include/ncurses; then
                        CPPFLAGS="$CPPFLAGS -I/usr/include/ncurses"
                fi
                AC_CHECK_HEADERS(ncurses.h)],
 
-               [LIBS="$LIBS -lcurses"
+               [MUTTLIBS="$MUTTLIBS -lcurses"
                if test -f /usr/ccs/lib/libcurses.a; then
                                LDFLAGS="$LDFLAGS -L/usr/ccs/lib"
                else
@@ -196,9 +194,13 @@ main ()
                        fi
                fi])
 
+       old_LIBS="$LIBS"
+       LIBS="$LIBS $MUTTLIBS"
        AC_CHECK_FUNC(start_color, [AC_DEFINE(HAVE_COLOR)])
        AC_CHECK_FUNCS(typeahead bkgdset curs_set meta use_default_colors)
-       AC_CHECK_FUNCS(resizeterm, [MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS resize.o"])
+       AC_CHECK_FUNCS(resizeterm,
+               [MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS resize.o"])
+       LIBS="$old_LIBS"
        ])
 
 AC_HEADER_STDC
@@ -248,7 +250,7 @@ AC_CHECK_FUNCS(strftime, break, [AC_CHECK_LIB(intl, strftime)])
 dnl AIX may not have fchdir()
 AC_CHECK_FUNCS(fchdir, [AC_DEFINE(HAVE_FCHDIR)], [mutt_cv_fchdir=no])
 
-AC_ARG_WITH(regex, [  --with-regex            Use the GNU regex library ],
+AC_ARG_WITH(regex, [  --with-regex               Use the GNU regex library ],
        [mutt_cv_regex=yes],
        [AC_CHECK_FUNCS(regcomp, mutt_cv_regex=no, mutt_cv_regex=yes)])
 
@@ -272,7 +274,7 @@ if test $mutt_cv_regex = yes; then
 fi
 
 
-AC_ARG_WITH(homespool, [  --with-homespool[=FILE]    file in user's directory where new mail is spooled], with_homespool=${withval})
+AC_ARG_WITH(homespool, [  --with-homespool[=FILE]    File in user's directory where new mail is spooled], with_homespool=${withval})
 if test x$with_homespool != x; then
        if test $with_homespool = yes; then
                with_homespool=mailbox
@@ -282,7 +284,7 @@ if test x$with_homespool != x; then
        AC_DEFINE(USE_DOTLOCK)
        mutt_cv_setgid=no
 else
-       AC_ARG_WITH(mailpath, [  --with-mailpath=DIR        directory where spool mailboxes are located],
+       AC_ARG_WITH(mailpath, [  --with-mailpath=DIR        Directory where spool mailboxes are located],
                [mutt_cv_mailpath=$withval],
                [ AC_CACHE_CHECK(where new mail is stored, mutt_cv_mailpath,
                        [mutt_cv_mailpath=no
@@ -338,7 +340,7 @@ int main (int argc, char **argv)
        fi
 fi
 
-AC_ARG_ENABLE(external_dotlock, [  --enable-external-dotlock   Force use of an external dotlock program],
+AC_ARG_ENABLE(external_dotlock, [  --enable-external-dotlock  Force use of an external dotlock program],
        [mutt_cv_external_dotlock="$enableval"])
 
 if test "x$mutt_cv_setgid" = "xyes" || test "x$mutt_cv_fchdir" = "xno" \
@@ -353,7 +355,7 @@ fi
 AC_SUBST(DOTLOCK_TARGET)
 
 
-AC_ARG_WITH(libdir, [  --with-libdir=PATH       specify where to put arch dependent files],
+AC_ARG_WITH(libdir, [  --with-libdir=PATH         Specify where to put arch dependent files],
        [mutt_cv_libdir=$withval],
        [ AC_CACHE_CHECK(where to put architecture-dependent files,
                       mutt_cv_libdir,
@@ -363,7 +365,7 @@ AC_ARG_WITH(libdir, [  --with-libdir=PATH       specify where to put arch depend
 libdir=$mutt_cv_libdir
 AC_SUBST(libdir)
 
-AC_ARG_WITH(sharedir, [  --with-sharedir=PATH       specify where to put arch independent files],
+AC_ARG_WITH(sharedir, [  --with-sharedir=PATH       Specify where to put arch independent files],
        [mutt_cv_sharedir=$withval],
        [ AC_CACHE_CHECK(where to put architecture-independent data files,
                       mutt_cv_sharedir,
@@ -378,7 +380,7 @@ sharedir=$mutt_cv_sharedir
 AC_SUBST(sharedir)
 
 mutt_cv_charmaps=/usr/share/i18n/charmaps
-AC_ARG_WITH(charmaps, [--with-charmaps=PATH    specify where on the system mutt can find character set definitions],
+AC_ARG_WITH(charmaps, [  --with-charmaps=PATH       Where to find character set definitions],
        [mutt_cv_charmaps=$withval])
 
 mutt_cv_fake_charmaps=yes
@@ -406,7 +408,7 @@ charmaps=$mutt_cv_charmaps
 AC_SUBST(charmaps)
 AM_CONDITIONAL(BUILD_CHARMAPS, test x$need_charmaps = xyes)
 
-AC_ARG_WITH(docdir, [  --with-docdir=PATH       specify where to put the documentation],
+AC_ARG_WITH(docdir, [  --with-docdir=PATH         Specify where to put the documentation],
        [mutt_cv_docdir=$withval],
        [ AC_CACHE_CHECK(where to put the documentation,
                       mutt_cv_docdir,
@@ -436,7 +438,7 @@ AC_ARG_WITH(domain, [  --with-domain=DOMAIN       Specify your DNS domain name ]
                AC_DEFINE_UNQUOTED(DOMAIN, "$withval")
        fi])
 
-AC_ARG_ENABLE(pop, [  --enable-pop               Enable POP3 support],
+AC_ARG_ENABLE(pop,  [  --enable-pop               Enable POP3 support],
 [      if test x$enableval = xyes ; then
                AC_DEFINE(USE_POP)
                AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt))
@@ -457,8 +459,13 @@ AC_ARG_ENABLE(imap, [  --enable-imap              Enable IMAP support],
 ])
 AM_CONDITIONAL(BUILD_IMAP, test x$need_imap = xyes)
 
-AC_ARG_WITH(gss, [  --with-gss[=DIR]        Compile in GSSAPI authentication for IMAP],
+AC_ARG_WITH(gss,    [    --with-gss[=DIR]         Compile in GSSAPI authentication for IMAP],
        [
+       if test "$need_imap" != "yes"
+        then
+          AC_MSG_ERROR([GSS support is only for IMAP, but IMAP is not enabled])
+        fi
+
        if test "$with_gss" != "no"
        then
          if test "$with_gss" != "yes"
@@ -473,24 +480,29 @@ AC_ARG_WITH(gss, [  --with-gss[=DIR]        Compile in GSSAPI authentication for
          AC_CHECK_LIB(gssapi_krb5, gss_init_sec_context,,
            AC_MSG_ERROR([could not find libgssapi_krb5 which is needed for GSS authentication]), -lkrb5)
          LIBS="$saved_LIBS"
-         GSSLIBS="-lgssapi_krb5 -lkrb5"
+         MUTTLIBS="$MUTTLIBS -lgssapi_krb5 -lkrb5"
          AC_DEFINE(USE_GSS)
+          need_gss="yes"
        fi
 ])
+AM_CONDITIONAL(USE_GSS, test x$need_gss = xyes)
 
-AC_ARG_ENABLE(ssl, [  --enable-ssl               Enable SSL support],
+AC_ARG_ENABLE(ssl, [    --enable-ssl             Enable SSL support for IMAP],
 [      if test "$need_imap" != "yes"; then
-          AC_MSG_ERROR([Sorry, SSL support only for IMAP])
+          AC_MSG_ERROR([SSL support is only for IMAP, but IMAP is not enabled])
        fi
 
+       saved_LIBS="$LIBS"
        AC_CHECK_LIB(crypto, X509_new,, AC_MSG_ERROR([Unable to find SSL library]))
        AC_CHECK_LIB(ssl, SSL_new,, AC_MSG_ERROR([Unable to find SSL library]), -lcrypto)
        AC_DEFINE(USE_SSL)
+       LIBS="$saved_LIBS"
+       MUTTLIBS="$MUTTLIBS -lssl -lcrypto"
        need_ssl=yes
 ])
 AM_CONDITIONAL(USE_SSL, test x$need_ssl = xyes)
 
-AC_ARG_ENABLE(debug, [  --enable-debug         Enable debugging support],
+AC_ARG_ENABLE(debug, [  --enable-debug             Enable debugging support],
        [ if test x$enableval = xyes ; then
                AC_DEFINE(DEBUG)
          fi
@@ -544,10 +556,10 @@ AC_ARG_ENABLE(exact-address, [  --enable-exact-address     enable regeneration o
                AC_DEFINE(EXACT_ADDRESS)
        fi])
 
+AC_SUBST(MUTTLIBS)
 AC_SUBST(MUTT_LIB_OBJECTS)
 AC_SUBST(LIBIMAP)
 AC_SUBST(LIBIMAPDEPS)
-AC_SUBST(GSSLIBS)
 
 MUTT_AM_GNU_GETTEXT
 CPPFLAGS="$CPPFLAGS -I\$(top_srcdir)/intl"
index f4eae534a239e20b28b02d573caaf188e25a4935..345ab48d3f8b0841c67a55839e5aafa5cd7e16bb 100644 (file)
@@ -1994,14 +1994,38 @@ variable, which defaults to every 60 seconds.
 
 Mutt is designed to work with IMAP4rev1 servers, and was originally tested
 with both the UWash IMAP server v11.241 and the Cyrus IMAP server v1.5.14.
-Nowadays it is primarily developed against UW-IMAP 12.250. It works
-more-or-less correctly against Cyrus 1.6.11, though there are a few minor
-quirks in the folder browser.
+Nowadays it is primarily developed against UW-IMAP 12.250. It appears
+to work more-or-less correctly against Cyrus 1.6.11 as well.
 
 Note that if you are using mbox as the mail store on UW servers prior to
 v12.250, the server has been reported to disconnect a client if another client
 selects the same folder.
 
+<sect2>The Folder Browser
+<p>
+
+As of version 1.2, mutt supports browsing mailboxes on an IMAP
+server. This is mostly the same as the local file browser, with the
+following differences:
+<itemize>
+<item>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
+  subfolders. 
+<item>For the case where an entry can contain both messages and
+  subfolders, the selection key (bound to <tt>enter</tt> by default)
+  will choose to descend into the subfolder view. If you wish to view
+  the messages in that folder, you must use <tt>view-file</tt> instead
+  (bound to <tt>space</tt> by default).
+<item>You can delete mailboxes with the <tt>delete-mailbox</tt>
+  command (bound to <tt>d</tt> by default. You may also
+  <tt>subscribe</tt> and <tt>unsubscribe</tt> to mailboxes (normally
+  these are bound to <tt>s</tt> and <tt>u</tt>, respectively).
+</itemize>
+
 <sect2>Authentication
 <p>
 
index d04524682f25bc272195a81d091ce9e989946ba7..3713dbbcf1e2272a90e64141329c3ca3d9fd445d 100644 (file)
@@ -2,6 +2,10 @@
 
 AUTOMAKE_OPTIONS = foreign
 
+if USE_GSS
+GSSSOURCES = auth_gss.c
+endif
+
 if USE_SSL
 SSLSOURCES = imap_ssl.c
 SSLHEADERS = imap_ssl.h
@@ -15,4 +19,4 @@ noinst_LIBRARIES = libimap.a
 noinst_HEADERS = imap_private.h imap_socket.h md5.h message.h $(SSLHEADERS)
 
 libimap_a_SOURCES = auth.c browse.c command.c imap.c imap.h md5c.c message.c \
-       socket.c util.c $(SSLSOURCES)
+       socket.c util.c $(GSSSOURCES) $(SSLSOURCES)
index b440c3178798f41f839c37a1a90b9ed5542de154..fbdcfd34d1fa3f403e162432e55a3beb5d211c7b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
  * Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
- * Copyright (C) 1999 Brendan Cully <brendan@kublai.com>
+ * Copyright (C) 1999-2000 Brendan Cully <brendan@kublai.com>
  * 
  *     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
 #define MD5_BLOCK_LEN 64
 #define MD5_DIGEST_LEN 16
 
+/* external authenticator prototypes */
 #ifdef USE_GSS
-#include <netinet/in.h>
-#include <gssapi/gssapi.h>
-#include <gssapi/gssapi_generic.h>
-
-#define GSS_BUFSIZE 8192
-
-#define GSS_AUTH_P_NONE      1
-#define GSS_AUTH_P_INTEGRITY 2
-#define GSS_AUTH_P_PRIVACY   4
+int imap_auth_gss (IMAP_DATA* idata, const char* user);
 #endif
 
 /* forward declarations */
@@ -45,9 +38,6 @@ static void hmac_md5 (const char* password, char* challenge,
 static int imap_auth_cram_md5 (IMAP_DATA* idata, const char* user,
   const char* pass);
 static int imap_auth_anon (IMAP_DATA *idata);
-#ifdef USE_GSS
-static int imap_auth_gss (IMAP_DATA* idata, const char* user);
-#endif
 
 /* hmac_md5: produce CRAM-MD5 challenge response. */
 static void hmac_md5 (const char* password, char* challenge,
@@ -100,229 +90,6 @@ static void hmac_md5 (const char* password, char* challenge,
   MD5Final (response, &ctx);
 }
 
-#ifdef USE_GSS
-/* imap_auth_gss: AUTH=GSSAPI support. Used unconditionally if the server
- *   supports it */
-static int imap_auth_gss (IMAP_DATA* idata, const char* user)
-{
-  gss_buffer_desc request_buf, send_token;
-  gss_buffer_t sec_token;
-  gss_name_t target_name;
-  gss_ctx_id_t context;
-  gss_OID mech_name;
-  gss_qop_t quality;
-  int cflags;
-  OM_uint32 maj_stat, min_stat;
-  char buf1[GSS_BUFSIZE], buf2[GSS_BUFSIZE], server_conf_flags;
-  unsigned long buf_size;
-
-  char seq[16];
-
-  dprint (2, (debugfile, "Attempting GSS login...\n"));
-
-  /* get an IMAP service ticket for the server */
-  snprintf (buf1, sizeof (buf1), "imap@%s", idata->conn->mx.host);
-  request_buf.value = buf1;
-  request_buf.length = strlen (buf1) + 1;
-  maj_stat = gss_import_name (&min_stat, &request_buf, gss_nt_service_name,
-    &target_name);
-  if (maj_stat != GSS_S_COMPLETE)
-  {
-    dprint (2, (debugfile, "Couldn't get service name for [%s]\n", buf1));
-    return -1;
-  }
-  else if (debuglevel >= 2)
-  {
-    maj_stat = gss_display_name (&min_stat, target_name, &request_buf,
-      &mech_name);
-    dprint (2, (debugfile, "Using service name [%s]\n",
-      (char*) request_buf.value));
-    maj_stat = gss_release_buffer (&min_stat, &request_buf);
-  }
-
-  /* now begin login */
-  mutt_message _("Authenticating (GSSAPI)...");
-  imap_make_sequence (seq, sizeof (seq));
-  snprintf (buf1, sizeof (buf1), "%s AUTHENTICATE GSSAPI\r\n", seq);
-  mutt_socket_write (idata->conn, buf1);
-
-  /* expect a null continuation response ("+") */
-  if (mutt_socket_read_line_d (buf1, sizeof (buf1), idata->conn) < 0)
-  {
-    dprint (1, (debugfile, "Error receiving server response.\n"));
-    gss_release_name (&min_stat, &target_name);
-
-    return -1;
-  }
-
-  if (buf1[0] != '+')
-  {
-    dprint (2, (debugfile, "Invalid response from server: %s\n", buf1));
-    gss_release_name (&min_stat, &target_name);
-
-    return -1;
-  }
-
-  /* now start the security context initialisation loop... */
-  dprint (2, (debugfile, "Sending credentials\n"));
-  sec_token = GSS_C_NO_BUFFER;
-  context = GSS_C_NO_CONTEXT;
-  do
-  {
-    /* build token */
-    maj_stat = gss_init_sec_context (&min_stat, 
-                                    GSS_C_NO_CREDENTIAL, 
-                                    &context,
-                                    target_name, 
-                                    GSS_C_NO_OID,
-                                    GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG,
-                                    0, 
-                                    GSS_C_NO_CHANNEL_BINDINGS, 
-                                    sec_token, 
-                                    NULL, 
-                                    &send_token,
-                                    (unsigned int*) &cflags, 
-                                    NULL);
-    if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
-    {
-      dprint (1, (debugfile, "Error exchanging credentials\n"));
-      gss_release_name (&min_stat, &target_name);
-      /* end authentication attempt */
-      mutt_socket_write (idata->conn, "*\r\n");
-      mutt_socket_read_line_d (buf1, sizeof (buf1), idata->conn);
-
-      return -1;
-    }
-
-    /* send token */
-    mutt_to_base64 ((unsigned char*) buf1, send_token.value,
-      send_token.length);
-    gss_release_buffer (&min_stat, &send_token);
-    strcpy (buf1 + strlen (buf1), "\r\n");
-    mutt_socket_write (idata->conn, buf1);
-
-    if (maj_stat == GSS_S_CONTINUE_NEEDED)
-    {
-      if (mutt_socket_read_line_d (buf1, sizeof (buf1), idata->conn) < 0)
-      {
-        dprint (1, (debugfile, "Error receiving server response.\n"));
-        gss_release_name (&min_stat, &target_name);
-
-        return -1;
-      }
-
-      request_buf.length = mutt_from_base64 (buf2, buf1 + 2);
-      request_buf.value = buf2;
-      sec_token = &request_buf;
-    }
-  }
-  while (maj_stat == GSS_S_CONTINUE_NEEDED);
-
-  gss_release_name (&min_stat, &target_name);
-
-  /* get security flags and buffer size */
-  if (mutt_socket_read_line_d (buf1, sizeof (buf1), idata->conn) < 0)
-  {
-    dprint (1, (debugfile, "Error receiving server response.\n"));
-
-    return -1;
-  }
-  request_buf.length = mutt_from_base64 (buf2, buf1 + 2);
-  request_buf.value = buf2;
-
-  maj_stat = gss_unwrap (&min_stat, context, &request_buf, &send_token,
-    &cflags, &quality);
-  if (maj_stat != GSS_S_COMPLETE)
-  {
-    dprint (2, (debugfile, "Couldn't unwrap security level data\n"));
-    gss_release_buffer (&min_stat, &send_token);
-
-    mutt_socket_write(idata->conn, "*\r\n");
-    return -1;
-  }
-  dprint (2, (debugfile, "Credential exchange complete\n"));
-
-  /* first octet is security levels supported. We want NONE */
-  server_conf_flags = ((char*) send_token.value)[0];
-  if ( !(((char*) send_token.value)[0] & GSS_AUTH_P_NONE) )
-  {
-    dprint (2, (debugfile, "Server requires integrity or privace\n"));
-    gss_release_buffer (&min_stat, &send_token);
-
-    mutt_socket_write(idata->conn, "*\r\n");
-    return -1;
-  }
-
-  /* we don't care about buffer size if we don't wrap content. But here it is */
-  ((char*) send_token.value)[0] = 0;
-  buf_size = ntohl (*((long *) send_token.value));
-  gss_release_buffer (&min_stat, &send_token);
-  dprint (2, (debugfile, "Unwrapped security level flags: %c%c%c\n",
-    server_conf_flags & GSS_AUTH_P_NONE      ? 'N' : '-',
-    server_conf_flags & GSS_AUTH_P_INTEGRITY ? 'I' : '-',
-    server_conf_flags & GSS_AUTH_P_PRIVACY   ? 'P' : '-'));
-  dprint (2, (debugfile, "Maximum GSS token size is %ld\n", buf_size));
-
-  /* agree to terms (hack!) */
-  buf_size = htonl (buf_size); /* not relevant without integrity/privacy */
-  memcpy (buf1, &buf_size, 4);
-  buf1[0] = GSS_AUTH_P_NONE;
-  /* server decides if principal can log in as user */
-  strncpy (buf1 + 4, user, sizeof (buf1) - 4);
-  request_buf.value = buf1;
-  request_buf.length = 4 + strlen (user) + 1;
-  maj_stat = gss_wrap (&min_stat, context, 0, GSS_C_QOP_DEFAULT, &request_buf,
-    &cflags, &send_token);
-  if (maj_stat != GSS_S_COMPLETE)
-  {
-    dprint (2, (debugfile, "Error creating login request\n"));
-
-    mutt_socket_write(idata->conn, "*\r\n");
-    return -1;
-  }
-
-  mutt_to_base64 ((unsigned char*) buf1, send_token.value, send_token.length);
-  dprint (2, (debugfile, "Requesting authorisation as %s\n", user));
-  strncat (buf1, "\r\n", sizeof (buf1));
-  mutt_socket_write (idata->conn, buf1);
-
-  /* Joy of victory or agony of defeat? */
-  if (mutt_socket_read_line_d (buf1, GSS_BUFSIZE, idata->conn) < 0)
-  {
-    dprint (1, (debugfile, "Error receiving server response.\n"));
-
-    mutt_socket_write(idata->conn, "*\r\n");
-    return -1;
-  }
-  if (imap_code (buf1))
-  {
-    /* flush the security context */
-    dprint (2, (debugfile, "Releasing GSS credentials\n"));
-    maj_stat = gss_delete_sec_context (&min_stat, &context, &send_token);
-    if (maj_stat != GSS_S_COMPLETE)
-    {
-      dprint (1, (debugfile, "Error releasing credentials\n"));
-
-      return -1;
-    }
-    /* send_token may contain a notification to the server to flush
-     * credentials. RFC 1731 doesn't specify what to do, and since this
-     * support is only for authentication, we'll assume the server knows
-     * enough to flush its own credentials */
-    gss_release_buffer (&min_stat, &send_token);
-
-    dprint (2, (debugfile, "GSS login complete\n"));
-
-    return 0;
-  }
-
-  /* logon failed */
-  dprint (2, (debugfile, "GSS login failed.\n"));
-
-  return -1;
-}
-#endif
-
 /* imap_auth_cram_md5: AUTH=CRAM-MD5 support. Used unconditionally if the
  *   server supports it */
 static int imap_auth_cram_md5 (IMAP_DATA* idata, const char* user,
diff --git a/imap/auth_gss.c b/imap/auth_gss.c
new file mode 100644 (file)
index 0000000..acf9387
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 1999-2000 Brendan Cully <brendan@kublai.com>
+ * 
+ *     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
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ * 
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ * 
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */ 
+
+/* GSS login/authentication code */
+
+#include "mutt.h"
+#include "imap_private.h"
+
+#include <netinet/in.h>
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+
+#define GSS_BUFSIZE 8192
+
+#define GSS_AUTH_P_NONE      1
+#define GSS_AUTH_P_INTEGRITY 2
+#define GSS_AUTH_P_PRIVACY   4
+
+/* imap_auth_gss: AUTH=GSSAPI support. Used unconditionally if the server
+ *   supports it */
+int imap_auth_gss (IMAP_DATA* idata, const char* user)
+{
+  gss_buffer_desc request_buf, send_token;
+  gss_buffer_t sec_token;
+  gss_name_t target_name;
+  gss_ctx_id_t context;
+  gss_OID mech_name;
+  gss_qop_t quality;
+  int cflags;
+  OM_uint32 maj_stat, min_stat;
+  char buf1[GSS_BUFSIZE], buf2[GSS_BUFSIZE], server_conf_flags;
+  unsigned long buf_size;
+
+  char seq[16];
+
+  dprint (2, (debugfile, "Attempting GSS login...\n"));
+
+  /* get an IMAP service ticket for the server */
+  snprintf (buf1, sizeof (buf1), "imap@%s", idata->conn->mx.host);
+  request_buf.value = buf1;
+  request_buf.length = strlen (buf1) + 1;
+  maj_stat = gss_import_name (&min_stat, &request_buf, gss_nt_service_name,
+    &target_name);
+  if (maj_stat != GSS_S_COMPLETE)
+  {
+    dprint (2, (debugfile, "Couldn't get service name for [%s]\n", buf1));
+    return -1;
+  }
+  else if (debuglevel >= 2)
+  {
+    maj_stat = gss_display_name (&min_stat, target_name, &request_buf,
+      &mech_name);
+    dprint (2, (debugfile, "Using service name [%s]\n",
+      (char*) request_buf.value));
+    maj_stat = gss_release_buffer (&min_stat, &request_buf);
+  }
+
+  /* now begin login */
+  mutt_message _("Authenticating (GSSAPI)...");
+  imap_make_sequence (seq, sizeof (seq));
+  snprintf (buf1, sizeof (buf1), "%s AUTHENTICATE GSSAPI\r\n", seq);
+  mutt_socket_write (idata->conn, buf1);
+
+  /* expect a null continuation response ("+") */
+  if (mutt_socket_read_line_d (buf1, sizeof (buf1), idata->conn) < 0)
+  {
+    dprint (1, (debugfile, "Error receiving server response.\n"));
+    gss_release_name (&min_stat, &target_name);
+
+    return -1;
+  }
+
+  if (buf1[0] != '+')
+  {
+    dprint (2, (debugfile, "Invalid response from server: %s\n", buf1));
+    gss_release_name (&min_stat, &target_name);
+
+    return -1;
+  }
+
+  /* now start the security context initialisation loop... */
+  dprint (2, (debugfile, "Sending credentials\n"));
+  sec_token = GSS_C_NO_BUFFER;
+  context = GSS_C_NO_CONTEXT;
+  do
+  {
+    /* build token */
+    maj_stat = gss_init_sec_context (&min_stat, 
+                                    GSS_C_NO_CREDENTIAL, 
+                                    &context,
+                                    target_name, 
+                                    GSS_C_NO_OID,
+                                    GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG,
+                                    0, 
+                                    GSS_C_NO_CHANNEL_BINDINGS, 
+                                    sec_token, 
+                                    NULL, 
+                                    &send_token,
+                                    (unsigned int*) &cflags, 
+                                    NULL);
+    if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
+    {
+      dprint (1, (debugfile, "Error exchanging credentials\n"));
+      gss_release_name (&min_stat, &target_name);
+      /* end authentication attempt */
+      mutt_socket_write (idata->conn, "*\r\n");
+      mutt_socket_read_line_d (buf1, sizeof (buf1), idata->conn);
+
+      return -1;
+    }
+
+    /* send token */
+    mutt_to_base64 ((unsigned char*) buf1, send_token.value,
+      send_token.length);
+    gss_release_buffer (&min_stat, &send_token);
+    strcpy (buf1 + strlen (buf1), "\r\n");
+    mutt_socket_write (idata->conn, buf1);
+
+    if (maj_stat == GSS_S_CONTINUE_NEEDED)
+    {
+      if (mutt_socket_read_line_d (buf1, sizeof (buf1), idata->conn) < 0)
+      {
+        dprint (1, (debugfile, "Error receiving server response.\n"));
+        gss_release_name (&min_stat, &target_name);
+
+        return -1;
+      }
+
+      request_buf.length = mutt_from_base64 (buf2, buf1 + 2);
+      request_buf.value = buf2;
+      sec_token = &request_buf;
+    }
+  }
+  while (maj_stat == GSS_S_CONTINUE_NEEDED);
+
+  gss_release_name (&min_stat, &target_name);
+
+  /* get security flags and buffer size */
+  if (mutt_socket_read_line_d (buf1, sizeof (buf1), idata->conn) < 0)
+  {
+    dprint (1, (debugfile, "Error receiving server response.\n"));
+
+    return -1;
+  }
+  request_buf.length = mutt_from_base64 (buf2, buf1 + 2);
+  request_buf.value = buf2;
+
+  maj_stat = gss_unwrap (&min_stat, context, &request_buf, &send_token,
+    &cflags, &quality);
+  if (maj_stat != GSS_S_COMPLETE)
+  {
+    dprint (2, (debugfile, "Couldn't unwrap security level data\n"));
+    gss_release_buffer (&min_stat, &send_token);
+
+    mutt_socket_write(idata->conn, "*\r\n");
+    return -1;
+  }
+  dprint (2, (debugfile, "Credential exchange complete\n"));
+
+  /* first octet is security levels supported. We want NONE */
+  server_conf_flags = ((char*) send_token.value)[0];
+  if ( !(((char*) send_token.value)[0] & GSS_AUTH_P_NONE) )
+  {
+    dprint (2, (debugfile, "Server requires integrity or privace\n"));
+    gss_release_buffer (&min_stat, &send_token);
+
+    mutt_socket_write(idata->conn, "*\r\n");
+    return -1;
+  }
+
+  /* we don't care about buffer size if we don't wrap content. But here it is */
+  ((char*) send_token.value)[0] = 0;
+  buf_size = ntohl (*((long *) send_token.value));
+  gss_release_buffer (&min_stat, &send_token);
+  dprint (2, (debugfile, "Unwrapped security level flags: %c%c%c\n",
+    server_conf_flags & GSS_AUTH_P_NONE      ? 'N' : '-',
+    server_conf_flags & GSS_AUTH_P_INTEGRITY ? 'I' : '-',
+    server_conf_flags & GSS_AUTH_P_PRIVACY   ? 'P' : '-'));
+  dprint (2, (debugfile, "Maximum GSS token size is %ld\n", buf_size));
+
+  /* agree to terms (hack!) */
+  buf_size = htonl (buf_size); /* not relevant without integrity/privacy */
+  memcpy (buf1, &buf_size, 4);
+  buf1[0] = GSS_AUTH_P_NONE;
+  /* server decides if principal can log in as user */
+  strncpy (buf1 + 4, user, sizeof (buf1) - 4);
+  request_buf.value = buf1;
+  request_buf.length = 4 + strlen (user) + 1;
+  maj_stat = gss_wrap (&min_stat, context, 0, GSS_C_QOP_DEFAULT, &request_buf,
+    &cflags, &send_token);
+  if (maj_stat != GSS_S_COMPLETE)
+  {
+    dprint (2, (debugfile, "Error creating login request\n"));
+
+    mutt_socket_write(idata->conn, "*\r\n");
+    return -1;
+  }
+
+  mutt_to_base64 ((unsigned char*) buf1, send_token.value, send_token.length);
+  dprint (2, (debugfile, "Requesting authorisation as %s\n", user));
+  strncat (buf1, "\r\n", sizeof (buf1));
+  mutt_socket_write (idata->conn, buf1);
+
+  /* Joy of victory or agony of defeat? */
+  if (mutt_socket_read_line_d (buf1, GSS_BUFSIZE, idata->conn) < 0)
+  {
+    dprint (1, (debugfile, "Error receiving server response.\n"));
+
+    mutt_socket_write(idata->conn, "*\r\n");
+    return -1;
+  }
+  if (imap_code (buf1))
+  {
+    /* flush the security context */
+    dprint (2, (debugfile, "Releasing GSS credentials\n"));
+    maj_stat = gss_delete_sec_context (&min_stat, &context, &send_token);
+    if (maj_stat != GSS_S_COMPLETE)
+    {
+      dprint (1, (debugfile, "Error releasing credentials\n"));
+
+      return -1;
+    }
+    /* send_token may contain a notification to the server to flush
+     * credentials. RFC 1731 doesn't specify what to do, and since this
+     * support is only for authentication, we'll assume the server knows
+     * enough to flush its own credentials */
+    gss_release_buffer (&min_stat, &send_token);
+
+    dprint (2, (debugfile, "GSS login complete\n"));
+
+    return 0;
+  }
+
+  /* logon failed */
+  dprint (2, (debugfile, "GSS login failed.\n"));
+
+  return -1;
+}
index adb354f756e34cacf00b54847ed89916852db04e..f49fa3720b59fde906f8dbc51d790cd1e862bbf5 100644 (file)
@@ -283,14 +283,12 @@ static int add_list_result (CONNECTION *conn, const char *seq, const char *cmd,
 }
 
 /* imap_add_folder: add a folder name to the browser list, formatting it as
- *   necessary. NOTE: check for duplicate folders removed, believed to be
- *   useless. Tell me if otherwise (brendan@kublai.com) */
+ *   necessary. */
 static void imap_add_folder (char delim, char *folder, int noselect,
   int noinferiors, struct browser_state *state, short isparent)
 {
   char tmp[LONG_STRING];
   char relpath[LONG_STRING];
-  int flen = strlen (folder);
   IMAP_MBOX mx;
 
   if (imap_parse_path (state->folder, &mx))
@@ -298,14 +296,10 @@ static void imap_add_folder (char delim, char *folder, int noselect,
 
   imap_unquote_string (folder);
 
-  /* plus 2: folder may be selectable AND have inferiors */
-  if (state->entrylen + 2 == state->entrymax)
+  if (state->entrylen + 1 == state->entrymax)
   {
     safe_realloc ((void **) &state->entry,
       sizeof (struct folder_file) * (state->entrymax += 256));
-    /* apparently linux+glibc2.1 was zeroing this for me? Jon Hellan reports
-     * that the browser segfaults on more than 256 entries. I never had this
-     * problem */
     memset (state->entry + state->entrylen, 0,
       (sizeof (struct folder_file) * (state->entrymax - state->entrylen)));
   }
@@ -325,34 +319,19 @@ static void imap_add_folder (char delim, char *folder, int noselect,
   if (!((regexec (Mask.rx, relpath, 0, NULL, 0) == 0) ^ Mask.not))
     return;
 
-  if (!noselect)
-  {
-    imap_qualify_path (tmp, sizeof (tmp), &mx, folder, NULL);
-    (state->entry)[state->entrylen].name = safe_strdup (tmp);
-
-    (state->entry)[state->entrylen].desc = safe_strdup (relpath);
-
-    (state->entry)[state->entrylen].notfolder = 0;
-    (state->entrylen)++;
-  }
-  if (!noinferiors)
-  {
-    char trailing_delim[2];
-
-    /* create trailing delimiter if necessary */
-    trailing_delim[1] = '\0';
-    trailing_delim[0] = (flen && folder[flen - 1] != delim) ? delim : '\0';
-
-    imap_qualify_path (tmp, sizeof (tmp), &mx, folder, trailing_delim);
-    (state->entry)[state->entrylen].name = safe_strdup (tmp);
+  imap_qualify_path (tmp, sizeof (tmp), &mx, folder, NULL);
+  (state->entry)[state->entrylen].name = safe_strdup (tmp);
 
-    if (!isparent && (strlen (relpath) < sizeof (relpath) - 2))
-      strcat (relpath, trailing_delim);
-    (state->entry)[state->entrylen].desc = safe_strdup (relpath);
+  (state->entry)[state->entrylen].desc = safe_strdup (relpath);
 
-    (state->entry)[state->entrylen].notfolder = 1;
-    (state->entrylen)++;
-  }
+  (state->entry)[state->entrylen].imap = 1;
+  /* delimiter at the root is useless. */
+  if (folder[0] == '\0')
+    delim = '\0';
+  (state->entry)[state->entrylen].delim = delim;
+  (state->entry)[state->entrylen].selectable = !noselect;
+  (state->entry)[state->entrylen].inferiors = !noinferiors;
+  (state->entrylen)++;
 }
 
 static int compare_names(struct folder_file *a, struct folder_file *b) 
@@ -382,9 +361,7 @@ static int get_namespace (IMAP_DATA *idata, char *nsbuf, int nsblen,
   do 
   {
     if (mutt_socket_read_line_d (buf, sizeof (buf), idata->conn) < 0)
-    {
-      return (-1);
-    }
+      return -1;
 
     if (buf[0] == '*') 
     {
@@ -459,7 +436,7 @@ static int get_namespace (IMAP_DATA *idata, char *nsbuf, int nsblen,
   return 0;
 }
 
-/* Check which namespaces actually exist */
+/* Check which namespaces have contents */
 static int verify_namespace (CONNECTION *conn, IMAP_NAMESPACE_INFO *nsi, 
   int nns)
 {
@@ -472,8 +449,11 @@ static int verify_namespace (CONNECTION *conn, IMAP_NAMESPACE_INFO *nsi,
   for (i = 0; i < nns; i++, nsi++)
   {
     imap_make_sequence (seq, sizeof (seq));
-    snprintf (buf, sizeof (buf), "%s %s \"\" \"%s\"\r\n", seq, 
-             option (OPTIMAPLSUB) ? "LSUB" : "LIST", nsi->prefix);
+    /* 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);
     mutt_socket_write (conn, buf);
 
     nsi->listable = 0;
@@ -481,9 +461,8 @@ static int verify_namespace (CONNECTION *conn, IMAP_NAMESPACE_INFO *nsi,
     do 
     {
       if (imap_parse_list_response(conn, buf, sizeof(buf), &name,
-                                  &(nsi->noselect), &(nsi->noinferiors), 
-                                  &delim) != 0)
-       return (-1);
+          &(nsi->noselect), &(nsi->noinferiors), &delim) != 0)
+       return -1;
       nsi->listable |= (name != NULL);
     }
     while ((mutt_strncmp (buf, seq, SEQLEN) != 0));
index 828af0b018aebfd4151a0ff4f99b979207628401..36cda2bc0e2b6195484ad9a76a4b43bb337956b8 100644 (file)
@@ -1113,6 +1113,13 @@ void imap_fastclose_mailbox (CONTEXT *ctx)
       safe_free ((void **) &CTX_DATA->cache[i].path);
     }
   }
+
+#if 0
+  /* This is not the right place to logout, actually. There are two dangers:
+   * 1. status is set to IMAP_LOGOUT as soon as the user says q, even if she
+   *    cancels a bit later.
+   * 2. We may get here when closing the $received folder, but before we sync
+   *    the spool. So the sync will currently cause an abort. */
   if (CTX_DATA->status == IMAP_BYE || CTX_DATA->status == IMAP_FATAL ||
     CTX_DATA->status == IMAP_LOGOUT)
   {
@@ -1120,6 +1127,7 @@ void imap_fastclose_mailbox (CONTEXT *ctx)
     CTX_DATA->conn->data = NULL;
     safe_free ((void **) &ctx->data);
   }
+#endif
 }
 
 /* use the NOOP command to poll for new mail
diff --git a/mx.c b/mx.c
index e562b1c5f9a04d26cd5c7a0b920f3c79f6c80eee..5ad4255e5ece7ec5a9c4b52c5f02c9bdee703c13 100644 (file)
--- a/mx.c
+++ b/mx.c
@@ -818,9 +818,6 @@ int mx_close_mailbox (CONTEXT *ctx)
     }
     mutt_expand_path (mbox, sizeof (mbox));
 
-#ifdef USE_IMAP
-    if (!mx_is_imap (ctx->path))
-#endif
     if (isSpool)
     {
       snprintf (buf, sizeof (buf), _("Move read messages to %s?"), mbox);
@@ -853,29 +850,54 @@ int mx_close_mailbox (CONTEXT *ctx)
 
   if (move_messages)
   {
-    if (mx_open_mailbox (mbox, M_APPEND, &f) == NULL)
-      return (-1);
-
     mutt_message (_("Moving read messages to %s..."), mbox);
 
-    for (i = 0; i < ctx->msgcount; i++)
+#ifdef USE_IMAP
+    /* try to use server-side copy first */
+    i = 1;
+    
+    if (ctx->magic == M_IMAP && mx_is_imap (mbox))
     {
-      if (ctx->hdrs[i]->read && !ctx->hdrs[i]->deleted)
-      {
-       if (mutt_append_message (&f, ctx, ctx->hdrs[i], 0, CH_UPDATE_LEN) == 0)
-       {
-         ctx->hdrs[i]->deleted = 1;
-         ctx->deleted++;
-       }
+      /* tag messages for moving, and clear old tags, if any */
+      for (i = 0; i < ctx->msgcount; i++)
+       if (ctx->hdrs[i]->read && !ctx->hdrs[i]->deleted)
+         ctx->hdrs[i]->tagged = 1;
        else
-       {
-         mx_close_mailbox (&f);
-         return -1;
+         ctx->hdrs[i]->tagged = 0;
+      
+      i = imap_copy_messages (ctx, NULL, mbox, 1);
+    }
+    
+    if (i == 0) /* success */
+      mutt_clear_error ();
+    else if (i == -1) /* horrible error, bail */
+      return -1;
+    else /* use regular append-copy mode */
+#endif
+    {
+      if (mx_open_mailbox (mbox, M_APPEND, &f) == NULL)
+       return -1;
+
+      for (i = 0; i < ctx->msgcount; i++)
+      {
+       if (ctx->hdrs[i]->read && !ctx->hdrs[i]->deleted)
+        {
+         if (mutt_append_message (&f, ctx, ctx->hdrs[i], 0, CH_UPDATE_LEN) == 0)
+         {
+           ctx->hdrs[i]->deleted = 1;
+           ctx->deleted++;
+         }
+         else
+         {
+           mx_close_mailbox (&f);
+           return -1;
+         }
        }
       }
+    
+      mx_close_mailbox (&f);
     }
-
-    mx_close_mailbox (&f);
+    
   }
   else if (!ctx->changed && ctx->deleted == 0)
   {
@@ -890,8 +912,6 @@ int mx_close_mailbox (CONTEXT *ctx)
   {
     if (imap_sync_mailbox (ctx, purge) == -1)
       return -1;
-    if (ctx->magic == M_IMAP && !purge)
-      mutt_message (_("%d kept."), ctx->msgcount);
   }
   else
 #endif
@@ -908,19 +928,19 @@ int mx_close_mailbox (CONTEXT *ctx)
       if (sync_mailbox (ctx) == -1)
         return -1;
     }
+  }
 
-    if (move_messages)
-      mutt_message (_("%d kept, %d moved, %d deleted."),
-        ctx->msgcount - ctx->deleted, read_msgs, ctx->deleted);
-    else
-      mutt_message (_("%d kept, %d deleted."),
-        ctx->msgcount - ctx->deleted, ctx->deleted);
+  if (move_messages)
+     mutt_message (_("%d kept, %d moved, %d deleted."),
+       ctx->msgcount - ctx->deleted, read_msgs, ctx->deleted);
+  else
+    mutt_message (_("%d kept, %d deleted."),
+      ctx->msgcount - ctx->deleted, ctx->deleted);
 
-    if (ctx->msgcount == ctx->deleted &&
-        (ctx->magic == M_MMDF || ctx->magic == M_MBOX) &&
-        !mutt_is_spool(ctx->path) && !option (OPTSAVEEMPTY))
-      mx_unlink_empty (ctx->path);
-  }
+  if (ctx->msgcount == ctx->deleted &&
+      (ctx->magic == M_MMDF || ctx->magic == M_MBOX) &&
+      !mutt_is_spool(ctx->path) && !option (OPTSAVEEMPTY))
+    mx_unlink_empty (ctx->path);
 
   mx_fastclose_mailbox (ctx);