[Pkg-Cyrus-imapd-Debian-devel] [SVN] r148 -
trunk/cyrus-imapd-2.2.12/debian/patches
debian at incase.de
debian at incase.de
Tue Aug 30 15:17:59 UTC 2005
Author: sven
Date: 2005-05-25 00:58:58 +0200 (Wed, 25 May 2005)
New Revision: 148
Modified:
trunk/cyrus-imapd-2.2.12/debian/patches/20_drac_auth.dpatch
Log:
Fix up 20_drac_auth.dpatch to _not_ generate superfluous .orig files
Modified: trunk/cyrus-imapd-2.2.12/debian/patches/20_drac_auth.dpatch
===================================================================
--- trunk/cyrus-imapd-2.2.12/debian/patches/20_drac_auth.dpatch 2005-05-24 22:35:08 UTC (rev 147)
+++ trunk/cyrus-imapd-2.2.12/debian/patches/20_drac_auth.dpatch 2005-05-24 22:58:58 UTC (rev 148)
@@ -5,9 +5,9 @@
## DP: Enable DRAC (pop-before-smtp) authentication
@DPATCH@
-diff -urNad cyrus-imapd-2.2.12/configure.in /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/configure.in
---- cyrus-imapd-2.2.12/configure.in 2005-05-24 20:41:38.000000000 +0200
-+++ /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/configure.in 2005-05-24 20:45:11.547994849 +0200
+diff -urNad cyrus-imapd-2.2.12/configure.in /tmp/dpep.MaSf95/cyrus-imapd-2.2.12/configure.in
+--- cyrus-imapd-2.2.12/configure.in 2005-05-24 22:16:17.000000000 +0200
++++ /tmp/dpep.MaSf95/cyrus-imapd-2.2.12/configure.in 2005-05-25 00:50:07.959143878 +0200
@@ -988,6 +988,19 @@
SNMP_SUBDIRS=""
AC_SUBST(SNMP_SUBDIRS)
@@ -28,1250 +28,9 @@
CMU_LIBWRAP
CMU_UCDSNMP
-diff -urNad cyrus-imapd-2.2.12/configure.in.orig /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/configure.in.orig
---- cyrus-imapd-2.2.12/configure.in.orig 1970-01-01 01:00:00.000000000 +0100
-+++ /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/configure.in.orig 2005-05-24 20:41:38.000000000 +0200
-@@ -0,0 +1,1237 @@
-+dnl Process this file with autoconf to produce a configure script.
-+
-+dnl
-+dnl Copyright (c) 1998-2000 Carnegie Mellon University. All rights reserved.
-+dnl
-+dnl Redistribution and use in source and binary forms, with or without
-+dnl modification, are permitted provided that the following conditions
-+dnl are met:
-+dnl
-+dnl 1. Redistributions of source code must retain the above copyright
-+dnl notice, this list of conditions and the following disclaimer.
-+dnl
-+dnl 2. Redistributions in binary form must reproduce the above copyright
-+dnl notice, this list of conditions and the following disclaimer in
-+dnl the documentation and/or other materials provided with the
-+dnl distribution.
-+dnl
-+dnl 3. The name "Carnegie Mellon University" must not be used to
-+dnl endorse or promote products derived from this software without
-+dnl prior written permission. For permission or any other legal
-+dnl details, please contact
-+dnl Office of Technology Transfer
-+dnl Carnegie Mellon University
-+dnl 5000 Forbes Avenue
-+dnl Pittsburgh, PA 15213-3890
-+dnl (412) 268-4387, fax: (412) 268-7395
-+dnl tech-transfer at andrew.cmu.edu
-+dnl
-+dnl 4. Redistributions of any form whatsoever must retain the following
-+dnl acknowledgment:
-+dnl \"This product includes software developed by Computing Services
-+dnl at Carnegie Mellon University (http://www.cmu.edu/computing/).\"
-+dnl
-+dnl CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
-+dnl THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-+dnl AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
-+dnl FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+dnl WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
-+dnl AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
-+dnl OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+dnl
-+
-+dnl
-+dnl configure.in for the Cyrus imapd
-+dnl $Id: configure.in,v 1.290 2005/01/18 23:46:00 shadow Exp $
-+dnl
-+
-+
-+AC_INIT(imap/imapd.c)
-+AC_PREREQ([2.54])
-+AC_CONFIG_HEADER(config.h)
-+AC_CANONICAL_HOST
-+
-+dnl Useful for maintainer mode stuff
-+WARNERROR=-W
-+AC_ARG_ENABLE(warnings-are-errors,[ --enable-warnings-are-errors add -Werror to most gcc calls], [ if test "$enableval" != "no" ; then WARNERROR=-Werror ; fi ])
-+AC_SUBST(WARNERROR)
-+
-+dnl Useful hook for distributions
-+AC_ARG_WITH(extraident,[ --with-extraident=STRING use STRING as extra version information],
-+ [AC_DEFINE_UNQUOTED(EXTRA_IDENT,"$withval", [Extra version information for imap/version.h])])
-+
-+AC_CHECK_PROG(MAKEDEPEND,makedepend,makedepend,[`cd ${srcdir};pwd`/tools/not-mkdep])
-+if test "$MAKEDEPEND" != "makedepend"; then
-+ AC_MSG_WARN([Makedepend is not installed on this system. You should compile and install the version from the makedepend subdirectory.])
-+fi
-+
-+AC_ARG_WITH(login,,AC_ERROR([--with-login is no longer supported.
-+Configure SASL appropriately instead.]))
-+
-+AC_ARG_WITH(cyrus-prefix,[ --with-cyrus-prefix=DIR use DIR as cyrus server install directory],
-+ cyrus_prefix="$withval",cyrus_prefix="/usr/cyrus")
-+AC_SUBST(cyrus_prefix)
-+AC_DEFINE_UNQUOTED(CYRUS_PATH,"$cyrus_prefix",[Where will we be installed?])
-+AC_ARG_WITH(service-path,[ --with-service-path=DIR use DIR as service install directory],
-+ service_path="$withval",service_path="$cyrus_prefix/bin")
-+AC_SUBST(service_path)
-+AC_DEFINE_UNQUOTED(SERVICE_PATH,"$service_path",[Directiory to use for service binaries])
-+AC_ARG_WITH(cyrus-user,[ --with-cyrus-user=USERID use USERID cyrus userid],
-+ cyrus_user="$withval",cyrus_user="cyrus")
-+AC_SUBST(cyrus_user)
-+AC_DEFINE_UNQUOTED(CYRUS_USER, "$cyrus_user",[What user will we run as?])
-+AC_ARG_WITH(cyrus-group,[ --with-cyrus-group=GROUPID use GROUPID cyrus group],
-+ cyrus_group="$withval",cyrus_group="mail")
-+AC_SUBST(cyrus_group)
-+
-+dnl allow users to override $sysconfdir, but retain old default (/etc)
-+dnl if not specified
-+if test $sysconfdir = '${prefix}/etc'; then
-+ sysconfdir="/etc"
-+fi
-+AC_DEFINE_UNQUOTED(SYSCONFDIR,"$sysconfdir",[Config File Location])
-+
-+AC_PROG_CC
-+AC_PROG_RANLIB
-+AC_PROG_MAKE_SET
-+AC_PROG_INSTALL
-+AC_AIX
-+AC_ISC_POSIX
-+AC_PROG_AWK
-+AC_C_CONST
-+dnl fakeroot sometimes fails this test
-+dnl and Debian always supports long filenames anyway
-+dnl AC_SYS_LONG_FILE_NAMES
-+dnl if test $ac_cv_sys_long_file_names = no; then
-+dnl AC_MSG_ERROR(The Cyrus IMAPD requires support for long file names)
-+dnl fi
-+AC_C_INLINE
-+
-+CMU_C___ATTRIBUTE__
-+CMU_C_FPIC
-+
-+dnl check for -R, etc. switch
-+CMU_GUESS_RUNPATH_SWITCH
-+
-+AC_CHECK_HEADERS(unistd.h sys/select.h sys/param.h stdarg.h)
-+AC_REPLACE_FUNCS(memmove strcasecmp ftruncate strerror)
-+AC_CHECK_FUNCS(strlcat strlcpy)
-+AC_HEADER_DIRENT
-+
-+dnl do this before Berkeley DB/IPv6 detection
-+CMU_SOCKETS
-+LIBS="$LIBS ${LIB_SOCKET}"
-+
-+dnl check for IPv6 functions (fall back to sasl's if we don't have them)
-+cyrus_cv_getaddrinfo=yes
-+IPv6_CHECK_FUNC(getaddrinfo, [IPv6_CHECK_FUNC(gai_strerror,
-+ AC_DEFINE(HAVE_GETADDRINFO,[],[Do we have a getaddrinfo?]),
-+ cyrus_cv_getaddrinfo=no)], cyrus_cv_getaddrinfo=no)
-+
-+if test $cyrus_cv_getaddrinfo = no; then
-+ IPV6_OBJS="getaddrinfo.o"
-+fi
-+
-+cyrus_cv_getnameinfo=yes
-+IPv6_CHECK_FUNC(getnameinfo,
-+ AC_DEFINE(HAVE_GETNAMEINFO,[],[Do we have a getnameinfo?]),
-+ cyrus_cv_getnameinfo=no)
-+
-+if test $cyrus_cv_getnameinfo = no; then
-+ IPV6_OBJS="$IPV6_OBJS getnameinfo.o"
-+fi
-+
-+IPv6_CHECK_SS_FAMILY()
-+IPv6_CHECK_SA_LEN()
-+
-+AC_SUBST(IPV6_OBJS)
-+
-+dnl this is to check for time things
-+AC_CHECK_HEADERS(sys/time.h)
-+AC_HEADER_TIME
-+AC_STRUCT_TM
-+AC_STRUCT_TIMEZONE
-+
-+AC_SUBST(CPPFLAGS)
-+AC_SUBST(PRE_SUBDIRS)
-+AC_SUBST(EXTRA_SUBDIRS)
-+AC_SUBST(DEPLIBS)
-+AC_SUBST(LOCALDEFS)
-+AC_FUNC_VPRINTF
-+
-+dnl check authorization method before databases, to find out
-+dnl if we need a PTS database or not
-+AC_ARG_WITH(auth,[ --with-auth=METHOD use authorization module METHOD
-+ METHOD is 'unix' (default), 'krb', 'krb5', or 'pts'],
-+ WITH_AUTH="$withval", WITH_AUTH="unix")
-+AC_SUBST(WITH_AUTH)
-+
-+AC_MSG_CHECKING(authorization method)
-+AC_MSG_RESULT($WITH_AUTH)
-+
-+dnl function for doing each of the database backends
-+dnl parameters: backend name, variable to set, withval
-+
-+CYRUSDB_OBJS="cyrusdb_flat.o cyrusdb_skiplist.o cyrusdb_quotalegacy.o"
-+
-+dnl Berkeley DB Detection
-+
-+AC_ARG_WITH(bdb, [ --with-bdb=DIR use Berkeley DB (in DIR) [[yes]] ],
-+ with_bdb=$withval, with_bdb="yes")
-+
-+dnl support old-style
-+AC_ARG_WITH(dbdir,, with_bdb=$withval)
-+
-+case "$with_bdb" in
-+ no)
-+ use_berkeley="no"
-+ ;;
-+ yes)
-+ use_berkeley="yes"
-+ with_bdb_lib=none
-+ with_bdb_inc=none
-+ ;;
-+
-+ *)
-+ use_berkeley="yes"
-+ with_bdb_lib="$with_bdb/lib"
-+ with_bdb_inc="$with_bdb/include"
-+ ;;
-+esac
-+
-+if test "$use_berkeley" != "no"; then
-+ CYRUS_BERKELEY_DB_CHK()
-+
-+ if test "$dblib" = "no"; then
-+ AC_ERROR([Berkeley DB 3.x or later was not found. You may need to
-+ supply the --with-bdb-libdir or --with-bdb-incdir configure options.])
-+ fi
-+
-+ if test "$with_bdb_lib" != "none"; then
-+ CMU_ADD_LIBPATH($with_bdb_lib)
-+ fi
-+
-+ BDB_INC=${BDB_INCADD}
-+ BDB_LIB=${BDB_LIBADD}
-+ AC_SUBST(BDB_INC)
-+ AC_SUBST(BDB_LIB)
-+
-+ LIBS="${LIBS} ${BDB_LIBADD}"
-+ CPPFLAGS="${BDB_INCADD} ${CPPFLAGS}"
-+
-+ CYRUSDB_OBJS="$CYRUSDB_OBJS cyrusdb_berkeley.o"
-+ AC_DEFINE(HAVE_BDB,[],[Build in Berkeley DB support?])
-+fi
-+
-+dnl End Berkeley DB Detection
-+
-+AC_SUBST(CYRUSDB_OBJS)
-+
-+SIEVE_SUBDIRS=""
-+sievedir="sieve"
-+AC_ARG_ENABLE(sieve,
-+ [ --disable-sieve disable Sieve support],
-+ if test "$enableval" = no; then
-+ sievedir="no"
-+ fi)
-+
-+if test "$sievedir" != "no"; then
-+ SIEVE_OBJS="lmtp_sieve.o smtpclient.o"
-+ AC_SUBST(SIEVE_OBJS)
-+ SIEVE_LIBS="../${sievedir}/libsieve.a"
-+ AC_SUBST(SIEVE_LIBS)
-+ SIEVE_CPPFLAGS="-I\$(srcdir)/../$sievedir"
-+ AC_SUBST(SIEVE_CPPFLAGS)
-+ AC_DEFINE(USE_SIEVE,[],[Build in Sieve support?])
-+
-+ dnl Sieve configure stuff
-+ AC_PROG_YACC
-+ AC_PROG_LEX
-+ AC_CHECK_LIB(fl,main)
-+
-+ AC_SEARCH_LIBS(regcomp, rx regex, [
-+ AC_DEFINE(ENABLE_REGEX,[],[Do we have a decent regex library?])
-+ AC_CHECK_HEADER(rxposix.h, AC_DEFINE(HAVE_RX,[],[Do we have rxposix.h?]))])
-+
-+
-+ SIEVE_SUBDIRS="${SIEVE_SUBDIRS} $sievedir"
-+ EXTRA_OUTPUT="${EXTRA_OUTPUT} $sievedir/Makefile"
-+fi
-+
-+AC_SUBST(SIEVE_SUBDIRS)
-+
-+dnl for et routines
-+AC_FUNC_CHECK(strerror,AC_DEFINE(HAS_STRERROR,[],[Do we have strerror()?]),
-+ AC_DEFINE(NEED_SYS_ERRLIST,[],[Do we have a sys_errlist?]))
-+
-+dnl for master fd limits
-+AC_CHECK_HEADERS(sys/resource.h)
-+AC_CHECK_FUNCS(setrlimit)
-+AC_CHECK_FUNCS(getrlimit)
-+
-+dnl for detaching terminal
-+AC_CHECK_FUNCS(daemon setsid)
-+
-+dnl for turning off sockets
-+AC_CHECK_FUNCS(shutdown)
-+
-+AC_EGREP_HEADER(socklen_t, sys/socket.h, AC_DEFINE(HAVE_SOCKLEN_T,[],[Do we have a socklen_t?]))
-+AC_EGREP_HEADER(sockaddr_storage, sys/socket.h,
-+ AC_DEFINE(HAVE_STRUCT_SOCKADDR_STORAGE,[],[Do we have a sockaddr_storage?]))
-+AC_EGREP_HEADER(rlim_t, sys/resource.h, AC_DEFINE(HAVE_RLIM_T,[],[Do we have an rlim_t?]))
-+
-+dnl Bunch of setproctitle stuff
-+spt_type=""
-+AC_CHECK_FUNC(setproctitle,spt_type=SPT_BUILTIN)
-+if test "$spt_type" = ""; then
-+ dnl BSD/OS and FreeBSD put it in -lutil
-+ AC_CHECK_LIB(util,setproctitle,spt_type=SPT_BUILTIN
-+ LIBS="${LIBS} -lutil")
-+fi
-+if test "$spt_type" = ""; then
-+ AC_CHECK_HEADER(sys/pstat.h,spt_type=SPT_PSTAT)
-+fi
-+if test "$spt_type" = ""; then
-+ AC_CHECK_HEADER(sys/sysnews.h,spt_type=SPT_SYSMIPS)
-+fi
-+if test "$spt_type" = ""; then
-+ AC_MSG_CHECKING(for PS_STRINGS)
-+ AC_CACHE_VAL(cyrus_cv_sys_psstrings, AC_TRY_CPP([
-+#include <machine/vmparam.h>
-+#include <sys/exec.h>
-+#ifndef PS_STRINGS
-+#include </nonexistent>
-+#endif],cyrus_cv_sys_psstrings=yes,cyrus_cv_sys_psstrings=no))
-+ if test $cyrus_cv_sys_psstrings = yes; then
-+ spt_type=SPT_PSSTRINGS
-+ fi
-+ AC_MSG_RESULT($cyrus_cv_sys_psstrings)
-+fi
-+if test "$spt_type" = ""; then
-+ AC_MSG_CHECKING(for SCO)
-+ AC_CACHE_VAL(cyrus_cv_sys_sco, AC_TRY_CPP([
-+#ifndef _SCO_unix_
-+#include </nonexistent>
-+#endif],cyrus_cv_sys_sco=yes,cyrus_cv_sys_sco=no))
-+ if test $cyrus_cv_sys_sco = yes; then
-+ spt_type=SPT_SCO
-+ fi
-+ AC_MSG_RESULT($cyrus_cv_sys_sco)
-+fi
-+if test "$spt_type" = ""; then
-+ AC_MSG_CHECKING(for setproctitle usability)
-+ AC_CACHE_VAL(cyrus_cv_sys_setproctitle, AC_TRY_CPP([
-+#if defined(DGUX) || defined(_SEQUENT_) || defined(apollo)
-+#include </nonexistent>
-+#endif],cyrus_cv_sys_setproctitle=yes,cyrus_cv_sys_setproctitle=no))
-+ if test $cyrus_cv_sys_setproctitle = no; then
-+ spt_type=SPT_NONE
-+ fi
-+ AC_MSG_RESULT($cyrus_cv_sys_setproctitle)
-+fi
-+if test "$spt_type" != ""; then
-+ AC_DEFINE_UNQUOTED(SPT_TYPE,$spt_type,[Do we already have setproctitle?])
-+fi
-+
-+AC_MSG_CHECKING(nonblocking method)
-+AC_CACHE_VAL(cyrus_cv_sys_nonblock,AC_TRY_LINK([#include <sys/types.h>
-+#include <sys/file.h>
-+#include <fcntl.h>
-+#ifndef FNDELAY
-+#define FNDELAY O_NDELAY
-+#endif],[fcntl(0, F_GETFL, 0)&FNDELAY],
-+cyrus_cv_sys_nonblock=fcntl,cyrus_cv_sys_nonblock=ioctl))
-+WITH_NONBLOCK=$cyrus_cv_sys_nonblock
-+AC_SUBST(WITH_NONBLOCK)
-+AC_MSG_RESULT($WITH_NONBLOCK)
-+
-+AC_MSG_CHECKING(timezone GMT offset method)
-+AC_CACHE_VAL(cyrus_cv_struct_sys_gmtoff,AC_TRY_COMPILE([
-+#include <time.h>],[struct tm tm;
-+tm.tm_gmtoff = 0;
-+],cyrus_cv_struct_sys_gmtoff=tm,cyrus_cv_struct_sys_gmtoff=gmtime))
-+WITH_GMTOFF=$cyrus_cv_struct_sys_gmtoff
-+AC_SUBST(WITH_GMTOFF)
-+AC_MSG_RESULT($WITH_GMTOFF)
-+AC_MSG_CHECKING(for shared mmap)
-+AC_CACHE_VAL(cyrus_cv_func_mmap_shared,AC_TRY_RUN([
-+#include <sys/types.h>
-+#include <sys/mman.h>
-+#include <fcntl.h>
-+main() {
-+char *base;
-+int fd = open("conftestmmap", O_RDWR|O_CREAT|O_TRUNC, 0666);
-+if (fd == -1) exit(1);
-+if (write(fd, "test", 4) != 4) exit(1);
-+fsync(fd);
-+base = mmap((caddr_t)0, 100, PROT_READ, MAP_SHARED
-+#ifdef MAP_FILE
-+| MAP_FILE
-+#endif
-+#ifdef MAP_VARIABLE
-+| MAP_VARIABLE
-+#endif
-+, fd, 0L);
-+if (base == (caddr_t)-1) exit(1);
-+if (strncmp(base, "test", 4) != 0) exit(1);
-+if (write(fd, "test", 4) != 4) exit(1);
-+fsync(fd);
-+if (strncmp(base+4, "test", 4) != 0) exit(1);
-+exit(0);}
-+],cyrus_cv_func_mmap_shared=yes,cyrus_cv_func_mmap_shared=no,
-+cyrus_cv_func_mmap_shared=no))
-+AC_MSG_RESULT($cyrus_cv_func_mmap_shared)
-+if test $cyrus_cv_func_mmap_shared = yes; then
-+ WITH_MAP="shared"
-+else
-+AC_MSG_CHECKING(for stupid shared mmap)
-+AC_CACHE_VAL(cyrus_cv_func_mmap_stupidshared,AC_TRY_RUN([
-+#include <sys/types.h>
-+#include <sys/mman.h>
-+#include <fcntl.h>
-+main() {
-+char *base;
-+int fd = open("conftestmmap", O_RDWR|O_CREAT|O_TRUNC, 0666);
-+if (fd == -1) exit(1);
-+if (write(fd, "test", 4) != 4) exit(1);
-+fsync(fd);
-+base = mmap((caddr_t)0, 4, PROT_READ, MAP_SHARED
-+#ifdef MAP_FILE
-+| MAP_FILE
-+#endif
-+#ifdef MAP_VARIABLE
-+| MAP_VARIABLE
-+#endif
-+, fd, 0L);
-+if (base == (caddr_t)-1) exit(1);
-+if (strncmp(base, "test", 4) != 0) exit(1);
-+lseek(fd, 0L, 0);
-+if (write(fd, "xyzz", 4) != 4) exit(1);
-+fsync(fd);
-+if (strncmp(base, "xyzz", 4) != 0) exit(1);
-+exit(0);}
-+],cyrus_cv_func_mmap_stupidshared=yes,cyrus_cv_func_mmap_stupidshared=no,
-+cyrus_cv_func_mmap_stupidshared=no))
-+AC_MSG_RESULT($cyrus_cv_func_mmap_stupidshared)
-+if test $cyrus_cv_func_mmap_stupidshared = yes; then
-+ WITH_MAP="stupidshared"
-+else
-+ AC_MSG_WARN([*** This system does not have a working mmap()])
-+ AC_MSG_WARN(*** Expect a considerable performance penalty)
-+ WITH_MAP=nommap
-+fi
-+fi
-+
-+AC_SUBST(WITH_MAP)
-+AC_ARG_WITH(lock,
-+ [ --with-lock=METHOD force use of METHOD for locking (flock or fcntl)],
-+ WITH_LOCK="$withval", [
-+ AC_CHECK_FUNC(fcntl,WITH_LOCK="fcntl",[
-+ AC_CHECK_FUNC(flock,WITH_LOCK="flock",[
-+ AC_ERROR(unable to detect locking method)
-+ ])
-+ ])
-+ ])
-+
-+AC_SUBST(WITH_LOCK)
-+
-+dnl check for fdatasync (used by cyrusdb_skiplist)
-+LIB_RT=""
-+AC_CHECK_FUNC(fdatasync, AC_DEFINE(HAVE_FDATASYNC,[],[Do we have fdatasync()?]), [
-+ AC_CHECK_LIB(rt, fdatasync, [
-+ LIB_RT="-lrt"
-+ AC_DEFINE(HAVE_FDATASYNC,[],[Do we have fdatasync()?])
-+ ])
-+])
-+
-+dnl for makedepend and AFS.
-+cant_find_sigvec=no
-+AC_CACHE_VAL(cyrus_sigveclib,[
-+ dnl bsd classic flavor
-+ AC_CHECK_FUNC(sigvec, [
-+ cyrus_sigveclib=""
-+ ], [
-+ dnl hp flavor
-+ AC_CHECK_LIB(BSD, sigvec, cyrus_sigveclib="-lBSD", [
-+ dnl not hp flavor
-+ SAVE_LDFLAGS="$LDFLAGS"
-+ dnl solaris flavor
-+ LDFLAGS="-L/usr/ucblib -R/usr/ucblib $LDFLAGS"
-+ AC_CHECK_LIB(ucb, sigvec, [
-+ dnl more solaris flavor
-+ cyrus_sigveclib="-lc -L/usr/ucblib -R/usr/ucblib -lucb"],
-+ [ cant_find_sigvec=yes ])
-+ LDFLAGS="$SAVE_LDFLAGS"])
-+ ])
-+])
-+AC_SUBST(cyrus_sigveclib)
-+
-+# ok, we still look for this stuff because of checking groups, but
-+# all authentication goes through SASL
-+
-+AC_ARG_WITH(afs,[ --with-afs=PATH use AFS libraries from PATH],
-+ [with_afs="${withval}"
-+ CFLAGS="${CFLAGS} -I${withval}/include"],with_afs="/usr/local")
-+
-+AC_ARG_WITH(ldap, [ --with-ldap=DIR use LDAP (in DIR) (experimental) [/usr/local] ],
-+ with_ldap=$withval, with_ldap="/usr/local")
-+
-+dnl select module for ptloader
-+AC_ARG_WITH(pts,[ --with-pts=MODULE use PTS module MODULE
-+ MODULE is 'afskrb' (default) or 'ldap' (experimental)],
-+ WITH_PTS="$withval", WITH_PTS="afskrb")
-+AC_SUBST(WITH_PTS)
-+
-+dnl select mode of afspts
-+AC_ARG_ENABLE(krb5afspts,[ --enable-krb5afspts compile afskrb PTS module with krb5 support],
-+ [SASL_SET_GSSAPI_LIBS
-+ AC_DEFINE(AFSPTS_USE_KRB5,[],[Should the AFS PTS plugin use krb5?])])
-+
-+if test "$WITH_AUTH" = "pts"; then
-+ AC_MSG_CHECKING(which pts module to use)
-+ AC_MSG_RESULT($WITH_PTS)
-+
-+ EXTRA_SUBDIRS="${EXTRA_SUBDIRS} ptclient"
-+ EXTRA_OUTPUT="${EXTRA_OUTPUT} ptclient/Makefile"
-+
-+ LDAP_CPPFLAGS=""
-+ LDAP_LDFLAGS=""
-+ LDAP_LIBS=""
-+
-+ if test "$WITH_PTS" = "afskrb"; then
-+ AFS_LIBS="${with_afs}/lib/afs/libkauth.a ${with_afs}/lib/afs/libprot.a ${with_afs}/lib/afs/libauth.a ${with_afs}/lib/afs/libsys.a ${with_afs}/lib/librxkad.a ${with_afs}/lib/librx.a ${with_afs}/lib/afs/libsys.a ${with_afs}/lib/libubik.a ${with_afs}/lib/liblwp.a ${with_afs}/lib/afs/util.a"
-+ if test -f ${with_afs}/lib/afs/libaudit.a; then
-+ AFS_LIBS="$AFS_LIBS ${with_afs}/lib/afs/libaudit.a"
-+ fi
-+ if test -f /usr/ucblib/libucb.a; then
-+ CMU_ADD_LIBPATH_TO(/usr/ucblib, AFS_LDFLAGS)
-+ AFS_LIBS="$AFS_LIBS -lc -lucb"
-+ fi
-+
-+ AC_CACHE_VAL(cyrus_afs_sigvec,[
-+ SAVE_LIBS="$LIBS"
-+ LIBS="${with_afs}/lib/liblwp.a"
-+ AC_MSG_CHECKING(if AFS libraries need sigvec)
-+ dnl Does AFS need sigvec? We have to link against lwp and see
-+ dnl if IOMGR_Initialize wants it
-+ AC_TRY_LINK([IOMGR_Initialize();],
-+ [IOMGR_Initialize()],
-+ [
-+ dnl it linked; don't need it
-+ AC_MSG_RESULT(no)
-+ cyrus_afs_sigvec="no"
-+ ], [
-+ dnl didn't link; pick up sigvec
-+ AC_MSG_RESULT(yes)
-+ cyrus_afs_sigvec="yes"
-+ ])
-+ ])
-+ if test "$cyrus_afs_sigvec" = yes; then
-+ if test "$cant_find_sigvec" = yes; then
-+ AC_MSG_WARN([Can't find a sigvec for AFS libraries which seem])
-+ AC_MSG_WARN([to need one; ptloader may not build.])
-+ else
-+ AFS_LIBS="${AFS_LIBS} $cyrus_sigveclib"
-+ fi
-+ fi
-+ LIBS="$SAVE_LIBS"
-+ AC_SUBST(AFS_LIBS)
-+ AC_SUBST(AFS_LDFLAGS)
-+ elif test "$WITH_PTS" = "ldap"; then
-+ AC_MSG_WARN([*** WARNING: COMPILING WITH EXPERIMENTAL LDAP PTLOADER MODULE ***])
-+ if test -d $with_ldap; then
-+ LDAP_CPPFLAGS="$CPPFLAGS -I${with_ldap}/include"
-+ LDAP_LDFLAGS="$LDFLAGS -L${with_ldap}/lib"
-+ else
-+ AC_ERROR(LDAP path isn't a directory)
-+ fi
-+
-+ LDAP_LIBS=""
-+
-+ save_CPPFLAGS=$CPPFLAGS
-+ save_LDFLAGS=$LDFLAGS
-+ CPPFLAGS=$LDAP_CPPFLAGS
-+ LDFLAGS=$LDAP_LDFLAGS
-+
-+ AC_CHECK_LIB(ldap, ldap_initialize, [
-+ LDAP_LIBS="-lldap -llber" ],,-llber)
-+
-+ CPPFLAGS=$save_CPPFLAGS
-+ LDFLAGS=$save_LDFLAGS
-+ else
-+ AC_ERROR(unknown with-pts value)
-+ fi
-+
-+ AC_SUBST(LDAP_CPPFLAGS)
-+ AC_SUBST(LDAP_LDFLAGS)
-+ AC_SUBST(LDAP_LIBS)
-+
-+ AC_DEFINE(WITH_PTS,[],[Build in PTS support?])
-+fi
-+
-+
-+
-+SERVER_SUBDIRS="master imap"
-+AC_ARG_ENABLE(server,
-+ [ --disable-server disable compiling servers],
-+ if test "$enableval" = no; then
-+ SERVER_SUBDIRS=""
-+ fi)
-+AC_SUBST(SERVER_SUBDIRS)
-+# We always output a server makefile (just because we can)
-+
-+dnl this is the new simple check for kerberos; since the person had to
-+dnl compile SASL, we might as well use the same checks.
-+AC_ARG_WITH(krb,[ --with-krb=PATH use Kerberos from PATH],
-+ with_krb="$withval", with_krb="no")
-+
-+AC_ARG_WITH(krbimpl,[ --with-krbimpl=\[kth|mit\] assume Kerberos 4 from KTH or MIT],
-+ with_krbimpl="$withval", with_krbimpl="kth")
-+
-+AC_ARG_ENABLE(statickrb,
-+ [ --enable-statickrb link Kerberos statically],
-+ with_statickrb="yes", with_statickrb="no")
-+
-+if test "$WITH_AUTH" = "krb" -o "$WITH_AUTH" = "krb_pts" -o "$with_krb" != "no"; then
-+ dnl In order to compile kerberos4, we need libkrb and libdes.
-+
-+ dnl we might need -lresolv for kerberos
-+ AC_CHECK_LIB(resolv,res_search)
-+
-+ if test "$with_statickrb" = "yes" -a ! -d "$with_krb"; then
-+ AC_MSG_ERROR([--enable-statickrb specified but --with-krb did not specify a valid directory])
-+ fi
-+
-+ dnl Do we need DES for kerberos?
-+ AC_ARG_WITH(krbdes,[ --with-krbdes use Kerberos DES implementation [[yes]]],
-+ with_krbdes="$withval", with_krbdes="yes")
-+ if test "$with_krbdes" = "yes"; then
-+ AC_CHECK_LIB(des,des_ecb_encrypt,
-+ if test "$with_statickrb" = "yes"; then
-+ KRB_LIBS="$with_krb/lib/libdes.a"
-+ else
-+ KRB_LIBS="-ldes"
-+ fi,
-+ AC_MSG_ERROR([The Kerberos DES library is required for Kerberos support. You might want --with-auth=unix.]))
-+ fi
-+
-+ dnl if we were ambitious, we'd look more aggressively for the
-+ dnl krb4 install
-+ if test -d ${with_krb}; then
-+ AC_CACHE_CHECK(for Kerberos includes, cyrus_krbinclude, [
-+ for krbhloc in include/kerberosIV include
-+ do
-+ if test -f ${with_krb}/${krbhloc}/krb.h ; then
-+ cyrus_krbinclude=${with_krb}/${krbhloc}
-+ break
-+ fi
-+ done
-+ ])
-+
-+ if test -n "${cyrus_krbinclude}"; then
-+ CPPFLAGS="$CPPFLAGS -I${cyrus_krbinclude}"
-+ fi
-+ CMU_ADD_LIBPATH(${with_krb}/lib)
-+ fi
-+
-+ if test "$with_krbimpl" != "kth"; then
-+ KRBLIB="krb4"
-+ else
-+ KRBLIB="krb"
-+ fi
-+
-+ if test "$with_des" != no; then
-+ AC_CHECK_HEADER(krb.h,
-+ AC_CHECK_LIB(${KRBLIB}, krb_mk_priv,
-+ if test "$with_statickrb" = "yes"; then
-+ KRB_LIBS="$KRB_LIBS $with_krb/lib/lib${KRBLIB}.a"
-+ else
-+ KRB_LIBS="$KRB_LIBS -l${KRBLIB}"
-+ fi,
-+ AC_WARN(No Kerberos V4 found); krb4=no,
-+ $KRB_LIBS),
-+ AC_WARN(No Kerberos V4 found); krb4=no)
-+ else
-+ AC_WARN(No DES library found for Kerberos V4 support)
-+ krb4=no
-+ fi
-+
-+ if test "${krb4}" != no; then
-+ AC_DEFINE(HAVE_KRB,[],[Support for Kerberos?])
-+ else
-+ AC_ERROR([Kerberos not found for authorization module])
-+ fi
-+fi
-+
-+LIBS="$KRB_LIBS $LIBS"
-+
-+if test "$WITH_AUTH" = "krb5"; then
-+ SASL_SET_GSSAPI_LIBS
-+fi
-+
-+dnl
-+dnl Test for OpenSSL
-+dnl
-+IMAP_PROGS=""
-+AC_ARG_WITH(openssl,[ --with-openssl=PATH use OpenSSL from PATH],
-+ with_openssl="${withval}")
-+
-+OPENSSL_INC=
-+OPENSSL_LIB=
-+case "$with_openssl" in
-+ no) with_openssl="no";;
-+ ""|yes)
-+ dnl if openssl has been compiled with the rsaref2 libraries,
-+ dnl we need to include the rsaref libraries in the crypto check
-+ LIB_RSAREF=""
-+ AC_CHECK_LIB(rsaref, RSAPublicEncrypt,
-+ LIB_RSAREF="-lRSAglue -lrsaref"; cmu_have_rsaref=yes,
-+ cmu_have_rsaref=no)
-+
-+ with_openssl="yes"
-+ AC_CHECK_LIB(crypto,BIO_accept,
-+ LIBS="-lcrypto $LIB_RSAREF ${LIBS}",
-+ with_openssl="no", $LIB_RSAREF)
-+ AC_CHECK_LIB(ssl, SSL_CTX_new, LIBS="-lssl ${LIBS}",
-+ with_openssl="no", -lcrypto $LIB_RSAREF)
-+
-+ ;;
-+ *) OPENSSL_INC="-I${with_openssl}/include"
-+ OPENSSL_LIBPATH="${with_openssl}/lib"
-+ OPENSSL_LIB="-L${OPENSSL_LIBPATH}"
-+ CPPFLAGS="${CPPFLAGS} ${OPENSSL_INC}"
-+ CMU_ADD_LIBPATH(${OPENSSL_LIBPATH})
-+ CMU_ADD_LIBPATH_TO(${OPENSSL_LIBPATH}, OPENSSL_LIB)
-+ LIBS="${LIBS} -lssl -lcrypto";;
-+esac
-+
-+AC_MSG_CHECKING(for openssl)
-+AC_MSG_RESULT($with_openssl)
-+
-+if test "$with_openssl" != "no"; then
-+ AC_DEFINE(HAVE_SSL,[],[Build with SSL support?])
-+ IMAP_PROGS="$IMAP_PROGS tls_prune"
-+fi
-+AC_SUBST(OPENSSL_INC)
-+AC_SUBST(OPENSSL_LIB)
-+
-+dnl
-+dnl Allow for setting EGD socket file on systems without /dev/*random.
-+dnl
-+AC_ARG_WITH(egd-socket,
-+ [ --with-egd-socket=FILE Entropy Gathering Daemon socket pathname
-+ for systems without /dev/urandom],
-+ [ EGD_SOCKET="$withval" ]
-+ )
-+if test -n "$EGD_SOCKET" ; then
-+ AC_DEFINE_UNQUOTED(EGD_SOCKET, "$EGD_SOCKET", [Alternative to /dev/urandom?])
-+fi
-+
-+dnl
-+dnl Test for Zephyr
-+dnl
-+AC_ARG_WITH(zephyr,[ --with-zephyr[=PATH] enable Zephyr notification (installed on PATH)],
-+ with_zephyr="${withval}")
-+if test -z "$with_zephyr"; then
-+ if test -f /usr/local/lib/libzephyr.a; then
-+ with_zephyr="/usr/local"
-+ elif test -f /usr/lib/libzephyr.a; then
-+ with_zephyr="/usr"
-+ fi
-+fi
-+ZEPHYR_LIBS=""
-+ZEPHYR_CPPFLAGS=""
-+case "$with_zephyr" in
-+ no) true;;
-+ ""|yes) AC_CHECK_LIB(zephyr,ZInitialize,ZEPHYR_LIBS="-lzephyr",
-+ with_zephyr="no",);;
-+ *) if test -d ${with_zephyr}/include/zephyr; then
-+ ZEPHYR_CPPFLAGS="-I${with_zephyr}/include/zephyr"
-+ else
-+ ZEPHYR_CPPFLAGS="-I${with_zephyr}/include"
-+ fi
-+ ZEPHYR_LIBS="-lzephyr";;
-+esac
-+AC_SUBST(ZEPHYR_LIBS)
-+AC_SUBST(ZEPHYR_CPPFLAGS)
-+if test "$with_zephyr" != "no"; then
-+ AC_DEFINE(HAVE_ZEPHYR,[],[Build with Zephyr support?])
-+fi
-+
-+dnl
-+dnl Set pidfile location
-+dnl
-+AC_ARG_WITH(pidfile,[ --with-pidfile[=PATH] pidfile in PATH (/var/run/cyrus-master.pid)],
-+ [MASTERPIDFILE="$withval"],
-+ [MASTERPIDFILE="/var/run/cyrus-master.pid"])
-+MASTERPIDFILE="\"$MASTERPIDFILE\""
-+AC_DEFINE_UNQUOTED(MASTER_PIDFILE, $MASTERPIDFILE,[Name of the pidfile for master])
-+
-+dnl
-+dnl Select a method for IMAP IDLE
-+dnl
-+AC_ARG_WITH(idle,[ --with-idle=METHOD use METHOD for IMAP IDLE
-+ METHOD is [poll], idled or no],
-+ WITH_IDLE="${withval}",WITH_IDLE="poll")
-+AC_SUBST(WITH_IDLE)
-+if test "$WITH_IDLE" = "idled"; then
-+ IMAP_PROGS="$IMAP_PROGS idled"
-+fi
-+
-+dnl
-+dnl see if we're compiling with NNTP support
-+dnl
-+ENABLE_NNTP=no
-+AC_ARG_ENABLE(nntp,
-+ [ --enable-nntp enable NNTP support (experimental)],
-+ ENABLE_NNTP=$enableval
-+ if test "$ENABLE_NNTP" != no; then
-+ IMAP_PROGS="$IMAP_PROGS nntpd fetchnews"
-+ fi)
-+
-+dnl
-+dnl see if we're compiling the Murder support programs
-+dnl
-+AC_ARG_ENABLE(murder,
-+ [ --enable-murder enable IMAP Murder support],
-+ if test "$enableval" != no; then
-+ IMAP_PROGS="$IMAP_PROGS proxyd lmtpproxyd mupdate"
-+ fi)
-+
-+AC_SUBST(IMAP_PROGS)
-+
-+dnl
-+dnl Try and find a system version of com_err.
-+dnl If we see something that looks a little wacky, ignore it (there are many
-+dnl deficient installs of com_err, unfortunately, which leave out compile_et)
-+dnl
-+AC_ARG_WITH(com_err,
-+[ --with-com_err=PATH use com_err from path -- includes in PATH/include,
-+ libs in PATH/lib, and compile_et in PATH/bin])
-+if test -z "$with_com_err"; then
-+ # no value supplied
-+ AC_CHECK_LIB(com_err, com_err, [
-+ # com_err is already in library path
-+ # guess we're okay
-+ # can use system com_err
-+ with_com_err=""
-+ AC_CHECK_HEADER(et/com_err.h,
-+ [AC_DEFINE(HAVE_ET_COM_ERR_H,[],[We need et/com_err.h])],
-+ [AC_CHECK_HEADER(com_err.h,[],[AC_ERROR([cannot locate com_err.h])])])
-+ AC_PATH_PROG(COMPILE_ET, compile_et, [no compile et])
-+ ], [
-+ if test -f /usr/local/include/com_err.h -o -f /usr/local/include/et/com_err.h; then
-+ with_com_err="/usr/local"
-+ AC_PATH_PROG(COMPILE_ET, /usr/local/bin/compile_et, [no compile et])
-+ elif test -f /usr/include/com_err.h -o -f /usr/include/et/com_err.h; then
-+ with_com_err="/usr"
-+ AC_PATH_PROG(COMPILE_ET, /usr/bin/compile_et, [no compile et])
-+ else
-+ # use ours
-+ with_com_err=yes
-+ fi
-+ ])
-+
-+ if test "${with_com_err}" = "no"; then
-+ AC_MSG_WARN([com_err is required; included version will be used.])
-+ with_com_err="yes"
-+ fi
-+ if test "${COMPILE_ET}" = "no compile et" -o "${COMPILE_ET}" = ""; then
-+ AC_MSG_WARN([Parts of com_err distribuion were found, but not compile_et.])
-+ AC_MSG_WARN([Will build com_err from included sources.])
-+ with_com_err="yes" # build it ourselves
-+ fi
-+fi
-+
-+case "$with_com_err" in
-+ # built-in et
-+ yes) # use the com_err we're gonna build
-+ COM_ERR_LIBS="../et/libcom_err.a"
-+ COMPILE_ET="../et/compile_et"
-+ COM_ERR_LDFLAGS=""
-+ COM_ERR_CPPFLAGS="-I\${top_srcdir}/et"
-+ PRE_SUBDIRS="et ${PRE_SUBDIRS}"
-+ EXTRA_OUTPUT="${EXTRA_OUTPUT} et/Makefile"
-+ ;;
-+ "") # no problem, we already have it in the paths
-+ # we do nothing to pick it up
-+ COM_ERR_LIBS="-lcom_err" # hope it's not shared
-+ # we already set COMPILE_ET, or we didn't get here
-+ COM_ERR_LDFLAGS=""
-+ COM_ERR_CPPFLAGS=""
-+ ;;
-+ *) # use whatever they told us, or whatever we found
-+ COMPILE_ET="${with_com_err}/bin/compile_et"
-+ COM_ERR_LIBS="${with_com_err}/lib/libcom_err.a"
-+ COM_ERR_CPPFLAGS="-I${with_com_err}/include"
-+ # Ever get the feeling people hide this stuff on purpose?
-+ if test -d "${with_com_err}/include/et" ; then
-+ COM_ERR_CPPFLAGS="-I${with_com_err}/include/et"
-+ fi
-+dnl CMU_ADD_LIBPATH_TO(${with_com_err}/lib, COM_ERR_LDFLAGS)
-+ COMPILE_ET="${with_com_err}/bin/compile_et"
-+esac
-+AC_SUBST(COMPILE_ET)
-+AC_SUBST(COM_ERR_LIBS)
-+AC_SUBST(COM_ERR_LDFLAGS)
-+AC_SUBST(COM_ERR_CPPFLAGS)
-+
-+AC_MSG_CHECKING(for modern syslog)
-+AC_CACHE_VAL(cyrus_cv_lib_syslog, AC_TRY_CPP([#include <syslog.h>
-+#ifndef LOG_LOCAL6
-+#include </nonexistent>
-+#endif],cyrus_cv_lib_syslog=yes,cyrus_cv_lib_syslog=no))
-+if test $cyrus_cv_lib_syslog = no; then
-+ PRE_SUBDIRS="${PRE_SUBDIRS} syslog"
-+ EXTRA_OUTPUT="${EXTRA_OUTPUT} syslog/Makefile"
-+ DEPLIBS="${DEPLIBS} ../syslog/libsyslog.a"
-+ CPPFLAGS="$CPPFLAGS -I\$(srcdir)/../syslog"
-+fi
-+AC_MSG_RESULT($cyrus_cv_lib_syslog)
-+
-+AC_MSG_CHECKING(which syslog facility to use)
-+SYSLOG_FACILITY=LOG_LOCAL6
-+AC_ARG_WITH(syslogfacility,[ --with-syslogfacility=FACILITY set the syslog facility to use (default LOCAL6)],
-+ [ if test "$withval" != "yes" -a "$withval" != "no" ; then
-+ SYSLOG_FACILITY=LOG_$withval
-+ fi; ])
-+AC_DEFINE_UNQUOTED(SYSLOG_FACILITY, $SYSLOG_FACILITY, [Syslog facility to use.])
-+AC_MSG_RESULT($SYSLOG_FACILITY)
-+
-+dnl Have to check getdtabalesize after adding ossup, as some ossups define it
-+AC_REPLACE_FUNCS(getdtablesize)
-+AC_ARG_ENABLE(cmulocal,
-+ [ --enable-cmulocal enable CMU-specific local support],
-+ if test "$enableval" = yes; then
-+ EXTRA_SUBDIRS="${EXTRA_SUBDIRS} netnews depot"
-+ EXTRA_OUTPUT="${EXTRA_OUTPUT} depot/Makefile"
-+ fi)
-+
-+AC_MSG_CHECKING(to use old sieve service name)
-+AC_ARG_ENABLE(oldsievename,
-+ [ --enable-oldsievename enable the use of 'imap' as the sieve service name],
-+ if test "$enableval" = yes; then
-+ AC_MSG_RESULT(yes)
-+ AC_DEFINE(OLD_SIEVE_SERVICE_NAME,[],[Use "imap" as sieve service name?])
-+ else
-+ AC_MSG_RESULT(no)
-+ fi,
-+ AC_MSG_RESULT(no))
-+
-+AC_ARG_ENABLE(listext,
-+ [ --enable-listext enable IMAP List extensions],
-+ if test "$enableval" = yes; then
-+ AC_DEFINE(ENABLE_LISTEXT,[],[Enable the LISTEXT extension?])
-+ fi)
-+
-+AC_ARG_ENABLE(netscapehack,
-+ [ --enable-netscapehack enable Netscape hack for the menu option
-+ in Communicator to Administrate Mail],
-+ if test "$enableval" = yes; then
-+ AC_DEFINE(ENABLE_X_NETSCAPE_HACK,[],[Enable Netscape Menu Option Hack?])
-+ fi)
-+
-+AC_CHECK_FUNC(dlopen,,[AC_CHECK_LIB(dl, dlopen)])
-+CMU_SASL2_REQUIRE_VER(2,1,7)
-+CMU_SASL2_CHECKAPOP_REQUIRED
-+
-+AC_ARG_WITH(perl, [ --with-perl=PERL use PERL for perl],
-+ with_perl="$withval", with_perl="perl")
-+
-+if test "${with_perl}" = yes; then
-+ with_perl="perl"
-+fi
-+if test "${with_perl}" != no; then
-+ if test ${using_static_sasl} = "staticonly"; then
-+ AC_MSG_WARN([Cannot compile perl utilities using static libsasl])
-+ with_perl="no"
-+ else
-+ AC_CHECK_PROGS(PERL, ${with_perl} perl, with_perl=notfound)
-+ fi
-+fi
-+if test "$with_perl" = "notfound"; then
-+ AC_MSG_WARN(Perl not found: Administrative tools won't be available)
-+elif test "${with_perl}" != "no"; then
-+dnl compile perl stuff
-+ EXTRA_SUBDIRS="${EXTRA_SUBDIRS} perl"
-+dnl and compile perl/cyradm
-+ PERL_SUBDIRS="imap"
-+ PERL="${with_perl}"
-+dnl add perl cccdlflags when building libraries -- this ensures that the
-+dnl libraries will be compiled as PIC if perl requires PIC objects
-+dnl -- this is needed on NetBSD, but seems to cause problems on atleast Solaris --
-+dnl eval `${PERL} -V:cccdlflags`
-+ PERL_CCCDLFLAGS="$cccdlflags"
-+ AC_SUBST(PERL_CCCDLFLAGS)
-+fi
-+
-+dnl for timsieved
-+if test "$sievedir" != "no"; then
-+ EXTRA_SUBDIRS="${EXTRA_SUBDIRS} timsieved notifyd"
-+ EXTRA_OUTPUT="${EXTRA_OUTPUT} timsieved/Makefile notifyd/Makefile"
-+
-+ PERL_SUBDIRS="${PERL_SUBDIRS} sieve"
-+ PERL_DEPSUBDIRS="sieve"
-+ EXTRA_OUTPUT="${EXTRA_OUTPUT} perl/sieve/Makefile perl/sieve/lib/Makefile"
-+else
-+ PERL_DEPSUBDIRS="none"
-+fi
-+
-+dnl Check for MD5 functions
-+AC_FUNC_CHECK(MD5Init,,
-+ AC_CHECK_LIB(md, MD5Init, LIBS="${LIBS} -lmd",
-+ MD5OBJ="md5.o"))
-+AC_SUBST(MD5OBJ)
-+
-+dnl snmp
-+dnl (agentx was depricated, but SNMP_SUBDIRS is conveinent as a placeholder)
-+SNMP_SUBDIRS=""
-+AC_SUBST(SNMP_SUBDIRS)
-+
-+CMU_LIBWRAP
-+CMU_UCDSNMP
-+
-+# Figure out what directories we're linking against.
-+# Lots of fun for the whole family.
-+# This probably chokes on anything with spaces in it.
-+# All we want is the list of -L directories, and -L may or may not be
-+# followed by a space.
-+isdir=no
-+libpath=""
-+#echo "debug ldflags: << ${ldflags} >>"
-+#echo "debug default_ldflags: << ${default_ldflags} >>"
-+for flag in ${ldflags} ${default_ldflags}; do
-+ case $flag in
-+ -L)
-+ # it's a split -L option, we'll mark the next option as a dir.
-+ isdir=yes
-+ ;;
-+
-+ -L*)
-+ # attached -L option: split off the directory
-+ larg=`echo $flag | sed -e 's:-L\(..*\):\1:'`
-+ libpath="${libpath} ${larg}"
-+ ;;
-+
-+ *)
-+ if test $isdir = yes ; then
-+ libpath="${libpath} ${flag}"
-+ isdir=no
-+ fi
-+ esac
-+done
-+
-+IMAP_COM_ERR_LIBS="${COM_ERR_LIBS}"
-+IMAP_LIBS="${LIB_SASL} ${LIBS}"
-+
-+AC_SUBST(LIB_RT)
-+AC_SUBST(IMAP_COM_ERR_LIBS)
-+AC_SUBST(IMAP_LIBS)
-+
-+dnl AC_OUTPUT_COMMANDS([
-+dnl if test "$with_perl" != "no"; then
-+dnl (cd perl/sieve/managesieve; $perl Makefile.PL PREFIX=$prefix)
-+dnl (cd perl/imap; $perl Makefile.PL PREFIX=$prefix)
-+dnl fi
-+dnl ], perl=$PERL; with_perl=$with_perl; prefix=$prefix; SASL_LIB="$LIB_SASL"; SASL_INC="$SASLFLAGS"; export SASL_LIB SASL_INC)
-+AC_SUBST(PERL_SUBDIRS)
-+AC_SUBST(PERL_DEPSUBDIRS)
-+AC_SUBST(PERL)
-+
-+AH_TOP([
-+/* $Id: configure.in,v 1.290 2005/01/18 23:46:00 shadow Exp $ */
-+/*
-+ * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ *
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ *
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in
-+ * the documentation and/or other materials provided with the
-+ * distribution.
-+ *
-+ * 3. The name "Carnegie Mellon University" must not be used to
-+ * endorse or promote products derived from this software without
-+ * prior written permission. For permission or any other legal
-+ * details, please contact
-+ * Office of Technology Transfer
-+ * Carnegie Mellon University
-+ * 5000 Forbes Avenue
-+ * Pittsburgh, PA 15213-3890
-+ * (412) 268-4387, fax: (412) 268-7395
-+ * tech-transfer at andrew.cmu.edu
-+ *
-+ * 4. Redistributions of any form whatsoever must retain the following
-+ * acknowledgment:
-+ * "This product includes software developed by Computing Services
-+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
-+ *
-+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
-+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
-+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
-+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
-+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+#ifndef _CYRUS_IMAPD_CONFIG_H_
-+#define _CYRUS_IMAPD_CONFIG_H_
-+])
-+
-+AH_BOTTOM([
-+/* time.h */
-+#if TIME_WITH_SYS_TIME
-+# include <sys/time.h>
-+# include <time.h>
-+#else
-+# if HAVE_SYS_TIME_H
-+# include <sys/time.h>
-+# else
-+# include <time.h>
-+# endif
-+#endif
-+
-+/* com_err.h, as needed */
-+#ifndef IN_COM_ERR
-+#ifdef HAVE_ET_COM_ERR_H
-+#include <et/com_err.h>
-+#else
-+#include <com_err.h>
-+#endif /* HAVE_ET_COM_ERR_H */
-+#endif /* IN_COM_ERR */
-+
-+/* This allows us to work even when we don't have an fdatasync */
-+#ifndef HAVE_FDATASYNC
-+#define fdatasync(fd) fsync(fd)
-+#endif
-+
-+/* A similar setup for not having O_DSYNC */
-+#include <fcntl.h>
-+
-+#ifndef O_DSYNC
-+# ifdef O_SYNC
-+# define O_DSYNC O_SYNC /* POSIX */
-+# else
-+# define O_DSYNC O_FSYNC /* BSD */
-+# endif
-+#endif
-+
-+#ifndef HAVE___ATTRIBUTE__
-+/* Can't use attributes... */
-+#define __attribute__(foo)
-+#endif
-+
-+#ifndef HAVE_SOCKLEN_T
-+typedef unsigned int socklen_t;
-+#endif
-+
-+#ifndef HAVE_RLIM_T
-+typedef int rlim_t;
-+#endif
-+
-+/* some potentially memory saving tradeoffs,
-+ preconfigured in memory-saving mode */
-+
-+/* save the cmdlines for the ID command */
-+#undef ID_SAVE_CMDLINE
-+
-+/* IPv6 things */
-+#include <netdb.h>
-+#include <sys/types.h>
-+#include <sys/socket.h>
-+#include <netinet/in.h>
-+
-+#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
-+#define _SS_MAXSIZE 128 /* Implementation specific max size */
-+#define _SS_PADSIZE (_SS_MAXSIZE - sizeof (struct sockaddr))
-+
-+struct sockaddr_storage {
-+ struct sockaddr ss_sa;
-+ char __ss_pad2[_SS_PADSIZE];
-+};
-+# define ss_family ss_sa.sa_family
-+# define HAVE_SS_FAMILY
-+#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */
-+
-+#ifndef HAVE_SS_FAMILY
-+#define ss_family __ss_family
-+#endif
-+
-+#ifndef AF_INET6
-+/* Define it to something that should never appear */
-+#define AF_INET6 AF_MAX
-+#endif
-+
-+#if !defined(HAVE_GETADDRINFO) || !defined(HAVE_GETNAMEINFO)
-+#include "gai.h"
-+#endif
-+
-+/* End IPv6 things */
-+
-+#ifdef OLD_SIEVE_SERVICE_NAME
-+#define SIEVE_SERVICE_NAME "imap"
-+#else
-+#define SIEVE_SERVICE_NAME "sieve"
-+#endif
-+
-+/* filenames */
-+#define FNAME_DBDIR "/db"
-+#define FNAME_USERDIR "/user/"
-+#define FNAME_DOMAINDIR "/domain/"
-+#define FNAME_LOGDIR "/log/"
-+#define FNAME_PTSDB "/ptclient/ptscache.db"
-+#define CONFIG_FILENAME (SYSCONFDIR "/imapd.conf")
-+#define DEFAULT_MASTER_CONFIG_FILENAME (SYSCONFDIR "/cyrus.conf")
-+
-+#ifndef HAVE_SHUTDOWN
-+#define shutdown(fd, mode) 0
-+#endif
-+
-+/* compile time options; think carefully before modifying */
-+enum {
-+ /* should we send an UNAVAILABLE message to master when
-+ * a service is exiting (master is already going to be
-+ * informed of the exit by the SIGCHLD signal anyway) ? */
-+ MESSAGE_MASTER_ON_EXIT = 0,
-+
-+ /* should a hierarchical rename stop on error? */
-+ RENAME_STOP_ON_ERROR = 1,
-+
-+ /* should we call fsync() to maybe help with softupdates? (it should) */
-+ APPEND_ULTRA_PARANOID = 1,
-+
-+ /* should we log extra information at the DEBUG level for DB stuff?
-+ * 0 -> nothing; 1 -> some; higher -> even more */
-+ CONFIG_DB_VERBOSE = 1,
-+
-+ /* log timing information to LOG_DEBUG */
-+ CONFIG_TIMING_VERBOSE = 0,
-+
-+ /* should we be pedantic about namespace or sleezy? */
-+ SLEEZY_NAMESPACE = 1,
-+
-+ /* should we do a fast TLS session shutdown? */
-+ TLS_FAST_SHUTDOWN = 1,
-+
-+ /* should we use the SQUAT engine to accelerate SEARCH? */
-+ SQUAT_ENGINE = 1,
-+
-+ /* should we have long LMTP error messages? */
-+ LMTP_LONG_ERROR_MSGS = 1,
-+
-+ /* default time to wait, in seconds, before giving up
-+ * trying to lock something */
-+ LOCK_GIVEUP_TIMER_DEFAULT = 100
-+};
-+
-+#endif /* _CYRUS_IMAPD_CONFIG_H_ */
-+])
-+
-+dnl make sure that Makefile is the last thing output
-+AC_OUTPUT(man/Makefile master/Makefile lib/Makefile imap/Makefile imtest/Makefile netnews/Makefile perl/Makefile $EXTRA_OUTPUT Makefile)
-diff -urNad cyrus-imapd-2.2.12/imap/Makefile.in /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/imap/Makefile.in
---- cyrus-imapd-2.2.12/imap/Makefile.in 2005-05-24 20:41:38.000000000 +0200
-+++ /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/imap/Makefile.in 2005-05-24 20:45:11.549995030 +0200
+diff -urNad cyrus-imapd-2.2.12/imap/Makefile.in /tmp/dpep.MaSf95/cyrus-imapd-2.2.12/imap/Makefile.in
+--- cyrus-imapd-2.2.12/imap/Makefile.in 2005-05-24 22:16:17.000000000 +0200
++++ /tmp/dpep.MaSf95/cyrus-imapd-2.2.12/imap/Makefile.in 2005-05-25 00:50:07.977145500 +0200
@@ -69,6 +69,7 @@
SIEVE_LIBS = @SIEVE_LIBS@
IMAP_COM_ERR_LIBS = @IMAP_COM_ERR_LIBS@
@@ -1310,367 +69,9 @@
nntpd: nntpd.o backend.o index.o smtpclient.o spool.o tls.o \
mutex_fake.o nntp_err.o libimap.a $(DEPLIBS) $(SERVICE)
-diff -urNad cyrus-imapd-2.2.12/imap/Makefile.in.orig /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/imap/Makefile.in.orig
---- cyrus-imapd-2.2.12/imap/Makefile.in.orig 1970-01-01 01:00:00.000000000 +0100
-+++ /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/imap/Makefile.in.orig 2005-05-24 20:41:38.000000000 +0200
-@@ -0,0 +1,354 @@
-+# Makefile for cyrus imap server and associated programs
-+# $Id: Makefile.in,v 1.184 2004/05/28 18:03:02 rjs3 Exp $
-+#
-+# @configure_input@
-+#
-+# Copyright (c) 1998-2000 Carnegie Mellon University. All rights reserved.
-+#
-+# Redistribution and use in source and binary forms, with or without
-+# modification, are permitted provided that the following conditions
-+# are met:
-+#
-+# 1. Redistributions of source code must retain the above copyright
-+# notice, this list of conditions and the following disclaimer.
-+#
-+# 2. Redistributions in binary form must reproduce the above copyright
-+# notice, this list of conditions and the following disclaimer in
-+# the documentation and/or other materials provided with the
-+# distribution.
-+#
-+# 3. The name "Carnegie Mellon University" must not be used to
-+# endorse or promote products derived from this software without
-+# prior written permission. For permission or any other legal
-+# details, please contact
-+# Office of Technology Transfer
-+# Carnegie Mellon University
-+# 5000 Forbes Avenue
-+# Pittsburgh, PA 15213-3890
-+# (412) 268-4387, fax: (412) 268-7395
-+# tech-transfer at andrew.cmu.edu
-+#
-+# 4. Redistributions of any form whatsoever must retain the following
-+# acknowledgment:
-+# "This product includes software developed by Computing Services
-+# at Carnegie Mellon University (http://www.cmu.edu/computing/)."
-+#
-+# CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
-+# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-+# AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
-+# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
-+# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
-+# OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+#
-+DEFINES=-DSETPROCTITLE
-+
-+# \Seen state database. Either 'db' (berkeley db) or
-+# 'local' (legacy flat file).
-+SEEN=seen_db.o
-+
-+# IMAP IDLE mechanism
-+IDLE=idle_ at WITH_IDLE@.o
-+
-+srcdir = @srcdir@
-+top_srcdir = @top_srcdir@
-+VPATH = @srcdir@
-+
-+CC = @CC@
-+INSTALL = @INSTALL@
-+RANLIB = @RANLIB@
-+AWK = @AWK@
-+
-+CYRUS_USER=@cyrus_user@
-+CYRUS_GROUP=@cyrus_group@
-+
-+DEFS = @DEFS@ @LOCALDEFS@
-+CPPFLAGS = -I.. -I$(srcdir)/../lib @COM_ERR_CPPFLAGS@ @SIEVE_CPPFLAGS@ @CPPFLAGS@ @SASLFLAGS@
-+IMAP_LIBS = @IMAP_LIBS@ @LIB_RT@
-+SIEVE_OBJS = @SIEVE_OBJS@
-+SIEVE_LIBS = @SIEVE_LIBS@
-+IMAP_COM_ERR_LIBS = @IMAP_COM_ERR_LIBS@
-+LIB_WRAP = @LIB_WRAP@
-+LIBS = $(IMAP_LIBS) $(IMAP_COM_ERR_LIBS)
-+DEPLIBS = ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
-+
-+CFLAGS = @CFLAGS@ @WARNERROR@
-+LDFLAGS = @LDFLAGS@ @COM_ERR_LDFLAGS@
-+
-+SHELL = /bin/sh
-+MAKEDEPEND = @MAKEDEPEND@
-+
-+COMPILE_ET=@COMPILE_ET@
-+
-+#
-+# Some notes on purify --
-+# you probably want to run the make as the cyrus user as
-+# purify sets the cache directory based on the user. So,
-+# if you don't, purify can't find the instrumented libraries
-+# and so you don't get any useful information.
-+# It may also help to run purify by hand to instrument any of
-+# the dynamic libraries that may crop up during run time.
-+#
-+PURIFY=/usr/local/bin/purify
-+PUREOPT= -best-effort -logfile=/tmp/pure/%v.%p.log -always_use_cache_dir -cachedir=/usr/tmp/$(USER)
-+QUANTIFY=/usr/local/bin/quantify
-+QUANTOPT=-windows=no -filename-prefix=/tmp/quant/%v.%p -write-summary-file= -logfile=/tmp/quant/%v.%p.log
-+
-+prefix = @prefix@
-+exec_prefix = @exec_prefix@
-+cyrus_prefix = @cyrus_prefix@
-+service_path = @service_path@
-+
-+LOBJS= append.o mailbox.o mboxlist.o mupdate-client.o mboxname.o message.o \
-+ global.o imap_err.o mupdate_err.o proc.o setproctitle.o \
-+ convert_code.o duplicate.o saslclient.o saslserver.o signals.o \
-+ annotate.o search_engines.o squat.o squat_internal.o mbdump.o \
-+ imapparse.o telemetry.o user.o notify.o protocol.o quota_db.o \
-+ $(SEEN) $(IDLE)
-+
-+IMAPDOBJS=pushstats.o backend.o imapd.o index.o tls.o version.o
-+
-+PROXYDOBJS=backend.o pushstats.o proxyd.o tls.o version.o
-+
-+LMTPOBJS=lmtpstats.o lmtpengine.o spool.o tls.o
-+
-+# Your typical objects for the command line utilities
-+CLIOBJS=cli_fatal.o mutex_fake.o
-+
-+SERVICE=../master/service.o
-+SERVICETHREAD=../master/service-thread.o
-+
-+PROGS = imapd lmtpd pop3d \
-+ fud smmapd reconstruct quota mbpath ipurge \
-+ cyrdump chk_cyrus cvt_cyrusdb deliver ctl_mboxlist \
-+ ctl_deliver ctl_cyrusdb squatter mbexamine cyr_expire arbitron \
-+ @IMAP_PROGS@
-+
-+BUILTSOURCES = imap_err.c imap_err.h pushstats.c pushstats.h \
-+ lmtpstats.c lmtpstats.h xversion.h mupdate_err.c mupdate_err.h \
-+ nntp_err.c nntp_err.h
-+
-+all: $(BUILTSOURCES) $(PROGS) $(SUIDPROGS)
-+
-+pure: imapd.pure lmtpd.pure proxyd.pure mupdate.pure lmtpproxyd.pure
-+
-+
-+install:
-+ $(srcdir)/../install-sh -d ${DESTDIR}$(service_path)
-+ for file in $(PROGS); \
-+ do \
-+ $(INSTALL) -m 755 $$file $(DESTDIR)$(service_path) || exit 1; \
-+ done
-+ ln -f $(DESTDIR)$(service_path)/pop3d $(DESTDIR)$(service_path)/pop3proxyd
-+
-+.c.o:
-+ $(CC) -c $(CPPFLAGS) $(DEFS) $(CFLAGS) \
-+ $<
-+
-+### libimap
-+
-+libimap.a: $(LOBJS)
-+ rm -f libimap.a
-+ ar cr libimap.a $(LOBJS)
-+ $(RANLIB) libimap.a
-+
-+### Built Source Files
-+
-+xversion:
-+ rm -f version.o
-+ AWK=$(AWK) $(srcdir)/xversion.sh
-+
-+xversion.h: xversion
-+
-+pushstats.c: pushstats.snmp $(srcdir)/../snmp/snmpgen
-+ $(srcdir)/../snmp/snmpgen $(srcdir)/pushstats.snmp
-+
-+pushstats.h: pushstats.c
-+
-+lmtpstats.c: lmtpstats.snmp $(srcdir)/../snmp/snmpgen
-+ $(srcdir)/../snmp/snmpgen $(srcdir)/lmtpstats.snmp
-+
-+lmtpstats.h: lmtpstats.c
-+
-+imap_err.c: imap_err.et
-+ $(COMPILE_ET) $(srcdir)/imap_err.et
-+
-+imap_err.h: imap_err.c
-+
-+nntp_err.c: nntp_err.et
-+ $(COMPILE_ET) $(srcdir)/nntp_err.et
-+
-+nntp_err.h: nntp_err.c
-+
-+mupdate_err.c: mupdate_err.et
-+ $(COMPILE_ET) $(srcdir)/mupdate_err.et
-+
-+mupdate_err.h: mupdate_err.c
-+
-+### Services
-+idled: idled.o mutex_fake.o libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o idled \
-+ idled.o mutex_fake.o libimap.a $(DEPLIBS) $(LIBS)
-+
-+lmtpd: lmtpd.o $(LMTPOBJS) $(SIEVE_OBJS) mutex_fake.o libimap.a $(SIEVE_LIBS) \
-+ $(DEPLIBS) $(SERVICE)
-+ $(CC) $(LDFLAGS) -o lmtpd \
-+ $(SERVICE) lmtpd.o $(LMTPOBJS) $(SIEVE_OBJS) mutex_fake.o \
-+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
-+
-+lmtpd.pure: lmtpd.o $(LMTPOBJS) $(SIEVE_OBJS) mutex_fake.o \
-+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
-+ $(PURIFY) $(PUREOPT) $(CC) $(LDFLAGS) -o lmtpd.pure \
-+ $(SERVICE) lmtpd.o $(LMTPOBJS) $(SIEVE_OBJS) mutex_fake.o \
-+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
-+
-+lmtpproxyd: lmtpproxyd.o backend.o $(LMTPOBJS) mutex_fake.o \
-+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
-+ $(CC) $(LDFLAGS) -o lmtpproxyd \
-+ $(SERVICE) lmtpproxyd.o backend.o $(LMTPOBJS) mutex_fake.o \
-+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
-+
-+lmtpproxyd.pure: lmtpproxyd.o backend.o $(LMTPOBJS) mutex_fake.o \
-+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
-+ $(PURIFY) $(PUREOPT) $(CC) $(LDFLAGS) -o lmtpproxyd.pure \
-+ $(SERVICE) lmtpproxyd.o backend.o $(LMTPOBJS) mutex_fake.o \
-+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
-+
-+imapd: xversion $(IMAPDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
-+ $(CC) $(LDFLAGS) -o imapd \
-+ $(SERVICE) $(IMAPDOBJS) mutex_fake.o \
-+ libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP)
-+
-+imapd.pure: $(IMAPDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
-+ $(PURIFY) $(PUREOPT) $(CC) $(LDFLAGS) -o imapd.pure \
-+ $(SERVICE) $(IMAPDOBJS) mutex_fake.o libimap.a \
-+ $(DEPLIBS) $(LIBS) $(LIB_WRAP)
-+
-+imapd.quant: $(IMAPDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
-+ $(QUANTIFY) $(QUANTOPT) $(CC) $(LDFLAGS) -o imapd.quant \
-+ $(SERVICE) $(IMAPDOBJS) mutex_fake.o libimap.a \
-+ $(DEPLIBS) $(LIBS) $(LIB_WRAP)
-+
-+proxyd: $(PROXYDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
-+ $(CC) $(LDFLAGS) -o proxyd \
-+ $(SERVICE) $(PROXYDOBJS) mutex_fake.o libimap.a \
-+ $(DEPLIBS) $(LIBS) $(LIB_WRAP)
-+
-+proxyd.pure: $(PROXYDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
-+ $(PURIFY) $(PUREOPT) $(CC) $(LDFLAGS) -o proxyd.pure \
-+ $(SERVICE) $(PROXYDOBJS) mutex_fake.o libimap.a \
-+ $(DEPLIBS) $(LIBS) $(LIB_WRAP)
-+
-+mupdate: mupdate.o mupdate-slave.o mupdate-client.o mutex_pthread.o tls.o \
-+ libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o mupdate \
-+ $(SERVICETHREAD) mupdate.o mupdate-slave.o mupdate-client.o \
-+ mutex_pthread.o tls.o libimap.a \
-+ $(DEPLIBS) $(LIBS) $(LIB_WRAP) -lpthread
-+
-+mupdate.pure: mupdate.o mupdate-slave.o mupdate-client.o mutex_pthread.o \
-+ libimap.a $(DEPLIBS)
-+ $(PURIFY) $(PUREOPT) $(CC) $(LDFLAGS) -o mupdate.pure \
-+ $(SERVICETHREAD) mupdate.o mupdate-slave.o mupdate-client.o \
-+ mutex_pthread.o libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP) -lpthread
-+
-+pop3d: pop3d.o backend.o tls.o mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
-+ $(CC) $(LDFLAGS) -o pop3d pop3d.o backend.o tls.o $(SERVICE) \
-+ mutex_fake.o libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP)
-+
-+nntpd: nntpd.o backend.o index.o smtpclient.o spool.o tls.o \
-+ mutex_fake.o nntp_err.o libimap.a $(DEPLIBS) $(SERVICE)
-+ $(CC) $(LDFLAGS) -o nntpd nntpd.o backend.o index.o spool.o \
-+ smtpclient.o tls.o $(SERVICE) mutex_fake.o nntp_err.o \
-+ libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP)
-+
-+fud: fud.o libimap.a mutex_fake.o $(DEPLIBS) $(SERVICE)
-+ $(CC) $(LDFLAGS) -o fud $(SERVICE) fud.o mutex_fake.o libimap.a \
-+ $(DEPLIBS) $(LIBS) $(LIB_WRAP)
-+
-+smmapd: smmapd.o libimap.a mutex_fake.o $(DEPLIBS) $(SERVICE)
-+ $(CC) $(LDFLAGS) -o smmapd $(SERVICE) smmapd.o mutex_fake.o libimap.a \
-+ $(DEPLIBS) $(LIBS) $(LIB_WRAP)
-+
-+### Command Line Utilities
-+arbitron: arbitron.o $(CLIOBJS) libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o arbitron arbitron.o $(CLIOBJS) \
-+ libimap.a $(DEPLIBS) $(LIBS)
-+
-+cvt_cyrusdb: cvt_cyrusdb.o mutex_fake.o libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o cvt_cyrusdb cvt_cyrusdb.o $(CLIOBJS) \
-+ libimap.a $(DEPLIBS) $(LIBS)
-+
-+chk_cyrus: chk_cyrus.o mutex_fake.o libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o chk_cyrus chk_cyrus.o $(CLIOBJS) \
-+ libimap.a $(DEPLIBS) $(LIBS)
-+
-+deliver: deliver.o backend.o $(LMTPOBJS) mutex_fake.o libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o deliver deliver.o backend.o $(LMTPOBJS) \
-+ mutex_fake.o libimap.a $(DEPLIBS) $(LIBS)
-+
-+ctl_deliver: ctl_deliver.o $(CLIOBJS) libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o \
-+ $@ ctl_deliver.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
-+
-+ctl_mboxlist: ctl_mboxlist.o mupdate-client.o $(CLIOBJS) libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o $@ ctl_mboxlist.o mupdate-client.o $(CLIOBJS) \
-+ libimap.a $(DEPLIBS) $(LIBS)
-+
-+ctl_cyrusdb: ctl_cyrusdb.o $(CLIOBJS) libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o \
-+ $@ ctl_cyrusdb.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
-+
-+cyr_expire: cyr_expire.o $(CLIOBJS) libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o $@ cyr_expire.o $(CLIOBJS) \
-+ libimap.a $(DEPLIBS) $(LIBS)
-+
-+fetchnews: fetchnews.o $(CLIOBJS) libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o \
-+ $@ fetchnews.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
-+
-+squatter: squatter.o index.o squat_build.o $(CLIOBJS) libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o squatter squatter.o index.o squat_build.o \
-+ $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
-+
-+mbpath: mbpath.o $(CLIOBJS) libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o mbpath mbpath.o $(CLIOBJS) libimap.a \
-+ $(DEPLIBS) $(LIBS)
-+
-+ipurge: ipurge.o $(CLIOBJS) libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o ipurge ipurge.o $(CLIOBJS) \
-+ libimap.a $(DEPLIBS) $(LIBS)
-+
-+cyrdump: cyrdump.o index.o $(CLIOBJS) libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o cyrdump cyrdump.o index.o $(CLIOBJS) \
-+ libimap.a $(DEPLIBS) $(LIBS)
-+
-+mbexamine: mbexamine.o $(CLIOBJS) libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o \
-+ mbexamine mbexamine.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
-+
-+reconstruct: reconstruct.o $(CLIOBJS) libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o \
-+ reconstruct reconstruct.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
-+
-+quota: quota.o $(CLIOBJS) libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o quota quota.o $(CLIOBJS) \
-+ libimap.a $(DEPLIBS) $(LIBS)
-+
-+tls_prune: tls_prune.o tls.o $(CLIOBJS) libimap.a $(DEPLIBS)
-+ $(CC) $(LDFLAGS) -o \
-+ $@ tls_prune.o tls.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
-+
-+### Other Misc Targets
-+
-+clean:
-+ rm -f *.o *.a Makefile.bak makedepend.log \
-+ $(BUILTSOURCES) $(PROGS) $(SUIDPROGS)
-+
-+distclean: clean
-+ rm -f Makefile
-+
-+depend: imap_err.h
-+ ${MAKEDEPEND} $(CPPFLAGS) $(DEFS) $(CFLAGS) *.c $(srcdir)/*.c 1>makedepend.log 2>&1
-+
-+# DO NOT DELETE THIS LINE -- make depend depends on it.
-diff -urNad cyrus-imapd-2.2.12/imap/imapd.c /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/imap/imapd.c
---- cyrus-imapd-2.2.12/imap/imapd.c 2005-05-24 20:41:38.000000000 +0200
-+++ /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/imap/imapd.c 2005-05-24 20:45:11.555995570 +0200
+diff -urNad cyrus-imapd-2.2.12/imap/imapd.c /tmp/dpep.MaSf95/cyrus-imapd-2.2.12/imap/imapd.c
+--- cyrus-imapd-2.2.12/imap/imapd.c 2005-05-24 22:16:17.000000000 +0200
++++ /tmp/dpep.MaSf95/cyrus-imapd-2.2.12/imap/imapd.c 2005-05-25 00:50:08.037150904 +0200
@@ -137,6 +137,18 @@
1, 1, &imapd_authstate, &imapd_userisadmin, &imapd_userisproxyadmin
};
@@ -1813,7620 +214,9 @@
/* Create telemetry log */
imapd_logfd = telemetry_log(imapd_userid, imapd_in, imapd_out, 0);
-diff -urNad cyrus-imapd-2.2.12/imap/imapd.c.orig /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/imap/imapd.c.orig
---- cyrus-imapd-2.2.12/imap/imapd.c.orig 1970-01-01 01:00:00.000000000 +0100
-+++ /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/imap/imapd.c.orig 2005-05-24 20:41:38.000000000 +0200
-@@ -0,0 +1,7607 @@
-+/*
-+ * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ *
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ *
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in
-+ * the documentation and/or other materials provided with the
-+ * distribution.
-+ *
-+ * 3. The name "Carnegie Mellon University" must not be used to
-+ * endorse or promote products derived from this software without
-+ * prior written permission. For permission or any other legal
-+ * details, please contact
-+ * Office of Technology Transfer
-+ * Carnegie Mellon University
-+ * 5000 Forbes Avenue
-+ * Pittsburgh, PA 15213-3890
-+ * (412) 268-4387, fax: (412) 268-7395
-+ * tech-transfer at andrew.cmu.edu
-+ *
-+ * 4. Redistributions of any form whatsoever must retain the following
-+ * "This product includes software developed by Computing Services
-+ * acknowledgment:
-+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
-+ *
-+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
-+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
-+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
-+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
-+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+/* $Id: imapd.c,v 1.490 2005/02/14 06:39:55 shadow Exp $ */
-+
-+#include <config.h>
-+
-+#ifdef HAVE_UNISTD_H
-+#include <unistd.h>
-+#endif
-+#include <stdio.h>
-+#include <string.h>
-+#include <ctype.h>
-+#include <errno.h>
-+#include <signal.h>
-+#include <fcntl.h>
-+#include <sys/types.h>
-+#include <sys/param.h>
-+#include <sys/stat.h>
-+#include <syslog.h>
-+#include <netdb.h>
-+#include <sys/socket.h>
-+#include <sys/wait.h>
-+#include <netinet/in.h>
-+#include <arpa/inet.h>
-+
-+#include <sasl/sasl.h>
-+
-+#include "acl.h"
-+#include "annotate.h"
-+#include "append.h"
-+#include "auth.h"
-+#include "backend.h"
-+#include "charset.h"
-+#include "exitcodes.h"
-+#include "idle.h"
-+#include "global.h"
-+#include "imap_err.h"
-+#include "imapd.h"
-+#include "imapurl.h"
-+#include "imparse.h"
-+#include "iptostring.h"
-+#include "mailbox.h"
-+#include "message.h"
-+#include "mboxname.h"
-+#include "mboxlist.h"
-+#include "mbdump.h"
-+#include "mkgmtime.h"
-+#include "mupdate-client.h"
-+#include "quota.h"
-+#include "telemetry.h"
-+#include "tls.h"
-+#include "user.h"
-+#include "util.h"
-+#include "version.h"
-+#include "xmalloc.h"
-+
-+#include "pushstats.h" /* SNMP interface */
-+
-+extern void seen_done(void);
-+
-+extern int optind;
-+extern char *optarg;
-+
-+/* global state */
-+const int config_need_data = CONFIG_NEED_PARTITION_DATA;
-+
-+static char shutdownfilename[1024];
-+static int imaps = 0;
-+static sasl_ssf_t extprops_ssf = 0;
-+
-+/* per-user/session state */
-+struct protstream *imapd_out = NULL;
-+struct protstream *imapd_in = NULL;
-+static char imapd_clienthost[NI_MAXHOST*2+1] = "[local]";
-+static int imapd_logfd = -1;
-+char *imapd_userid;
-+static char *imapd_magicplus = NULL;
-+struct auth_state *imapd_authstate = 0;
-+static int imapd_userisadmin = 0;
-+static int imapd_userisproxyadmin = 0;
-+static sasl_conn_t *imapd_saslconn; /* the sasl connection context */
-+static int imapd_starttls_done = 0; /* have we done a successful starttls? */
-+#ifdef HAVE_SSL
-+/* our tls connection, if any */
-+static SSL *tls_conn = NULL;
-+#endif /* HAVE_SSL */
-+
-+/* stage(s) for APPEND */
-+struct appendstage {
-+ struct stagemsg *stage;
-+ char **flag;
-+ int nflags, flagalloc;
-+ time_t internaldate;
-+} **stage = NULL;
-+unsigned long numstage = 0;
-+
-+/* the sasl proxy policy context */
-+static struct proxy_context imapd_proxyctx = {
-+ 1, 1, &imapd_authstate, &imapd_userisadmin, &imapd_userisproxyadmin
-+};
-+
-+/* current sub-user state */
-+static struct mailbox mboxstruct;
-+static struct mailbox *imapd_mailbox;
-+int imapd_exists = -1;
-+
-+/* current namespace */
-+static struct namespace imapd_namespace;
-+
-+static const char *monthname[] = {
-+ "jan", "feb", "mar", "apr", "may", "jun",
-+ "jul", "aug", "sep", "oct", "nov", "dec"
-+};
-+
-+static const int max_monthdays[] = {
-+ 31, 29, 31, 30, 31, 30,
-+ 31, 31, 30, 31, 30, 31
-+};
-+
-+void motd_file(int fd);
-+void shut_down(int code);
-+void fatal(const char *s, int code);
-+
-+void cmdloop(void);
-+void cmd_login(char *tag, char *user);
-+void cmd_authenticate(char *tag, char *authtype, char *resp);
-+void cmd_noop(char *tag, char *cmd);
-+void cmd_capability(char *tag);
-+void cmd_append(char *tag, char *name);
-+void cmd_select(char *tag, char *cmd, char *name);
-+void cmd_close(char *tag);
-+void cmd_fetch(char *tag, char *sequence, int usinguid);
-+void cmd_partial(const char *tag, const char *msgno, char *data,
-+ const char *start, const char *count);
-+void cmd_store(char *tag, char *sequence, char *operation, int usinguid);
-+void cmd_search(char *tag, int usinguid);
-+void cmd_sort(char *tag, int usinguid);
-+void cmd_thread(char *tag, int usinguid);
-+void cmd_copy(char *tag, char *sequence, char *name, int usinguid);
-+void cmd_expunge(char *tag, char *sequence);
-+void cmd_create(char *tag, char *name, char *partition, int localonly);
-+void cmd_delete(char *tag, char *name, int localonly);
-+void cmd_dump(char *tag, char *name, int uid_start);
-+void cmd_undump(char *tag, char *name);
-+void cmd_xfer(char *tag, char *name, char *toserver, char *topart);
-+void cmd_rename(const char *tag, char *oldname,
-+ char *newname, char *partition);
-+void cmd_reconstruct(const char *tag, const char *name, int recursive);
-+void cmd_find(char *tag, char *namespace, char *pattern);
-+void cmd_list(char *tag, int subscribed, char *reference, char *pattern);
-+void cmd_changesub(char *tag, char *namespace, char *name, int add);
-+void cmd_getacl(const char *tag, const char *name);
-+void cmd_listrights(char *tag, char *name, char *identifier);
-+void cmd_myrights(const char *tag, const char *name);
-+void cmd_setacl(const char *tag, const char *name,
-+ const char *identifier, const char *rights);
-+void cmd_getquota(const char *tag, const char *name);
-+void cmd_getquotaroot(const char *tag, const char *name);
-+void cmd_setquota(const char *tag, const char *quotaroot);
-+void cmd_status(char *tag, char *name);
-+void cmd_getuids(char *tag, char *startuid);
-+void cmd_unselect(char* tag);
-+void cmd_namespace(char* tag);
-+void cmd_mupdatepush(char *tag, char *name);
-+void cmd_id(char* tag);
-+extern void id_getcmdline(int argc, char **argv);
-+extern void id_response(struct protstream *pout);
-+
-+void cmd_idle(char* tag);
-+void idle_update(idle_flags_t flags);
-+
-+void cmd_starttls(char *tag, int imaps);
-+
-+#ifdef ENABLE_X_NETSCAPE_HACK
-+void cmd_netscrape(char* tag);
-+#endif
-+
-+void cmd_getannotation(char* tag, char *mboxpat);
-+void cmd_setannotation(char* tag, char *mboxpat);
-+
-+int getannotatefetchdata(char *tag,
-+ struct strlist **entries, struct strlist **attribs);
-+int getannotatestoredata(char *tag, struct entryattlist **entryatts);
-+
-+void annotate_response(struct entryattlist *l);
-+
-+#ifdef ENABLE_LISTEXT
-+int getlistopts(char *tag, int *listopts);
-+#endif
-+
-+int getsearchprogram(char *tag, struct searchargs *searchargs,
-+ int *charset, int parsecharset);
-+int getsearchcriteria(char *tag, struct searchargs *searchargs,
-+ int *charset, int parsecharset);
-+int getsearchdate(time_t *start, time_t *end);
-+int getsortcriteria(char *tag, struct sortcrit **sortcrit);
-+int getdatetime(time_t *date);
-+
-+void printstring(const char *s);
-+void printastring(const char *s);
-+
-+void appendfieldlist(struct fieldlist **l, char *section,
-+ struct strlist *fields, char *trail,
-+ void *d, size_t size);
-+void freefieldlist(struct fieldlist *l);
-+void freestrlist(struct strlist *l);
-+void appendsearchargs(struct searchargs *s, struct searchargs *s1,
-+ struct searchargs *s2);
-+void freesearchargs(struct searchargs *s);
-+static void freesortcrit(struct sortcrit *s);
-+
-+static int mailboxdata(char *name, int matchlen, int maycreate, void *rock);
-+static int listdata(char *name, int matchlen, int maycreate, void *rock);
-+static void mstringdata(char *cmd, char *name, int matchlen, int maycreate,
-+ int listopts);
-+
-+extern void setproctitle_init(int argc, char **argv, char **envp);
-+extern int proc_register(const char *progname, const char *clienthost,
-+ const char *userid, const char *mailbox);
-+extern void proc_cleanup(void);
-+
-+extern int saslserver(sasl_conn_t *conn, const char *mech,
-+ const char *init_resp, const char *resp_prefix,
-+ const char *continuation, const char *empty_resp,
-+ struct protstream *pin, struct protstream *pout,
-+ int *sasl_result, char **success_data);
-+
-+/* Enable the resetting of a sasl_conn_t */
-+static int reset_saslconn(sasl_conn_t **conn);
-+
-+static struct
-+{
-+ char *ipremoteport;
-+ char *iplocalport;
-+ sasl_ssf_t ssf;
-+ char *authid;
-+} saslprops = {NULL,NULL,0,NULL};
-+
-+static int imapd_canon_user(sasl_conn_t *conn, void *context,
-+ const char *user, unsigned ulen,
-+ unsigned flags, const char *user_realm,
-+ char *out, unsigned out_max, unsigned *out_ulen)
-+{
-+ char userbuf[MAX_MAILBOX_NAME+1], *p;
-+ size_t n;
-+ int r;
-+
-+ if (!ulen) ulen = strlen(user);
-+
-+ if (config_getswitch(IMAPOPT_IMAPMAGICPLUS)) {
-+ /* make a working copy of the auth[z]id */
-+ if (ulen > MAX_MAILBOX_NAME) {
-+ sasl_seterror(conn, 0, "buffer overflow while canonicalizing");
-+ return SASL_BUFOVER;
-+ }
-+ memcpy(userbuf, user, ulen);
-+ userbuf[ulen] = '\0';
-+ user = userbuf;
-+
-+ /* See if we're using the magic plus
-+ (currently we don't support anything after '+') */
-+ if ((p = strchr(userbuf, '+')) &&
-+ (n = config_virtdomains ? strcspn(p, "@") : strlen(p)) == 1) {
-+
-+ if (flags & SASL_CU_AUTHZID) {
-+ /* make a copy of the magic plus */
-+ if (imapd_magicplus) free(imapd_magicplus);
-+ imapd_magicplus = xstrndup(p, n);
-+ }
-+
-+ /* strip the magic plus from the auth[z]id */
-+ memmove(p, p+n, strlen(p+n)+1);
-+ ulen -= n;
-+ }
-+ }
-+
-+ r = mysasl_canon_user(conn, context, user, ulen, flags, user_realm,
-+ out, out_max, out_ulen);
-+
-+ if (!r && imapd_magicplus && flags == SASL_CU_AUTHZID) {
-+ /* If we're only doing the authzid, put back the magic plus
-+ in case its used in the challenge/response calculation */
-+ n = strlen(imapd_magicplus);
-+ if (*out_ulen + n > out_max) {
-+ sasl_seterror(conn, 0, "buffer overflow while canonicalizing");
-+ r = SASL_BUFOVER;
-+ }
-+ else {
-+ p = (config_virtdomains && (p = strchr(out, '@'))) ?
-+ p : out + *out_ulen;
-+ memmove(p+n, p, strlen(p)+1);
-+ memcpy(p, imapd_magicplus, n);
-+ *out_ulen += n;
-+ }
-+ }
-+
-+ return r;
-+}
-+
-+static int imapd_proxy_policy(sasl_conn_t *conn,
-+ void *context,
-+ const char *requested_user, unsigned rlen,
-+ const char *auth_identity, unsigned alen,
-+ const char *def_realm,
-+ unsigned urlen,
-+ struct propctx *propctx)
-+{
-+ if (config_getswitch(IMAPOPT_IMAPMAGICPLUS)) {
-+ char userbuf[MAX_MAILBOX_NAME+1], *p;
-+ size_t n;
-+
-+ /* make a working copy of the authzid */
-+ if (!rlen) rlen = strlen(requested_user);
-+ if (rlen > MAX_MAILBOX_NAME) {
-+ sasl_seterror(conn, 0, "buffer overflow while proxying");
-+ return SASL_BUFOVER;
-+ }
-+ memcpy(userbuf, requested_user, rlen);
-+ userbuf[rlen] = '\0';
-+ requested_user = userbuf;
-+
-+ /* See if we're using the magic plus */
-+ if ((p = strchr(userbuf, '+'))) {
-+ n = config_virtdomains ? strcspn(p, "@") : strlen(p);
-+
-+ /* strip the magic plus from the authzid */
-+ memmove(p, p+n, strlen(p+n)+1);
-+ rlen -= n;
-+ }
-+ }
-+
-+ return mysasl_proxy_policy(conn, context, requested_user, rlen,
-+ auth_identity, alen, def_realm, urlen, propctx);
-+}
-+
-+static const struct sasl_callback mysasl_cb[] = {
-+ { SASL_CB_GETOPT, &mysasl_config, NULL },
-+ { SASL_CB_PROXY_POLICY, &imapd_proxy_policy, (void*) &imapd_proxyctx },
-+ { SASL_CB_CANON_USER, &imapd_canon_user, NULL },
-+ { SASL_CB_LIST_END, NULL, NULL }
-+};
-+
-+/* imapd_refer() issues a referral to the client. */
-+static void imapd_refer(const char *tag,
-+ const char *server,
-+ const char *mailbox)
-+{
-+ char url[MAX_MAILBOX_PATH+1];
-+
-+ if(!strcmp(imapd_userid, "anonymous")) {
-+ imapurl_toURL(url, server, mailbox, "ANONYMOUS");
-+ } else {
-+ imapurl_toURL(url, server, mailbox, "*");
-+ }
-+
-+ prot_printf(imapd_out, "%s NO [REFERRAL %s] Remote mailbox.\r\n",
-+ tag, url);
-+}
-+
-+/* wrapper for mboxlist_lookup that will force a referral if we are remote
-+ * returns IMAP_SERVER_UNAVAILABLE if we don't have a place to send the client
-+ * (that'd be a bug).
-+ * returns IMAP_MAILBOX_MOVED if we referred the client */
-+/* ext_name is the external name of the mailbox */
-+/* you can avoid referring the client by setting tag or ext_name to NULL. */
-+static int mlookup(const char *tag, const char *ext_name,
-+ const char *name, int *flags, char **pathp, char **partp,
-+ char **aclp, struct txn **tid)
-+{
-+ int r, mbtype;
-+ char *remote, *acl;
-+
-+ r = mboxlist_detail(name, &mbtype, pathp, &remote, &acl, tid);
-+
-+ if(partp) *partp = remote;
-+ if(aclp) *aclp = acl;
-+ if(flags) *flags = mbtype;
-+ if(r) return r;
-+
-+ if(mbtype & MBTYPE_RESERVE) return IMAP_MAILBOX_RESERVED;
-+
-+ if(mbtype & MBTYPE_MOVING) {
-+ /* do we have rights on the mailbox? */
-+ if(!imapd_userisadmin &&
-+ (!acl || !(cyrus_acl_myrights(imapd_authstate,acl) & ACL_LOOKUP))) {
-+ r = IMAP_MAILBOX_NONEXISTENT;
-+ } else if(tag && ext_name && remote && *remote) {
-+ char *c = NULL;
-+
-+ c = strchr(remote, '!');
-+ if(c) *c = '\0';
-+ imapd_refer(tag, remote, ext_name);
-+ r = IMAP_MAILBOX_MOVED;
-+ } else if(config_mupdate_server) {
-+ r = IMAP_SERVER_UNAVAILABLE;
-+ } else {
-+ r = IMAP_MAILBOX_NOTSUPPORTED;
-+ }
-+ }
-+
-+ return r;
-+}
-+
-+static void imapd_reset(void)
-+{
-+ proc_cleanup();
-+
-+ if (imapd_mailbox) {
-+ index_closemailbox(imapd_mailbox);
-+ mailbox_close(imapd_mailbox);
-+ imapd_mailbox = 0;
-+ }
-+
-+ if (imapd_in) {
-+ /* Flush the incoming buffer */
-+ prot_NONBLOCK(imapd_in);
-+ prot_fill(imapd_in);
-+
-+ prot_free(imapd_in);
-+ }
-+
-+ if (imapd_out) {
-+ /* Flush the outgoing buffer */
-+ prot_flush(imapd_out);
-+
-+ prot_free(imapd_out);
-+ }
-+
-+ imapd_in = imapd_out = NULL;
-+
-+#ifdef HAVE_SSL
-+ if (tls_conn) {
-+ if (tls_reset_servertls(&tls_conn) == -1) {
-+ fatal("tls_reset() failed", EC_TEMPFAIL);
-+ }
-+ tls_conn = NULL;
-+ }
-+#endif
-+
-+ cyrus_reset_stdio();
-+
-+ strcpy(imapd_clienthost, "[local]");
-+ if (imapd_logfd != -1) {
-+ close(imapd_logfd);
-+ imapd_logfd = -1;
-+ }
-+ if (imapd_userid != NULL) {
-+ free(imapd_userid);
-+ imapd_userid = NULL;
-+ }
-+ if (imapd_magicplus != NULL) {
-+ free(imapd_magicplus);
-+ imapd_magicplus = NULL;
-+ }
-+ if (imapd_authstate) {
-+ auth_freestate(imapd_authstate);
-+ imapd_authstate = NULL;
-+ }
-+ imapd_userisadmin = 0;
-+ imapd_userisproxyadmin = 0;
-+ if (imapd_saslconn) {
-+ sasl_dispose(&imapd_saslconn);
-+ imapd_saslconn = NULL;
-+ }
-+ imapd_starttls_done = 0;
-+
-+ if(saslprops.iplocalport) {
-+ free(saslprops.iplocalport);
-+ saslprops.iplocalport = NULL;
-+ }
-+ if(saslprops.ipremoteport) {
-+ free(saslprops.ipremoteport);
-+ saslprops.ipremoteport = NULL;
-+ }
-+ if(saslprops.authid) {
-+ free(saslprops.authid);
-+ saslprops.authid = NULL;
-+ }
-+ saslprops.ssf = 0;
-+
-+ imapd_exists = -1;
-+}
-+
-+/*
-+ * run once when process is forked;
-+ * MUST NOT exit directly; must return with non-zero error code
-+ */
-+int service_init(int argc, char **argv, char **envp)
-+{
-+ int ret;
-+ int opt;
-+
-+ if (geteuid() == 0) fatal("must run as the Cyrus user", EC_USAGE);
-+ setproctitle_init(argc, argv, envp);
-+
-+ /* set signal handlers */
-+ signals_set_shutdown(&shut_down);
-+ signal(SIGPIPE, SIG_IGN);
-+
-+ /* load the SASL plugins */
-+ global_sasl_init(1, 1, mysasl_cb);
-+
-+ ret = snprintf(shutdownfilename, sizeof(shutdownfilename),
-+ "%s/msg/shutdown", config_dir);
-+
-+ if(ret < 0 || ret >= sizeof(shutdownfilename)) {
-+ fatal("shutdownfilename buffer too small (configdirectory too long)",
-+ EC_CONFIG);
-+ }
-+
-+ /* open the mboxlist, we'll need it for real work */
-+ mboxlist_init(0);
-+ mboxlist_open(NULL);
-+ mailbox_initialize();
-+
-+ /* open the quota db, we'll need it for real work */
-+ quotadb_init(0);
-+ quotadb_open(NULL);
-+
-+ /* setup for sending IMAP IDLE notifications */
-+ idle_enabled();
-+
-+ /* create connection to the SNMP listener, if available. */
-+ snmp_connect(); /* ignore return code */
-+ snmp_set_str(SERVER_NAME_VERSION,CYRUS_VERSION);
-+
-+ while ((opt = getopt(argc, argv, "sp:")) != EOF) {
-+ switch (opt) {
-+ case 's': /* imaps (do starttls right away) */
-+ imaps = 1;
-+ if (!tls_enabled()) {
-+ syslog(LOG_ERR, "imaps: required OpenSSL options not present");
-+ fatal("imaps: required OpenSSL options not present",
-+ EC_CONFIG);
-+ }
-+ break;
-+ case 'p': /* external protection */
-+ extprops_ssf = atoi(optarg);
-+ break;
-+ default:
-+ break;
-+ }
-+ }
-+
-+ /* Initialize the annotatemore extention */
-+ annotatemore_init(0, NULL, NULL);
-+ annotatemore_open(NULL);
-+
-+ return 0;
-+}
-+
-+
-+/*
-+ * run for each accepted connection
-+ */
-+#ifdef ID_SAVE_CMDLINE
-+int service_main(int argc, char **argv, char **envp __attribute__((unused)))
-+#else
-+int service_main(int argc __attribute__((unused)),
-+ char **argv __attribute__((unused)),
-+ char **envp __attribute__((unused)))
-+#endif
-+{
-+ socklen_t salen;
-+ int timeout;
-+ sasl_security_properties_t *secprops = NULL;
-+ struct sockaddr_storage imapd_localaddr, imapd_remoteaddr;
-+ char localip[60], remoteip[60];
-+ char hbuf[NI_MAXHOST];
-+ int niflags;
-+ int imapd_haveaddr = 0;
-+
-+ signals_poll();
-+
-+#ifdef ID_SAVE_CMDLINE
-+ /* get command line args for use in ID before getopt mangles them */
-+ id_getcmdline(argc, argv);
-+#endif
-+
-+ imapd_in = prot_new(0, 0);
-+ imapd_out = prot_new(1, 1);
-+
-+ /* Find out name of client host */
-+ salen = sizeof(imapd_remoteaddr);
-+ if (getpeername(0, (struct sockaddr *)&imapd_remoteaddr, &salen) == 0 &&
-+ (imapd_remoteaddr.ss_family == AF_INET ||
-+ imapd_remoteaddr.ss_family == AF_INET6)) {
-+ if (getnameinfo((struct sockaddr *)&imapd_remoteaddr, salen,
-+ hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD) == 0) {
-+ strncpy(imapd_clienthost, hbuf, sizeof(hbuf));
-+ strlcat(imapd_clienthost, " ", sizeof(imapd_clienthost));
-+ imapd_clienthost[sizeof(imapd_clienthost)-30] = '\0';
-+ } else {
-+ imapd_clienthost[0] = '\0';
-+ }
-+ niflags = NI_NUMERICHOST;
-+#ifdef NI_WITHSCOPEID
-+ if (((struct sockaddr *)&imapd_remoteaddr)->sa_family == AF_INET6)
-+ niflags |= NI_WITHSCOPEID;
-+#endif
-+ if (getnameinfo((struct sockaddr *)&imapd_remoteaddr, salen, hbuf,
-+ sizeof(hbuf), NULL, 0, niflags) != 0)
-+ strlcpy(hbuf, "unknown", sizeof(hbuf));
-+ strlcat(imapd_clienthost, "[", sizeof(imapd_clienthost));
-+ strlcat(imapd_clienthost, hbuf, sizeof(imapd_clienthost));
-+ strlcat(imapd_clienthost, "]", sizeof(imapd_clienthost));
-+ salen = sizeof(imapd_localaddr);
-+ if (getsockname(0, (struct sockaddr *)&imapd_localaddr, &salen) == 0) {
-+ if(iptostring((struct sockaddr *)&imapd_remoteaddr, salen,
-+ remoteip, sizeof(remoteip)) == 0
-+ && iptostring((struct sockaddr *)&imapd_localaddr, salen,
-+ localip, sizeof(localip)) == 0) {
-+ imapd_haveaddr = 1;
-+ }
-+ }
-+ }
-+
-+ /* create the SASL connection */
-+ if (sasl_server_new("imap", config_servername,
-+ NULL, NULL, NULL, NULL, 0,
-+ &imapd_saslconn) != SASL_OK) {
-+ fatal("SASL failed initializing: sasl_server_new()", EC_TEMPFAIL);
-+ }
-+
-+ /* never allow plaintext, since IMAP has the LOGIN command */
-+ secprops = mysasl_secprops(SASL_SEC_NOPLAINTEXT);
-+ sasl_setprop(imapd_saslconn, SASL_SEC_PROPS, secprops);
-+ sasl_setprop(imapd_saslconn, SASL_SSF_EXTERNAL, &extprops_ssf);
-+
-+ if (imapd_haveaddr) {
-+ sasl_setprop(imapd_saslconn, SASL_IPREMOTEPORT, remoteip);
-+ saslprops.ipremoteport = xstrdup(remoteip);
-+ sasl_setprop(imapd_saslconn, SASL_IPLOCALPORT, localip);
-+ saslprops.iplocalport = xstrdup(localip);
-+ }
-+
-+ proc_register("imapd", imapd_clienthost, NULL, NULL);
-+
-+ /* Set inactivity timer */
-+ timeout = config_getint(IMAPOPT_TIMEOUT);
-+ if (timeout < 30) timeout = 30;
-+ prot_settimeout(imapd_in, timeout*60);
-+ prot_setflushonread(imapd_in, imapd_out);
-+
-+ /* we were connected on imaps port so we should do
-+ TLS negotiation immediately */
-+ if (imaps == 1) cmd_starttls(NULL, 1);
-+
-+ snmp_increment(TOTAL_CONNECTIONS, 1);
-+ snmp_increment(ACTIVE_CONNECTIONS, 1);
-+
-+ cmdloop();
-+
-+ /* LOGOUT executed */
-+ prot_flush(imapd_out);
-+ snmp_increment(ACTIVE_CONNECTIONS, -1);
-+
-+ /* cleanup */
-+ imapd_reset();
-+
-+ return 0;
-+}
-+
-+/* Called by service API to shut down the service */
-+void service_abort(int error)
-+{
-+ shut_down(error);
-+}
-+
-+/*
-+ * found a motd file; spit out message and return
-+ */
-+void motd_file(fd)
-+int fd;
-+{
-+ struct protstream *motd_in;
-+ char buf[1024];
-+ char *p;
-+
-+ motd_in = prot_new(fd, 0);
-+
-+ prot_fgets(buf, sizeof(buf), motd_in);
-+ if ((p = strchr(buf, '\r'))!=NULL) *p = 0;
-+ if ((p = strchr(buf, '\n'))!=NULL) *p = 0;
-+
-+ for(p = buf; *p == '['; p++); /* can't have [ be first char, sigh */
-+ prot_printf(imapd_out, "* OK [ALERT] %s\r\n", p);
-+}
-+
-+/*
-+ * Cleanly shut down and exit
-+ */
-+void shut_down(int code) __attribute__((noreturn));
-+void shut_down(int code)
-+{
-+ proc_cleanup();
-+ if (imapd_mailbox) {
-+ index_closemailbox(imapd_mailbox);
-+ mailbox_close(imapd_mailbox);
-+ }
-+ seen_done();
-+ mboxlist_close();
-+ mboxlist_done();
-+
-+ quotadb_close();
-+ quotadb_done();
-+
-+ annotatemore_close();
-+ annotatemore_done();
-+
-+ if (imapd_in) {
-+ /* Flush the incoming buffer */
-+ prot_NONBLOCK(imapd_in);
-+ prot_fill(imapd_in);
-+
-+ prot_free(imapd_in);
-+ }
-+
-+ if (imapd_out) {
-+ /* Flush the outgoing buffer */
-+ prot_flush(imapd_out);
-+ prot_free(imapd_out);
-+
-+ /* one less active connection */
-+ snmp_increment(ACTIVE_CONNECTIONS, -1);
-+ }
-+
-+#ifdef HAVE_SSL
-+ tls_shutdown_serverengine();
-+#endif
-+ /* shutdown socket nicely */
-+ cyrus_close_sock(0);
-+ cyrus_close_sock(1);
-+ cyrus_close_sock(2);
-+
-+ cyrus_done();
-+
-+ exit(code);
-+}
-+
-+void fatal(const char *s, int code)
-+{
-+ static int recurse_code = 0;
-+
-+ if (recurse_code) {
-+ /* We were called recursively. Just give up */
-+ proc_cleanup();
-+ snmp_increment(ACTIVE_CONNECTIONS, -1);
-+ exit(recurse_code);
-+ }
-+ recurse_code = code;
-+ if (imapd_out) {
-+ prot_printf(imapd_out, "* BYE Fatal error: %s\r\n", s);
-+ prot_flush(imapd_out);
-+ }
-+ if (stage) {
-+ /* Cleanup the stage(s) */
-+ while (numstage) {
-+ struct appendstage *curstage = stage[--numstage];
-+
-+ append_removestage(curstage->stage);
-+ while (curstage->nflags--) {
-+ free(curstage->flag[curstage->nflags]);
-+ }
-+ if (curstage->flag) free((char *) curstage->flag);
-+ free(curstage);
-+ }
-+ free(stage);
-+ }
-+
-+ syslog(LOG_ERR, "Fatal error: %s", s);
-+ shut_down(code);
-+}
-+
-+/*
-+ * Top-level command loop parsing
-+ */
-+void cmdloop()
-+{
-+ int fd;
-+ char motdfilename[1024];
-+ int c;
-+ int ret;
-+ int usinguid, havepartition, havenamespace, recursive;
-+ static struct buf tag, cmd, arg1, arg2, arg3, arg4;
-+ char *p, shut[1024];
-+ const char *err;
-+
-+ prot_printf(imapd_out,
-+ "* OK %s Cyrus IMAP4 %s server ready\r\n", config_servername,
-+ CYRUS_VERSION);
-+
-+ ret = snprintf(motdfilename, sizeof(motdfilename), "%s/msg/motd",
-+ config_dir);
-+
-+ if(ret < 0 || ret >= sizeof(motdfilename)) {
-+ fatal("motdfilename buffer too small (configdirectory too long)",
-+ EC_CONFIG);
-+ }
-+
-+ if ((fd = open(motdfilename, O_RDONLY, 0)) != -1) {
-+ motd_file(fd);
-+ close(fd);
-+ }
-+
-+ for (;;) {
-+ if ( !imapd_userisadmin && imapd_userid
-+ && shutdown_file(shut, sizeof(shut))) {
-+ for (p = shut; *p == '['; p++); /* can't have [ be first char */
-+ prot_printf(imapd_out, "* BYE [ALERT] %s\r\n", p);
-+ shut_down(0);
-+ }
-+
-+ signals_poll();
-+
-+ /* Parse tag */
-+ c = getword(imapd_in, &tag);
-+ if (c == EOF) {
-+ if ((err = prot_error(imapd_in))!=NULL
-+ && strcmp(err, PROT_EOF_STRING)) {
-+ syslog(LOG_WARNING, "%s, closing connection", err);
-+ prot_printf(imapd_out, "* BYE %s\r\n", err);
-+ }
-+ return;
-+ }
-+ if (c != ' ' || !imparse_isatom(tag.s) || (tag.s[0] == '*' && !tag.s[1])) {
-+ prot_printf(imapd_out, "* BAD Invalid tag\r\n");
-+ eatline(imapd_in, c);
-+ continue;
-+ }
-+
-+ /* Parse command name */
-+ c = getword(imapd_in, &cmd);
-+ if (!cmd.s[0]) {
-+ prot_printf(imapd_out, "%s BAD Null command\r\n", tag.s);
-+ eatline(imapd_in, c);
-+ continue;
-+ }
-+ if (islower((unsigned char) cmd.s[0]))
-+ cmd.s[0] = toupper((unsigned char) cmd.s[0]);
-+ for (p = &cmd.s[1]; *p; p++) {
-+ if (isupper((unsigned char) *p)) *p = tolower((unsigned char) *p);
-+ }
-+
-+ /* Only Authenticate/Login/Logout/Noop/Capability/Id/Starttls
-+ allowed when not logged in */
-+ if (!imapd_userid && !strchr("ALNCIS", cmd.s[0])) goto nologin;
-+
-+ /* note that about half the commands (the common ones that don't
-+ hit the mailboxes file) now close the mailboxes file just in
-+ case it was open. */
-+ switch (cmd.s[0]) {
-+ case 'A':
-+ if (!strcmp(cmd.s, "Authenticate")) {
-+ int haveinitresp = 0;
-+
-+ if (c != ' ') goto missingargs;
-+ c = getword(imapd_in, &arg1);
-+ if (!imparse_isatom(arg1.s)) {
-+ prot_printf(imapd_out, "%s BAD Invalid authenticate mechanism\r\n", tag.s);
-+ eatline(imapd_in, c);
-+ continue;
-+ }
-+ if (c == ' ') {
-+ haveinitresp = 1;
-+ c = getword(imapd_in, &arg2);
-+ if (c == EOF) goto missingargs;
-+ }
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+
-+ if (imapd_userid) {
-+ prot_printf(imapd_out, "%s BAD Already authenticated\r\n", tag.s);
-+ continue;
-+ }
-+ cmd_authenticate(tag.s, arg1.s, haveinitresp ? arg2.s : NULL);
-+
-+ snmp_increment(AUTHENTICATE_COUNT, 1);
-+ }
-+ else if (!imapd_userid) goto nologin;
-+ else if (!strcmp(cmd.s, "Append")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c != ' ') goto missingargs;
-+
-+ cmd_append(tag.s, arg1.s);
-+
-+ snmp_increment(APPEND_COUNT, 1);
-+ }
-+ else goto badcmd;
-+ break;
-+
-+ case 'B':
-+ if (!strcmp(cmd.s, "Bboard")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c == EOF) goto missingargs;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+
-+ cmd_select(tag.s, cmd.s, arg1.s);
-+
-+ snmp_increment(BBOARD_COUNT, 1);
-+ }
-+ else goto badcmd;
-+ break;
-+
-+ case 'C':
-+ if (!strcmp(cmd.s, "Capability")) {
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_capability(tag.s);
-+
-+ snmp_increment(CAPABILITY_COUNT, 1);
-+ }
-+ else if (!imapd_userid) goto nologin;
-+ else if (!strcmp(cmd.s, "Check")) {
-+ if (!imapd_mailbox) goto nomailbox;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+
-+ cmd_noop(tag.s, cmd.s);
-+
-+ snmp_increment(CHECK_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Copy")) {
-+ if (!imapd_mailbox) goto nomailbox;
-+ usinguid = 0;
-+ if (c != ' ') goto missingargs;
-+ copy:
-+ c = getword(imapd_in, &arg1);
-+ if (c == '\r') goto missingargs;
-+ if (c != ' ' || !imparse_issequence(arg1.s)) goto badsequence;
-+ c = getastring(imapd_in, imapd_out, &arg2);
-+ if (c == EOF) goto missingargs;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+
-+ cmd_copy(tag.s, arg1.s, arg2.s, usinguid);
-+
-+ snmp_increment(COPY_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Create")) {
-+ havepartition = 0;
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c == EOF) goto missingargs;
-+ if (c == ' ') {
-+ havepartition = 1;
-+ c = getword(imapd_in, &arg2);
-+ if (!imparse_isatom(arg2.s)) goto badpartition;
-+ }
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_create(tag.s, arg1.s, havepartition ? arg2.s : 0, 0);
-+
-+ snmp_increment(CREATE_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Close")) {
-+ if (!imapd_mailbox) goto nomailbox;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+
-+ cmd_close(tag.s);
-+
-+ snmp_increment(CLOSE_COUNT, 1);
-+ }
-+ else goto badcmd;
-+ break;
-+
-+ case 'D':
-+ if (!strcmp(cmd.s, "Delete")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c == EOF) goto missingargs;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_delete(tag.s, arg1.s, 0);
-+
-+ snmp_increment(DELETE_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Deleteacl")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg2);
-+ if (c == EOF) goto missingargs;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_setacl(tag.s, arg1.s, arg2.s, NULL);
-+
-+ snmp_increment(DELETEACL_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Dump")) {
-+ int uid_start = 0;
-+
-+ if(c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if(c == ' ') {
-+ c = getastring(imapd_in, imapd_out, &arg2);
-+ if(!imparse_isnumber(arg2.s)) goto extraargs;
-+ uid_start = atoi(arg2.s);
-+ }
-+
-+ if(c == '\r') c = prot_getc(imapd_in);
-+ if(c != '\n') goto extraargs;
-+
-+ cmd_dump(tag.s, arg1.s, uid_start);
-+ /* snmp_increment(DUMP_COUNT, 1);*/
-+ }
-+ else goto badcmd;
-+ break;
-+
-+ case 'E':
-+ if (!strcmp(cmd.s, "Expunge")) {
-+ if (!imapd_mailbox) goto nomailbox;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+
-+ cmd_expunge(tag.s, 0);
-+
-+ snmp_increment(EXPUNGE_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Examine")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c == EOF) goto missingargs;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+
-+ cmd_select(tag.s, cmd.s, arg1.s);
-+
-+ snmp_increment(EXAMINE_COUNT, 1);
-+ }
-+ else goto badcmd;
-+ break;
-+
-+ case 'F':
-+ if (!strcmp(cmd.s, "Fetch")) {
-+ if (!imapd_mailbox) goto nomailbox;
-+ usinguid = 0;
-+ if (c != ' ') goto missingargs;
-+ fetch:
-+ c = getword(imapd_in, &arg1);
-+ if (c == '\r') goto missingargs;
-+ if (c != ' ' || !imparse_issequence(arg1.s)) goto badsequence;
-+
-+ cmd_fetch(tag.s, arg1.s, usinguid);
-+
-+ snmp_increment(FETCH_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Find")) {
-+ c = getword(imapd_in, &arg1);
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg2);
-+ if (c == EOF) goto missingargs;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_find(tag.s, arg1.s, arg2.s);
-+
-+ snmp_increment(FIND_COUNT, 1);
-+ }
-+ else goto badcmd;
-+ break;
-+
-+ case 'G':
-+ if (!strcmp(cmd.s, "Getacl")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c == EOF) goto missingargs;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_getacl(tag.s, arg1.s);
-+
-+ snmp_increment(GETACL_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Getannotation")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c != ' ') goto missingargs;
-+
-+ cmd_getannotation(tag.s, arg1.s);
-+
-+ snmp_increment(GETANNOTATION_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Getquota")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c == EOF) goto missingargs;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_getquota(tag.s, arg1.s);
-+
-+ snmp_increment(GETQUOTA_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Getquotaroot")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c == EOF) goto missingargs;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_getquotaroot(tag.s, arg1.s);
-+
-+ snmp_increment(GETQUOTAROOT_COUNT, 1);
-+ }
-+ else goto badcmd;
-+ break;
-+
-+ case 'I':
-+ if (!strcmp(cmd.s, "Id")) {
-+ if (c != ' ') goto missingargs;
-+ cmd_id(tag.s);
-+
-+ snmp_increment(ID_COUNT, 1);
-+ }
-+ else if (!imapd_userid) goto nologin;
-+ else if (!strcmp(cmd.s, "Idle")) {
-+ if (!idle_enabled()) {
-+ /* we don't support idle */
-+ goto badcmd;
-+ }
-+
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_idle(tag.s);
-+
-+ snmp_increment(IDLE_COUNT, 1);
-+ }
-+ else goto badcmd;
-+ break;
-+
-+ case 'L':
-+ if (!strcmp(cmd.s, "Login")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if(c != ' ') goto missingargs;
-+
-+ cmd_login(tag.s, arg1.s);
-+
-+ snmp_increment(LOGIN_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Logout")) {
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+
-+ snmp_increment(LOGOUT_COUNT, 1);
-+
-+ prot_printf(imapd_out, "* BYE %s\r\n",
-+ error_message(IMAP_BYE_LOGOUT));
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag.s,
-+ error_message(IMAP_OK_COMPLETED));
-+ return;
-+ }
-+ else if (!imapd_userid) goto nologin;
-+ else if (!strcmp(cmd.s, "List")) {
-+ int listopts = LIST_CHILDREN;
-+#ifdef ENABLE_LISTEXT
-+ /* Check for and parse LISTEXT options */
-+ c = prot_getc(imapd_in);
-+ if (c == '(') {
-+ c = getlistopts(tag.s, &listopts);
-+ if (c == EOF) {
-+ eatline(imapd_in, c);
-+ continue;
-+ }
-+ }
-+ else
-+ prot_ungetc(c, imapd_in);
-+#endif /* ENABLE_LISTEXT */
-+ if (imapd_magicplus) listopts |= LIST_SUBSCRIBED;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg2);
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_list(tag.s, listopts, arg1.s, arg2.s);
-+
-+ snmp_increment(LIST_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Lsub")) {
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg2);
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_list(tag.s, LIST_LSUB | LIST_CHILDREN, arg1.s, arg2.s);
-+
-+ snmp_increment(LSUB_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Listrights")) {
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg2);
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_listrights(tag.s, arg1.s, arg2.s);
-+
-+ snmp_increment(LISTRIGHTS_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Localcreate")) {
-+ /* create a local-only mailbox */
-+ havepartition = 0;
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c == EOF) goto missingargs;
-+ if (c == ' ') {
-+ havepartition = 1;
-+ c = getword(imapd_in, &arg2);
-+ if (!imparse_isatom(arg2.s)) goto badpartition;
-+ }
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_create(tag.s, arg1.s, havepartition ? arg2.s : NULL, 1);
-+
-+ /* xxxx snmp_increment(CREATE_COUNT, 1); */
-+ }
-+ else if (!strcmp(cmd.s, "Localdelete")) {
-+ /* delete a mailbox locally only */
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c == EOF) goto missingargs;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_delete(tag.s, arg1.s, 1);
-+
-+ /* xxxx snmp_increment(DELETE_COUNT, 1); */
-+ }
-+ else goto badcmd;
-+ break;
-+
-+ case 'M':
-+ if (!strcmp(cmd.s, "Myrights")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c == EOF) goto missingargs;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_myrights(tag.s, arg1.s);
-+
-+ /* xxxx snmp_increment(MYRIGHTS_COUNT, 1); */
-+ }
-+ else if (!strcmp(cmd.s, "Mupdatepush")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if(c == EOF) goto missingargs;
-+ if(c == '\r') c = prot_getc(imapd_in);
-+ if(c != '\n') goto extraargs;
-+ cmd_mupdatepush(tag.s, arg1.s);
-+
-+ /* xxxx snmp_increment(MUPDATEPUSH_COUNT, 1); */
-+ } else goto badcmd;
-+ break;
-+
-+ case 'N':
-+ if (!strcmp(cmd.s, "Noop")) {
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+
-+ cmd_noop(tag.s, cmd.s);
-+
-+ /* xxxx snmp_increment(NOOP_COUNT, 1); */
-+ }
-+#ifdef ENABLE_X_NETSCAPE_HACK
-+ else if (!strcmp(cmd.s, "Netscape")) {
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_netscrape(tag.s);
-+ }
-+#endif
-+ else if (!imapd_userid) goto nologin;
-+ else if (!strcmp(cmd.s, "Namespace")) {
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_namespace(tag.s);
-+
-+ /* xxxx snmp_increment(NAMESPACE_COUNT, 1); */
-+ }
-+ else goto badcmd;
-+ break;
-+
-+ case 'P':
-+ if (!strcmp(cmd.s, "Partial")) {
-+ if (!imapd_mailbox) goto nomailbox;
-+ if (c != ' ') goto missingargs;
-+ c = getword(imapd_in, &arg1);
-+ if (c != ' ') goto missingargs;
-+ c = getword(imapd_in, &arg2);
-+ if (c != ' ') goto missingargs;
-+ c = getword(imapd_in, &arg3);
-+ if (c != ' ') goto missingargs;
-+ c = getword(imapd_in, &arg4);
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+
-+ cmd_partial(tag.s, arg1.s, arg2.s, arg3.s, arg4.s);
-+
-+ /* xxxx snmp_increment(PARTIAL_COUNT, 1); */
-+ }
-+ else goto badcmd;
-+ break;
-+
-+ case 'R':
-+ if (!strcmp(cmd.s, "Rename")) {
-+ havepartition = 0;
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg2);
-+ if (c == EOF) goto missingargs;
-+ if (c == ' ') {
-+ havepartition = 1;
-+ c = getword(imapd_in, &arg3);
-+ if (!imparse_isatom(arg3.s)) goto badpartition;
-+ }
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_rename(tag.s, arg1.s, arg2.s, havepartition ? arg3.s : 0);
-+
-+ /* xxxx snmp_increment(RENAME_COUNT, 1); */
-+ } else if(!strcmp(cmd.s, "Reconstruct")) {
-+ recursive = 0;
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if(c == ' ') {
-+ /* Optional RECURSEIVE argument */
-+ c = getword(imapd_in, &arg2);
-+ if(!imparse_isatom(arg2.s))
-+ goto extraargs;
-+ else if(!strcasecmp(arg2.s, "RECURSIVE"))
-+ recursive = 1;
-+ else
-+ goto extraargs;
-+ }
-+ if(c == '\r') c = prot_getc(imapd_in);
-+ if(c != '\n') goto extraargs;
-+ cmd_reconstruct(tag.s, arg1.s, recursive);
-+
-+ /* snmp_increment(RECONSTRUCT_COUNT, 1); */
-+ }
-+ else if (!strcmp(cmd.s, "Rlist")) {
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg2);
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_list(tag.s, LIST_CHILDREN | LIST_REMOTE, arg1.s, arg2.s);
-+
-+/* snmp_increment(LIST_COUNT, 1); */
-+ }
-+ else if (!strcmp(cmd.s, "Rlsub")) {
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg2);
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_list(tag.s, LIST_LSUB | LIST_CHILDREN | LIST_REMOTE,
-+ arg1.s, arg2.s);
-+/* snmp_increment(LSUB_COUNT, 1); */
-+ } else goto badcmd;
-+ break;
-+
-+ case 'S':
-+ if (!strcmp(cmd.s, "Starttls")) {
-+ if (!tls_enabled()) {
-+ /* we don't support starttls */
-+ goto badcmd;
-+ }
-+
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+
-+ /* if we've already done SASL fail */
-+ if (imapd_userid != NULL) {
-+ prot_printf(imapd_out,
-+ "%s BAD Can't Starttls after authentication\r\n", tag.s);
-+ continue;
-+ }
-+
-+ /* check if already did a successful tls */
-+ if (imapd_starttls_done == 1) {
-+ prot_printf(imapd_out,
-+ "%s BAD Already did a successful Starttls\r\n",
-+ tag.s);
-+ continue;
-+ }
-+ cmd_starttls(tag.s, 0);
-+
-+ snmp_increment(STARTTLS_COUNT, 1);
-+ continue;
-+ }
-+ if (!imapd_userid) {
-+ goto nologin;
-+ } else if (!strcmp(cmd.s, "Store")) {
-+ if (!imapd_mailbox) goto nomailbox;
-+ usinguid = 0;
-+ if (c != ' ') goto missingargs;
-+ store:
-+ c = getword(imapd_in, &arg1);
-+ if (c != ' ' || !imparse_issequence(arg1.s)) goto badsequence;
-+ c = getword(imapd_in, &arg2);
-+ if (c != ' ') goto missingargs;
-+
-+ cmd_store(tag.s, arg1.s, arg2.s, usinguid);
-+
-+ snmp_increment(STORE_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Select")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c == EOF) goto missingargs;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+
-+ cmd_select(tag.s, cmd.s, arg1.s);
-+
-+ snmp_increment(SELECT_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Search")) {
-+ if (!imapd_mailbox) goto nomailbox;
-+ usinguid = 0;
-+ if (c != ' ') goto missingargs;
-+ search:
-+
-+ cmd_search(tag.s, usinguid);
-+
-+ snmp_increment(SEARCH_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Subscribe")) {
-+ if (c != ' ') goto missingargs;
-+ havenamespace = 0;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c == ' ') {
-+ havenamespace = 1;
-+ c = getastring(imapd_in, imapd_out, &arg2);
-+ }
-+ if (c == EOF) goto missingargs;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ if (havenamespace) {
-+ cmd_changesub(tag.s, arg1.s, arg2.s, 1);
-+ }
-+ else {
-+ cmd_changesub(tag.s, (char *)0, arg1.s, 1);
-+ }
-+ snmp_increment(SUBSCRIBE_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Setacl")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg2);
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg3);
-+ if (c == EOF) goto missingargs;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_setacl(tag.s, arg1.s, arg2.s, arg3.s);
-+
-+ snmp_increment(SETACL_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Setannotation")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c != ' ') goto missingargs;
-+
-+ cmd_setannotation(tag.s, arg1.s);
-+
-+ snmp_increment(SETANNOTATION_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Setquota")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c != ' ') goto missingargs;
-+ cmd_setquota(tag.s, arg1.s);
-+
-+ snmp_increment(SETQUOTA_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Sort")) {
-+ if (!imapd_mailbox) goto nomailbox;
-+ usinguid = 0;
-+ if (c != ' ') goto missingargs;
-+ sort:
-+ cmd_sort(tag.s, usinguid);
-+
-+ snmp_increment(SORT_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Status")) {
-+ if (c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c != ' ') goto missingargs;
-+ cmd_status(tag.s, arg1.s);
-+
-+ snmp_increment(STATUS_COUNT, 1);
-+ }
-+ else goto badcmd;
-+ break;
-+
-+ case 'T':
-+ if (!strcmp(cmd.s, "Thread")) {
-+ if (!imapd_mailbox) goto nomailbox;
-+ usinguid = 0;
-+ if (c != ' ') goto missingargs;
-+ thread:
-+ cmd_thread(tag.s, usinguid);
-+
-+ snmp_increment(THREAD_COUNT, 1);
-+ }
-+ else goto badcmd;
-+ break;
-+
-+ case 'U':
-+ if (!strcmp(cmd.s, "Uid")) {
-+ if (!imapd_mailbox) goto nomailbox;
-+ usinguid = 1;
-+ if (c != ' ') goto missingargs;
-+ c = getword(imapd_in, &arg1);
-+ if (c != ' ') goto missingargs;
-+ lcase(arg1.s);
-+ if (!strcmp(arg1.s, "fetch")) {
-+ goto fetch;
-+ }
-+ else if (!strcmp(arg1.s, "store")) {
-+ goto store;
-+ }
-+ else if (!strcmp(arg1.s, "search")) {
-+ goto search;
-+ }
-+ else if (!strcmp(arg1.s, "sort")) {
-+ goto sort;
-+ }
-+ else if (!strcmp(arg1.s, "thread")) {
-+ goto thread;
-+ }
-+ else if (!strcmp(arg1.s, "copy")) {
-+ goto copy;
-+ }
-+ else if (!strcmp(arg1.s, "expunge")) {
-+ c = getword(imapd_in, &arg1);
-+ if (!imparse_issequence(arg1.s)) goto badsequence;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_expunge(tag.s, arg1.s);
-+
-+ snmp_increment(EXPUNGE_COUNT, 1);
-+ }
-+ else {
-+ prot_printf(imapd_out, "%s BAD Unrecognized UID subcommand\r\n", tag.s);
-+ eatline(imapd_in, c);
-+ }
-+ }
-+ else if (!strcmp(cmd.s, "Unsubscribe")) {
-+ if (c != ' ') goto missingargs;
-+ havenamespace = 0;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+ if (c == ' ') {
-+ havenamespace = 1;
-+ c = getastring(imapd_in, imapd_out, &arg2);
-+ }
-+ if (c == EOF) goto missingargs;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ if (havenamespace) {
-+ cmd_changesub(tag.s, arg1.s, arg2.s, 0);
-+ }
-+ else {
-+ cmd_changesub(tag.s, (char *)0, arg1.s, 0);
-+ }
-+
-+ snmp_increment(UNSUBSCRIBE_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Unselect")) {
-+ if (!imapd_mailbox) goto nomailbox;
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+ cmd_unselect(tag.s);
-+
-+ snmp_increment(UNSELECT_COUNT, 1);
-+ }
-+ else if (!strcmp(cmd.s, "Undump")) {
-+ if(c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+
-+ /* we want to get a list at this point */
-+ if(c != ' ') goto missingargs;
-+
-+ cmd_undump(tag.s, arg1.s);
-+ /* snmp_increment(UNDUMP_COUNT, 1);*/
-+ }
-+ else goto badcmd;
-+ break;
-+
-+ case 'X':
-+ if (!strcmp(cmd.s, "Xfer")) {
-+ int havepartition = 0;
-+
-+ /* Mailbox */
-+ if(c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg1);
-+
-+ /* Dest Server */
-+ if(c != ' ') goto missingargs;
-+ c = getastring(imapd_in, imapd_out, &arg2);
-+
-+ if(c == ' ') {
-+ /* Dest Partition */
-+ c = getastring(imapd_in, imapd_out, &arg3);
-+ if (!imparse_isatom(arg3.s)) goto badpartition;
-+ havepartition = 1;
-+ }
-+
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') goto extraargs;
-+
-+ cmd_xfer(tag.s, arg1.s, arg2.s,
-+ (havepartition ? arg3.s : NULL));
-+ /* snmp_increment(XFER_COUNT, 1);*/
-+ }
-+ else goto badcmd;
-+ break;
-+
-+ default:
-+ badcmd:
-+ prot_printf(imapd_out, "%s BAD Unrecognized command\r\n", tag.s);
-+ eatline(imapd_in, c);
-+ }
-+
-+ continue;
-+
-+ nologin:
-+ prot_printf(imapd_out, "%s BAD Please login first\r\n", tag.s);
-+ eatline(imapd_in, c);
-+ continue;
-+
-+ nomailbox:
-+ prot_printf(imapd_out, "%s BAD Please select a mailbox first\r\n", tag.s);
-+ eatline(imapd_in, c);
-+ continue;
-+
-+ missingargs:
-+ prot_printf(imapd_out, "%s BAD Missing required argument to %s\r\n", tag.s, cmd.s);
-+ eatline(imapd_in, c);
-+ continue;
-+
-+ extraargs:
-+ prot_printf(imapd_out, "%s BAD Unexpected extra arguments to %s\r\n", tag.s, cmd.s);
-+ eatline(imapd_in, c);
-+ continue;
-+
-+ badsequence:
-+ prot_printf(imapd_out, "%s BAD Invalid sequence in %s\r\n", tag.s, cmd.s);
-+ eatline(imapd_in, c);
-+ continue;
-+
-+ badpartition:
-+ prot_printf(imapd_out, "%s BAD Invalid partition name in %s\r\n",
-+ tag.s, cmd.s);
-+ eatline(imapd_in, c);
-+ continue;
-+ }
-+}
-+
-+/*
-+ * Perform a LOGIN command
-+ */
-+void cmd_login(char *tag, char *user)
-+{
-+ char userbuf[MAX_MAILBOX_NAME+1];
-+ unsigned userlen;
-+ const char *canon_user = userbuf;
-+ char c;
-+ struct buf passwdbuf;
-+ char *passwd;
-+ const char *reply = NULL;
-+ int plaintextloginpause;
-+ int r;
-+
-+ if (imapd_userid) {
-+ eatline(imapd_in, ' ');
-+ prot_printf(imapd_out, "%s BAD Already logged in\r\n", tag);
-+ return;
-+ }
-+
-+ r = imapd_canon_user(imapd_saslconn, NULL, user, 0,
-+ SASL_CU_AUTHID | SASL_CU_AUTHZID, NULL,
-+ userbuf, sizeof(userbuf), &userlen);
-+
-+ if (r) {
-+ syslog(LOG_NOTICE, "badlogin: %s plaintext %s invalid user",
-+ imapd_clienthost, beautify_string(user));
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag,
-+ error_message(IMAP_INVALID_USER));
-+ return;
-+ }
-+
-+ /* possibly disallow login */
-+ if ((imapd_starttls_done == 0) &&
-+ (config_getswitch(IMAPOPT_ALLOWPLAINTEXT) == 0) &&
-+ !is_userid_anonymous(canon_user)) {
-+ eatline(imapd_in, ' ');
-+ prot_printf(imapd_out, "%s NO Login only available under a layer\r\n",
-+ tag);
-+ return;
-+ }
-+
-+ memset(&passwdbuf,0,sizeof(struct buf));
-+ c = getastring(imapd_in, imapd_out, &passwdbuf);
-+
-+ if(c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') {
-+ freebuf(&passwdbuf);
-+ prot_printf(imapd_out,
-+ "%s BAD Unexpected extra arguments to LOGIN\r\n",
-+ tag);
-+ eatline(imapd_in, c);
-+ return;
-+ }
-+
-+ passwd = passwdbuf.s;
-+
-+ if (is_userid_anonymous(canon_user)) {
-+ if (config_getswitch(IMAPOPT_ALLOWANONYMOUSLOGIN)) {
-+ passwd = beautify_string(passwd);
-+ if (strlen(passwd) > 500) passwd[500] = '\0';
-+ syslog(LOG_NOTICE, "login: %s anonymous %s",
-+ imapd_clienthost, passwd);
-+ reply = "Anonymous access granted";
-+ imapd_userid = xstrdup("anonymous");
-+ }
-+ else {
-+ syslog(LOG_NOTICE, "badlogin: %s anonymous login refused",
-+ imapd_clienthost);
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag,
-+ error_message(IMAP_ANONYMOUS_NOT_PERMITTED));
-+ freebuf(&passwdbuf);
-+ return;
-+ }
-+ }
-+ else if ((r = sasl_checkpass(imapd_saslconn,
-+ canon_user,
-+ strlen(canon_user),
-+ passwd,
-+ strlen(passwd))) != SASL_OK) {
-+ syslog(LOG_NOTICE, "badlogin: %s plaintext %s %s",
-+ imapd_clienthost, canon_user, sasl_errdetail(imapd_saslconn));
-+
-+ sleep(3);
-+
-+ if ((reply = sasl_errstring(r, NULL, NULL)) != NULL) {
-+ prot_printf(imapd_out, "%s NO Login failed: %s\r\n", tag, reply);
-+ } else {
-+ prot_printf(imapd_out, "%s NO Login failed: %d\r\n", tag, r);
-+ }
-+
-+ snmp_increment_args(AUTHENTICATION_NO, 1,
-+ VARIABLE_AUTH, 0 /* hash_simple("LOGIN") */,
-+ VARIABLE_LISTEND);
-+ freebuf(&passwdbuf);
-+ return;
-+ }
-+ else {
-+ r = sasl_getprop(imapd_saslconn, SASL_USERNAME,
-+ (const void **) &canon_user);
-+
-+ if(r != SASL_OK) {
-+ if ((reply = sasl_errstring(r, NULL, NULL)) != NULL) {
-+ prot_printf(imapd_out, "%s NO Login failed: %s\r\n",
-+ tag, reply);
-+ } else {
-+ prot_printf(imapd_out, "%s NO Login failed: %d\r\n", tag, r);
-+ }
-+
-+ snmp_increment_args(AUTHENTICATION_NO, 1,
-+ VARIABLE_AUTH, 0 /* hash_simple("LOGIN") */,
-+ VARIABLE_LISTEND);
-+ freebuf(&passwdbuf);
-+ return;
-+ }
-+
-+ reply = "User logged in";
-+ imapd_userid = xstrdup(canon_user);
-+ snmp_increment_args(AUTHENTICATION_YES, 1,
-+ VARIABLE_AUTH, 0 /*hash_simple("LOGIN") */,
-+ VARIABLE_LISTEND);
-+ syslog(LOG_NOTICE, "login: %s %s%s plaintext%s %s", imapd_clienthost,
-+ imapd_userid, imapd_magicplus ? imapd_magicplus : "",
-+ imapd_starttls_done ? "+TLS" : "",
-+ reply ? reply : "");
-+
-+ plaintextloginpause = config_getint(IMAPOPT_PLAINTEXTLOGINPAUSE);
-+ if (plaintextloginpause != 0 && !imapd_starttls_done) {
-+ /* Apply penalty only if not under layer */
-+ sleep(plaintextloginpause);
-+ }
-+ }
-+
-+ imapd_authstate = auth_newstate(imapd_userid);
-+
-+ imapd_userisadmin = global_authisa(imapd_authstate, IMAPOPT_ADMINS);
-+
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag, reply);
-+
-+ /* Create telemetry log */
-+ imapd_logfd = telemetry_log(imapd_userid, imapd_in, imapd_out, 0);
-+
-+ /* Set namespace */
-+ if ((r = mboxname_init_namespace(&imapd_namespace,
-+ imapd_userisadmin || imapd_userisproxyadmin)) != 0) {
-+ syslog(LOG_ERR, error_message(r));
-+ fatal(error_message(r), EC_CONFIG);
-+ }
-+
-+ /* Translate any separators in userid */
-+ mboxname_hiersep_tointernal(&imapd_namespace, imapd_userid,
-+ config_virtdomains ?
-+ strcspn(imapd_userid, "@") : 0);
-+
-+ freebuf(&passwdbuf);
-+ return;
-+}
-+
-+/*
-+ * Perform an AUTHENTICATE command
-+ */
-+void
-+cmd_authenticate(char *tag, char *authtype, char *resp)
-+{
-+ int sasl_result;
-+
-+ const int *ssfp;
-+ char *ssfmsg=NULL;
-+
-+ const char *canon_user;
-+
-+ int r;
-+
-+ r = saslserver(imapd_saslconn, authtype, resp, "", "+ ", "",
-+ imapd_in, imapd_out, &sasl_result, NULL);
-+
-+ if (r) {
-+ const char *errorstring = NULL;
-+
-+ switch (r) {
-+ case IMAP_SASL_CANCEL:
-+ prot_printf(imapd_out,
-+ "%s BAD Client canceled authentication\r\n", tag);
-+ break;
-+ case IMAP_SASL_PROTERR:
-+ errorstring = prot_error(imapd_in);
-+
-+ prot_printf(imapd_out,
-+ "%s NO Error reading client response: %s\r\n",
-+ tag, errorstring ? errorstring : "");
-+ break;
-+ default:
-+ /* failed authentication */
-+ errorstring = sasl_errstring(sasl_result, NULL, NULL);
-+
-+ syslog(LOG_NOTICE, "badlogin: %s %s [%s]",
-+ imapd_clienthost, authtype, sasl_errdetail(imapd_saslconn));
-+
-+ snmp_increment_args(AUTHENTICATION_NO, 1,
-+ VARIABLE_AUTH, 0, /* hash_simple(authtype) */
-+ VARIABLE_LISTEND);
-+ sleep(3);
-+
-+ if (errorstring) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, errorstring);
-+ } else {
-+ prot_printf(imapd_out, "%s NO Error authenticating\r\n", tag);
-+ }
-+ }
-+
-+ reset_saslconn(&imapd_saslconn);
-+ return;
-+ }
-+
-+ /* successful authentication */
-+
-+ /* get the userid from SASL --- already canonicalized from
-+ * mysasl_proxy_policy()
-+ */
-+ sasl_result = sasl_getprop(imapd_saslconn, SASL_USERNAME,
-+ (const void **) &canon_user);
-+ if (sasl_result != SASL_OK) {
-+ prot_printf(imapd_out, "%s NO weird SASL error %d SASL_USERNAME\r\n",
-+ tag, sasl_result);
-+ syslog(LOG_ERR, "weird SASL error %d getting SASL_USERNAME",
-+ sasl_result);
-+ reset_saslconn(&imapd_saslconn);
-+ return;
-+ }
-+
-+ /* If we're proxying, the authzid may contain a magic plus,
-+ so re-canonify it */
-+ if (config_getswitch(IMAPOPT_IMAPMAGICPLUS) && strchr(canon_user, '+')) {
-+ char userbuf[MAX_MAILBOX_NAME+1];
-+ unsigned userlen;
-+
-+ sasl_result = imapd_canon_user(imapd_saslconn, NULL, canon_user, 0,
-+ SASL_CU_AUTHID | SASL_CU_AUTHZID,
-+ NULL, userbuf, sizeof(userbuf), &userlen);
-+ if (sasl_result != SASL_OK) {
-+ prot_printf(imapd_out,
-+ "%s NO SASL canonification error %d\r\n",
-+ tag, sasl_result);
-+ reset_saslconn(&imapd_saslconn);
-+ return;
-+ }
-+
-+ imapd_userid = xstrdup(userbuf);
-+ } else {
-+ imapd_userid = xstrdup(canon_user);
-+ }
-+
-+ proc_register("imapd", imapd_clienthost, imapd_userid, (char *)0);
-+
-+ syslog(LOG_NOTICE, "login: %s %s%s %s%s %s", imapd_clienthost,
-+ imapd_userid, imapd_magicplus ? imapd_magicplus : "",
-+ authtype, imapd_starttls_done ? "+TLS" : "", "User logged in");
-+
-+ sasl_getprop(imapd_saslconn, SASL_SSF, (const void **) &ssfp);
-+
-+ /* really, we should be doing a sasl_getprop on SASL_SSF_EXTERNAL,
-+ but the current libsasl doesn't allow that. */
-+ if (imapd_starttls_done) {
-+ switch(*ssfp) {
-+ case 0: ssfmsg = "tls protection"; break;
-+ case 1: ssfmsg = "tls plus integrity protection"; break;
-+ default: ssfmsg = "tls plus privacy protection"; break;
-+ }
-+ } else {
-+ switch(*ssfp) {
-+ case 0: ssfmsg = "no protection"; break;
-+ case 1: ssfmsg = "integrity protection"; break;
-+ default: ssfmsg = "privacy protection"; break;
-+ }
-+ }
-+
-+ snmp_increment_args(AUTHENTICATION_YES, 1,
-+ VARIABLE_AUTH, 0, /* hash_simple(authtype) */
-+ VARIABLE_LISTEND);
-+
-+ prot_printf(imapd_out, "%s OK Success (%s)\r\n", tag, ssfmsg);
-+
-+ prot_setsasl(imapd_in, imapd_saslconn);
-+ prot_setsasl(imapd_out, imapd_saslconn);
-+
-+ /* Create telemetry log */
-+ imapd_logfd = telemetry_log(imapd_userid, imapd_in, imapd_out, 0);
-+
-+ /* Set namespace */
-+ if ((r = mboxname_init_namespace(&imapd_namespace,
-+ imapd_userisadmin || imapd_userisproxyadmin)) != 0) {
-+ syslog(LOG_ERR, error_message(r));
-+ fatal(error_message(r), EC_CONFIG);
-+ }
-+
-+ /* Translate any separators in userid */
-+ mboxname_hiersep_tointernal(&imapd_namespace, imapd_userid,
-+ config_virtdomains ?
-+ strcspn(imapd_userid, "@") : 0);
-+
-+ return;
-+}
-+
-+/*
-+ * Perform a NOOP command
-+ */
-+void
-+cmd_noop(char *tag, char *cmd __attribute__((unused)))
-+{
-+ if (imapd_mailbox) {
-+ index_check(imapd_mailbox, 0, 1);
-+ }
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+}
-+
-+/*
-+ * Parse and perform an ID command.
-+ *
-+ * the command has been parsed up to the parameter list.
-+ *
-+ * we only allow one ID in non-authenticated state from a given client.
-+ * we only allow MAXIDFAILED consecutive failed IDs from a given client.
-+ * we only record MAXIDLOG ID responses from a given client.
-+ */
-+void cmd_id(char *tag)
-+{
-+ static int did_id = 0;
-+ static int failed_id = 0;
-+ static int logged_id = 0;
-+ int error = 0;
-+ int c = EOF, npair = 0;
-+ static struct buf arg, field;
-+ struct attvaluelist *params = 0;
-+
-+ /* check if we've already had an ID in non-authenticated state */
-+ if (!imapd_userid && did_id) {
-+ prot_printf(imapd_out,
-+ "%s NO Only one Id allowed in non-authenticated state\r\n",
-+ tag);
-+ eatline(imapd_in, c);
-+ return;
-+ }
-+
-+ /* check if we've had too many failed IDs in a row */
-+ if (failed_id >= MAXIDFAILED) {
-+ prot_printf(imapd_out, "%s NO Too many (%u) invalid Id commands\r\n",
-+ tag, failed_id);
-+ eatline(imapd_in, c);
-+ return;
-+ }
-+
-+ /* ok, accept parameter list */
-+ c = getword(imapd_in, &arg);
-+ /* check for "NIL" or start of parameter list */
-+ if (strcasecmp(arg.s, "NIL") && c != '(') {
-+ prot_printf(imapd_out, "%s BAD Invalid parameter list in Id\r\n", tag);
-+ eatline(imapd_in, c);
-+ failed_id++;
-+ return;
-+ }
-+
-+ /* parse parameter list */
-+ if (c == '(') {
-+ for (;;) {
-+ if (c == ')') {
-+ /* end of string/value pairs */
-+ break;
-+ }
-+
-+ /* get field name */
-+ c = getstring(imapd_in, imapd_out, &field);
-+ if (c != ' ') {
-+ prot_printf(imapd_out,
-+ "%s BAD Invalid/missing field name in Id\r\n",
-+ tag);
-+ error = 1;
-+ break;
-+ }
-+
-+ /* get field value */
-+ c = getnstring(imapd_in, imapd_out, &arg);
-+ if (c != ' ' && c != ')') {
-+ prot_printf(imapd_out,
-+ "%s BAD Invalid/missing value in Id\r\n",
-+ tag);
-+ error = 1;
-+ break;
-+ }
-+
-+ /* ok, we're anal, but we'll still process the ID command */
-+ if (strlen(field.s) > MAXIDFIELDLEN) {
-+ prot_printf(imapd_out,
-+ "%s BAD field longer than %u octets in Id\r\n",
-+ tag, MAXIDFIELDLEN);
-+ error = 1;
-+ break;
-+ }
-+ if (strlen(arg.s) > MAXIDVALUELEN) {
-+ prot_printf(imapd_out,
-+ "%s BAD value longer than %u octets in Id\r\n",
-+ tag, MAXIDVALUELEN);
-+ error = 1;
-+ break;
-+ }
-+ if (++npair > MAXIDPAIRS) {
-+ prot_printf(imapd_out,
-+ "%s BAD too many (%u) field-value pairs in ID\r\n",
-+ tag, MAXIDPAIRS);
-+ error = 1;
-+ break;
-+ }
-+
-+ /* ok, we're happy enough */
-+ appendattvalue(¶ms, field.s, arg.s);
-+ }
-+
-+ if (error || c != ')') {
-+ /* erp! */
-+ eatline(imapd_in, c);
-+ freeattvalues(params);
-+ failed_id++;
-+ return;
-+ }
-+ c = prot_getc(imapd_in);
-+ }
-+
-+ /* check for CRLF */
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') {
-+ prot_printf(imapd_out,
-+ "%s BAD Unexpected extra arguments to Id\r\n", tag);
-+ eatline(imapd_in, c);
-+ freeattvalues(params);
-+ failed_id++;
-+ return;
-+ }
-+
-+ /* log the client's ID string.
-+ eventually this should be a callback or something. */
-+ if (npair && logged_id < MAXIDLOG) {
-+ char logbuf[MAXIDLOGLEN + 1] = "";
-+ struct attvaluelist *pptr;
-+
-+ for (pptr = params; pptr; pptr = pptr->next) {
-+ /* should we check for and format literals here ??? */
-+ snprintf(logbuf + strlen(logbuf), MAXIDLOGLEN - strlen(logbuf),
-+ " \"%s\" ", pptr->attrib);
-+ if (!strcmp(pptr->value, "NIL"))
-+ snprintf(logbuf + strlen(logbuf), MAXIDLOGLEN - strlen(logbuf),
-+ "NIL");
-+ else
-+ snprintf(logbuf + strlen(logbuf), MAXIDLOGLEN - strlen(logbuf),
-+ "\"%s\"", pptr->value);
-+ }
-+
-+ syslog(LOG_INFO, "client id:%s", logbuf);
-+
-+ logged_id++;
-+ }
-+
-+ freeattvalues(params);
-+
-+ /* spit out our ID string.
-+ eventually this might be configurable. */
-+ if (config_getswitch(IMAPOPT_IMAPIDRESPONSE)) {
-+ id_response(imapd_out);
-+ prot_printf(imapd_out, ")\r\n");
-+ }
-+ else
-+ prot_printf(imapd_out, "* ID NIL\r\n");
-+
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+
-+ failed_id = 0;
-+ did_id = 1;
-+}
-+
-+/*
-+ * Perform an IDLE command
-+ */
-+void cmd_idle(char *tag)
-+{
-+ int c;
-+ static struct buf arg;
-+
-+ /* Setup for doing mailbox updates */
-+ if (!idle_init(imapd_mailbox, idle_update)) {
-+ prot_printf(imapd_out,
-+ "%s NO cannot start idling\r\n", tag);
-+ return;
-+ }
-+
-+ /* Tell client we are idling and waiting for end of command */
-+ prot_printf(imapd_out, "+ idling\r\n");
-+ prot_flush(imapd_out);
-+
-+ /* Get continuation data */
-+ c = getword(imapd_in, &arg);
-+ if (c != EOF) {
-+ if (!strcasecmp(arg.s, "Done") &&
-+ (c = (c == '\r') ? prot_getc(imapd_in) : c) == '\n') {
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ }
-+
-+ else {
-+ prot_printf(imapd_out,
-+ "%s BAD Invalid Idle continuation\r\n", tag);
-+ eatline(imapd_in, c);
-+ }
-+ }
-+
-+ /* Do any necessary cleanup */
-+ idle_done(imapd_mailbox);
-+
-+ return;
-+}
-+
-+/* Send unsolicited untagged responses to the client */
-+void idle_update(idle_flags_t flags)
-+{
-+ if ((flags & IDLE_MAILBOX) && imapd_mailbox)
-+ index_check(imapd_mailbox, 0, 1);
-+
-+ if (flags & IDLE_ALERT) {
-+ char shut[1024];
-+ if (! imapd_userisadmin && shutdown_file(shut, sizeof(shut))) {
-+ char *p;
-+ for (p = shut; *p == '['; p++); /* can't have [ be first char */
-+ prot_printf(imapd_out, "* BYE [ALERT] %s\r\n", p);
-+ shut_down(0);
-+ }
-+ }
-+
-+ prot_flush(imapd_out);
-+}
-+
-+/*
-+ * Perform a CAPABILITY command
-+ */
-+void cmd_capability(char *tag)
-+{
-+ const char *sasllist; /* the list of SASL mechanisms */
-+ unsigned mechcount;
-+
-+ if (imapd_mailbox) {
-+ index_check(imapd_mailbox, 0, 0);
-+ }
-+ prot_printf(imapd_out, "* CAPABILITY " CAPABILITY_STRING);
-+
-+ if (idle_enabled()) {
-+ prot_printf(imapd_out, " IDLE");
-+ }
-+
-+ if (tls_enabled() && !imapd_starttls_done && !imapd_authstate) {
-+ prot_printf(imapd_out, " STARTTLS");
-+ }
-+ if (imapd_authstate ||
-+ (!imapd_starttls_done && !config_getswitch(IMAPOPT_ALLOWPLAINTEXT))) {
-+ prot_printf(imapd_out, " LOGINDISABLED");
-+ }
-+
-+ if(config_mupdate_server) {
-+ prot_printf(imapd_out, " MUPDATE=mupdate://%s/", config_mupdate_server);
-+ }
-+
-+ /* add the SASL mechs */
-+ if (!imapd_authstate &&
-+ sasl_listmech(imapd_saslconn, NULL,
-+ "AUTH=", " AUTH=", " SASL-IR",
-+ &sasllist,
-+ NULL, &mechcount) == SASL_OK && mechcount > 0) {
-+ prot_printf(imapd_out, " %s", sasllist);
-+ } else {
-+ /* else don't show anything */
-+ }
-+
-+#ifdef ENABLE_LISTEXT
-+ prot_printf(imapd_out, " LISTEXT LIST-SUBSCRIBED");
-+#endif /* ENABLE_LISTEXT */
-+
-+#ifdef ENABLE_X_NETSCAPE_HACK
-+ prot_printf(imapd_out, " X-NETSCAPE");
-+#endif
-+ prot_printf(imapd_out, "\r\n%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+}
-+
-+/*
-+ * Parse and perform an APPEND command.
-+ * The command has been parsed up to and including
-+ * the mailbox name.
-+ */
-+static int isokflag(char *s)
-+{
-+ if (s[0] == '\\') {
-+ lcase(s);
-+ if (!strcmp(s, "\\seen")) return 1;
-+ if (!strcmp(s, "\\answered")) return 1;
-+ if (!strcmp(s, "\\flagged")) return 1;
-+ if (!strcmp(s, "\\draft")) return 1;
-+ if (!strcmp(s, "\\deleted")) return 1;
-+
-+ /* uh oh, system flag i don't recognize */
-+ return 0;
-+ } else {
-+ /* valid user flag? */
-+ return imparse_isatom(s);
-+ }
-+}
-+
-+#define FLAGGROW 10
-+void cmd_append(char *tag, char *name)
-+
-+{
-+ int c;
-+ static struct buf arg;
-+ char *p;
-+ time_t now = time(NULL);
-+ unsigned size, totalsize = 0;
-+ int sawdigit = 0;
-+ int isnowait = 0;
-+ int r, i;
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+ struct appendstate mailbox;
-+ unsigned long uidvalidity;
-+ unsigned long firstuid, num;
-+ const char *parseerr = NULL;
-+ FILE *f;
-+ int numalloc = 5;
-+ struct appendstage *curstage;
-+
-+ /* See if we can append */
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+ if (!r) {
-+ r = append_check(mailboxname, MAILBOX_FORMAT_NORMAL,
-+ imapd_authstate, ACL_INSERT, totalsize);
-+ }
-+ if (r) {
-+ eatline(imapd_in, ' ');
-+ prot_printf(imapd_out, "%s NO %s%s\r\n",
-+ tag,
-+ (r == IMAP_MAILBOX_NONEXISTENT &&
-+ mboxlist_createmailboxcheck(mailboxname, 0, 0,
-+ imapd_userisadmin,
-+ imapd_userid, imapd_authstate,
-+ (char **)0, (char **)0) == 0)
-+ ? "[TRYCREATE] " : "", error_message(r));
-+ return;
-+ }
-+
-+ stage = xmalloc(numalloc * sizeof(struct appendstage *));
-+
-+ c = ' '; /* just parsed a space */
-+ /* we loop, to support MULTIAPPEND */
-+ while (!r && c == ' ') {
-+ /* Grow the stage array, if necessary */
-+ if (numstage == numalloc) {
-+ /* Avoid integer wrap as arg to xrealloc */
-+ if (numalloc > INT_MAX/(2*sizeof(struct appendstage *)))
-+ goto done;
-+ numalloc *= 2;
-+ stage = xrealloc(stage, numalloc * sizeof(struct appendstage *));
-+ }
-+ curstage = stage[numstage] = xzmalloc(sizeof(struct appendstage));
-+ numstage++;
-+ /* Parse flags */
-+ c = getword(imapd_in, &arg);
-+ if (c == '(' && !arg.s[0]) {
-+ curstage->nflags = 0;
-+ do {
-+ c = getword(imapd_in, &arg);
-+ if (!curstage->nflags && !arg.s[0] && c == ')') break; /* empty list */
-+ if (!isokflag(arg.s)) {
-+ parseerr = "Invalid flag in Append command";
-+ r = IMAP_PROTOCOL_ERROR;
-+ goto done;
-+ }
-+ if (curstage->nflags == curstage->flagalloc) {
-+ curstage->flagalloc += FLAGGROW;
-+ curstage->flag =
-+ (char **) xrealloc((char *) curstage->flag,
-+ curstage->flagalloc * sizeof(char *));
-+ }
-+ curstage->flag[curstage->nflags] = xstrdup(arg.s);
-+ curstage->nflags++;
-+ } while (c == ' ');
-+ if (c != ')') {
-+ parseerr =
-+ "Missing space or ) after flag name in Append command";
-+ r = IMAP_PROTOCOL_ERROR;
-+ goto done;
-+ }
-+ c = prot_getc(imapd_in);
-+ if (c != ' ') {
-+ parseerr = "Missing space after flag list in Append command";
-+ r = IMAP_PROTOCOL_ERROR;
-+ goto done;
-+ }
-+ c = getword(imapd_in, &arg);
-+ }
-+
-+ /* Parse internaldate */
-+ if (c == '\"' && !arg.s[0]) {
-+ prot_ungetc(c, imapd_in);
-+ c = getdatetime(&(curstage->internaldate));
-+ if (c != ' ') {
-+ parseerr = "Invalid date-time in Append command";
-+ r = IMAP_PROTOCOL_ERROR;
-+ goto done;
-+ }
-+ c = getword(imapd_in, &arg);
-+ } else {
-+ curstage->internaldate = now;
-+ }
-+
-+ p = arg.s;
-+ /* Check for literal8 */
-+ if (*p == '~') {
-+ p++;
-+ /* We don't support binary append yet */
-+ r = IMAP_NO_UNKNOWN_CTE;
-+ goto done;
-+ }
-+ if (*p != '{') {
-+ parseerr = "Missing required argument to Append command";
-+ r = IMAP_PROTOCOL_ERROR;
-+ goto done;
-+ }
-+
-+ /* Read size from literal */
-+ isnowait = 0;
-+ size = 0;
-+ for (++p; *p && isdigit((int) *p); p++) {
-+ sawdigit++;
-+ size = size*10 + *p - '0';
-+#if 0
-+ if (size < 0) {
-+ lose();
-+ }
-+#endif
-+ }
-+ if (*p == '+') {
-+ isnowait++;
-+ p++;
-+ }
-+
-+ if (c == '\r') {
-+ c = prot_getc(imapd_in);
-+ }
-+ else {
-+ prot_ungetc(c, imapd_in);
-+ c = ' '; /* Force a syntax error */
-+ }
-+
-+ if (*p != '}' || p[1] || c != '\n' || !sawdigit) {
-+ parseerr = "Invalid literal in Append command";
-+ r = IMAP_PROTOCOL_ERROR;
-+ goto done;
-+ }
-+
-+ if (!isnowait) {
-+ /* Tell client to send the message */
-+ prot_printf(imapd_out, "+ go ahead\r\n");
-+ prot_flush(imapd_out);
-+ }
-+
-+ /* Stage the message */
-+ f = append_newstage(mailboxname, now, numstage, &(curstage->stage));
-+ if (f) {
-+ totalsize += size;
-+ r = message_copy_strict(imapd_in, f, size);
-+ fclose(f);
-+ } else {
-+ r = IMAP_IOERROR;
-+ }
-+
-+ /* if we see a SP, we're trying to append more than one message */
-+
-+ /* Parse newline terminating command */
-+ c = prot_getc(imapd_in);
-+ }
-+
-+ done:
-+ if (r) {
-+ eatline(imapd_in, c);
-+ } else {
-+ /* we should be looking at the end of the line */
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') {
-+ parseerr = "junk after literal";
-+ r = IMAP_PROTOCOL_ERROR;
-+ eatline(imapd_in, c);
-+ }
-+ }
-+
-+ /* Append from the stage(s) */
-+ if (!r) {
-+ r = append_setup(&mailbox, mailboxname, MAILBOX_FORMAT_NORMAL,
-+ imapd_userid, imapd_authstate, ACL_INSERT, totalsize);
-+ }
-+ if (!r) {
-+ for (i = 0; !r && i < numstage; i++) {
-+ r = append_fromstage(&mailbox, stage[i]->stage, stage[i]->internaldate,
-+ (const char **) stage[i]->flag, stage[i]->nflags, 0);
-+ }
-+
-+ if (!r) {
-+ r = append_commit(&mailbox, totalsize, &uidvalidity, &firstuid, &num);
-+ } else {
-+ append_abort(&mailbox);
-+ }
-+ }
-+
-+ /* Cleanup the stage(s) */
-+ while (numstage) {
-+ curstage = stage[--numstage];
-+
-+ append_removestage(curstage->stage);
-+ while (curstage->nflags--) {
-+ free(curstage->flag[curstage->nflags]);
-+ }
-+ if (curstage->flag) free((char *) curstage->flag);
-+ free(curstage);
-+ }
-+ if (stage) free(stage);
-+ stage = NULL;
-+
-+ if (imapd_mailbox) {
-+ index_check(imapd_mailbox, 0, 0);
-+ }
-+
-+ if (r == IMAP_PROTOCOL_ERROR && parseerr) {
-+ prot_printf(imapd_out, "%s BAD %s\r\n", tag, parseerr);
-+ } else if (r) {
-+ prot_printf(imapd_out, "%s NO %s%s\r\n",
-+ tag,
-+ (r == IMAP_MAILBOX_NONEXISTENT &&
-+ mboxlist_createmailboxcheck(mailboxname, 0, 0,
-+ imapd_userisadmin,
-+ imapd_userid, imapd_authstate,
-+ (char **)0, (char **)0) == 0)
-+ ? "[TRYCREATE] " : "", error_message(r));
-+ } else {
-+ /* is this a space seperated list or sequence list? */
-+ prot_printf(imapd_out, "%s OK [APPENDUID %lu", tag, uidvalidity);
-+ if (num == 1) {
-+ prot_printf(imapd_out, " %lu", firstuid);
-+ } else {
-+ prot_printf(imapd_out, " %lu:%lu", firstuid, firstuid + num - 1);
-+ }
-+ prot_printf(imapd_out, "] %s\r\n", error_message(IMAP_OK_COMPLETED));
-+ }
-+}
-+
-+/*
-+ * Perform a SELECT/EXAMINE/BBOARD command
-+ */
-+void cmd_select(char *tag, char *cmd, char *name)
-+{
-+ struct mailbox mailbox;
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+ int r = 0;
-+ double usage;
-+ int doclose = 0;
-+
-+ if (imapd_mailbox) {
-+ index_closemailbox(imapd_mailbox);
-+ mailbox_close(imapd_mailbox);
-+ imapd_mailbox = 0;
-+ }
-+
-+ if (cmd[0] == 'B') {
-+ /* BBoard namespace is empty */
-+ r = IMAP_MAILBOX_NONEXISTENT;
-+ }
-+ else {
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+ }
-+
-+ if (!r) {
-+ r = mlookup(tag, name, mailboxname, NULL, NULL, NULL, NULL, NULL);
-+ }
-+ if (r == IMAP_MAILBOX_MOVED) return;
-+
-+ if (!r) {
-+ r = mailbox_open_header(mailboxname, imapd_authstate, &mailbox);
-+ }
-+
-+ if (!r) {
-+ doclose = 1;
-+ r = mailbox_open_index(&mailbox);
-+ }
-+ if (!r && !(mailbox.myrights & ACL_READ)) {
-+ r = (imapd_userisadmin || (mailbox.myrights & ACL_LOOKUP)) ?
-+ IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
-+ }
-+ if (!r && chdir(mailbox.path)) {
-+ syslog(LOG_ERR, "IOERROR: changing directory to %s: %m", mailbox.path);
-+ r = IMAP_IOERROR;
-+ }
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ if (doclose) mailbox_close(&mailbox);
-+ return;
-+ }
-+
-+ mboxstruct = mailbox;
-+ imapd_mailbox = &mboxstruct;
-+
-+ index_newmailbox(imapd_mailbox, cmd[0] == 'E');
-+
-+ /* Examine command puts mailbox in read-only mode */
-+ if (cmd[0] == 'E') {
-+ imapd_mailbox->myrights &= ~(ACL_SEEN|ACL_WRITE|ACL_DELETE);
-+ }
-+
-+ if (imapd_mailbox->myrights & ACL_DELETE) {
-+ /* Warn if mailbox is close to or over quota */
-+ r = quota_read(&imapd_mailbox->quota, NULL, 0);
-+ if (!r && imapd_mailbox->quota.limit > 0) {
-+ /* Warn if the following possibilities occur:
-+ * - quotawarnkb not set + quotawarn hit
-+ * - quotawarnkb set larger than mailbox + quotawarn hit
-+ * - quotawarnkb set + hit + quotawarn hit
-+ */
-+ int warnsize = config_getint(IMAPOPT_QUOTAWARNKB);
-+ if (warnsize <= 0 || warnsize >= imapd_mailbox->quota.limit ||
-+ (int)((imapd_mailbox->quota.limit * QUOTA_UNITS) -
-+ imapd_mailbox->quota.used) < (warnsize * QUOTA_UNITS)) {
-+ usage = ((double) imapd_mailbox->quota.used * 100.0) / (double)
-+ (imapd_mailbox->quota.limit * QUOTA_UNITS);
-+ if (usage >= 100.0) {
-+ prot_printf(imapd_out, "* NO [ALERT] %s\r\n",
-+ error_message(IMAP_NO_OVERQUOTA));
-+ }
-+ else if (usage > config_getint(IMAPOPT_QUOTAWARN)) {
-+ int usageint = (int) usage;
-+ prot_printf(imapd_out, "* NO [ALERT] ");
-+ prot_printf(imapd_out, error_message(IMAP_NO_CLOSEQUOTA),
-+ usageint);
-+ prot_printf(imapd_out, "\r\n");
-+ }
-+ }
-+ }
-+ }
-+
-+ prot_printf(imapd_out, "%s OK [READ-%s] %s\r\n", tag,
-+ (imapd_mailbox->myrights & (ACL_WRITE|ACL_DELETE)) ?
-+ "WRITE" : "ONLY", error_message(IMAP_OK_COMPLETED));
-+
-+ proc_register("imapd", imapd_clienthost, imapd_userid, mailboxname);
-+ syslog(LOG_DEBUG, "open: user %s opened %s", imapd_userid, name);
-+}
-+
-+/*
-+ * Perform a CLOSE command
-+ */
-+void
-+cmd_close(tag)
-+char *tag;
-+{
-+ int r;
-+
-+ if (!(imapd_mailbox->myrights & ACL_DELETE)) r = 0;
-+ else {
-+ r = mailbox_expunge(imapd_mailbox, 1, (int (*)())0, (char *)0);
-+ }
-+
-+ index_closemailbox(imapd_mailbox);
-+ mailbox_close(imapd_mailbox);
-+ imapd_mailbox = 0;
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ }
-+ else {
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ }
-+}
-+
-+/*
-+ * Perform an UNSELECT command -- for some support of IMAP proxy.
-+ * Just like close except no expunge.
-+ */
-+void
-+cmd_unselect(tag)
-+char* tag;
-+{
-+ index_closemailbox(imapd_mailbox);
-+ mailbox_close(imapd_mailbox);
-+ imapd_mailbox = 0;
-+
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+}
-+
-+/*
-+ * Parse the syntax for a partial fetch:
-+ * "<" number "." nz-number ">"
-+ */
-+#define PARSE_PARTIAL(start_octet, octet_count) \
-+ (start_octet) = (octet_count) = 0; \
-+ if (*p == '<' && isdigit((int) p[1])) { \
-+ (start_octet) = p[1] - '0'; \
-+ p += 2; \
-+ while (isdigit((int) *p)) { \
-+ (start_octet) = \
-+ (start_octet) * 10 + *p++ - '0'; \
-+ } \
-+ \
-+ if (*p == '.' && p[1] >= '1' && p[1] <= '9') { \
-+ (octet_count) = p[1] - '0'; \
-+ p[0] = '>'; p[1] = '\0'; /* clip off the octet count \
-+ (its not used in the reply) */ \
-+ p += 2; \
-+ while (isdigit((int) *p)) { \
-+ (octet_count) = \
-+ (octet_count) * 10 + *p++ - '0'; \
-+ } \
-+ } \
-+ else p--; \
-+ \
-+ if (*p != '>') { \
-+ prot_printf(imapd_out, \
-+ "%s BAD Invalid body partial\r\n", tag); \
-+ eatline(imapd_in, c); \
-+ goto freeargs; \
-+ } \
-+ p++; \
-+ }
-+
-+/*
-+ * Parse and perform a FETCH/UID FETCH command
-+ * The command has been parsed up to and including
-+ * the sequence
-+ */
-+void cmd_fetch(char *tag, char *sequence, int usinguid)
-+{
-+ char *cmd = usinguid ? "UID Fetch" : "Fetch";
-+ static struct buf fetchatt, fieldname;
-+ int c;
-+ int inlist = 0;
-+ int fetchitems = 0;
-+ struct fetchargs fetchargs;
-+ struct octetinfo oi;
-+ struct strlist *newfields = 0;
-+ char *p, *section;
-+ int fetchedsomething, r;
-+ clock_t start = clock();
-+ char mytime[100];
-+
-+ memset(&fetchargs, 0, sizeof(struct fetchargs));
-+
-+ c = getword(imapd_in, &fetchatt);
-+ if (c == '(' && !fetchatt.s[0]) {
-+ inlist = 1;
-+ c = getword(imapd_in, &fetchatt);
-+ }
-+ for (;;) {
-+ ucase(fetchatt.s);
-+ switch (fetchatt.s[0]) {
-+ case 'A':
-+ if (!inlist && !strcmp(fetchatt.s, "ALL")) {
-+ fetchitems |= FETCH_ALL;
-+ }
-+ else goto badatt;
-+ break;
-+
-+ case 'B':
-+ if (!strncmp(fetchatt.s, "BINARY[", 7) ||
-+ !strncmp(fetchatt.s, "BINARY.PEEK[", 12) ||
-+ !strncmp(fetchatt.s, "BINARY.SIZE[", 12)) {
-+ int binsize = 0;
-+
-+ p = section = fetchatt.s + 7;
-+ if (!strncmp(p, "PEEK[", 5)) {
-+ p = section += 5;
-+ }
-+ else if (!strncmp(p, "SIZE[", 5)) {
-+ p = section += 5;
-+ binsize = 1;
-+ }
-+ else {
-+ fetchitems |= FETCH_SETSEEN;
-+ }
-+ while ((*p >= '1' && *p <= '9') || *p == '.') {
-+ if (*p == '.' && !isdigit((int) p[-1])) break;
-+ p++;
-+ }
-+
-+ if (*p != ']') {
-+ prot_printf(imapd_out, "%s BAD Invalid body section\r\n", tag);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+ p++;
-+
-+ if (!binsize) PARSE_PARTIAL(oi.start_octet, oi.octet_count);
-+
-+ if (*p) {
-+ prot_printf(imapd_out, "%s BAD Junk after body section\r\n", tag);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+ if (binsize)
-+ appendstrlist_withdata(&fetchargs.sizesections, section, &oi, sizeof(oi));
-+ else
-+ appendstrlist_withdata(&fetchargs.binsections, section, &oi, sizeof(oi));
-+ }
-+ else if (!strcmp(fetchatt.s, "BODY")) {
-+ fetchitems |= FETCH_BODY;
-+ }
-+ else if (!strcmp(fetchatt.s, "BODYSTRUCTURE")) {
-+ fetchitems |= FETCH_BODYSTRUCTURE;
-+ }
-+ else if (!strncmp(fetchatt.s, "BODY[", 5) ||
-+ !strncmp(fetchatt.s, "BODY.PEEK[", 10)) {
-+ p = section = fetchatt.s + 5;
-+ if (!strncmp(p, "PEEK[", 5)) {
-+ p = section += 5;
-+ }
-+ else {
-+ fetchitems |= FETCH_SETSEEN;
-+ }
-+ while (isdigit((int) *p) || *p == '.') {
-+ if (*p == '.' && !isdigit((int) p[-1])) break;
-+ /* Obsolete section 0 can only occur before close brace */
-+ if (*p == '0' && !isdigit((int) p[-1]) && p[1] != ']') break;
-+ p++;
-+ }
-+
-+ if (*p == 'H' && !strncmp(p, "HEADER.FIELDS", 13) &&
-+ (p == section || p[-1] == '.') &&
-+ (p[13] == '\0' || !strcmp(p+13, ".NOT"))) {
-+
-+ /*
-+ * If not top-level or a HEADER.FIELDS.NOT, can't pull
-+ * the headers out of the cache.
-+ */
-+ if (p != section || p[13] != '\0') {
-+ fetchargs.cache_atleast = BIT32_MAX;
-+ }
-+
-+ if (c != ' ') {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing required argument to %s %s\r\n",
-+ tag, cmd, fetchatt.s);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+ c = prot_getc(imapd_in);
-+ if (c != '(') {
-+ prot_printf(imapd_out, "%s BAD Missing required open parenthesis in %s %s\r\n",
-+ tag, cmd, fetchatt.s);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+ do {
-+ c = getastring(imapd_in, imapd_out, &fieldname);
-+ for (p = fieldname.s; *p; p++) {
-+ if (*p <= ' ' || *p & 0x80 || *p == ':') break;
-+ }
-+ if (*p || !*fieldname.s) {
-+ prot_printf(imapd_out, "%s BAD Invalid field-name in %s %s\r\n",
-+ tag, cmd, fetchatt.s);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+ appendstrlist(&newfields, fieldname.s);
-+ if (fetchargs.cache_atleast < BIT32_MAX) {
-+ bit32 this_ver =
-+ mailbox_cached_header(fieldname.s);
-+ if(this_ver > fetchargs.cache_atleast)
-+ fetchargs.cache_atleast = this_ver;
-+ }
-+ } while (c == ' ');
-+ if (c != ')') {
-+ prot_printf(imapd_out, "%s BAD Missing required close parenthesis in %s %s\r\n",
-+ tag, cmd, fetchatt.s);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+
-+ /* Grab/parse the ]<x.y> part */
-+ c = getword(imapd_in, &fieldname);
-+ p = fieldname.s;
-+ if (*p++ != ']') {
-+ prot_printf(imapd_out, "%s BAD Missing required close bracket after %s %s\r\n",
-+ tag, cmd, fetchatt.s);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+
-+ PARSE_PARTIAL(oi.start_octet, oi.octet_count);
-+
-+ if (*p) {
-+ prot_printf(imapd_out, "%s BAD Junk after body section\r\n", tag);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+ appendfieldlist(&fetchargs.fsections,
-+ section, newfields, fieldname.s,
-+ &oi, sizeof(oi));
-+ newfields = 0;
-+ break;
-+ }
-+
-+ switch (*p) {
-+ case 'H':
-+ if (p != section && p[-1] != '.') break;
-+ if (!strncmp(p, "HEADER]", 7)) p += 6;
-+ break;
-+
-+ case 'M':
-+ if (!strncmp(p-1, ".MIME]", 6)) p += 4;
-+ break;
-+
-+ case 'T':
-+ if (p != section && p[-1] != '.') break;
-+ if (!strncmp(p, "TEXT]", 5)) p += 4;
-+ break;
-+ }
-+
-+ if (*p != ']') {
-+ prot_printf(imapd_out, "%s BAD Invalid body section\r\n", tag);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+ p++;
-+
-+ PARSE_PARTIAL(oi.start_octet, oi.octet_count);
-+
-+ if (*p) {
-+ prot_printf(imapd_out, "%s BAD Junk after body section\r\n", tag);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+ appendstrlist_withdata(&fetchargs.bodysections, section,
-+ &oi, sizeof(oi));
-+ }
-+ else goto badatt;
-+ break;
-+
-+ case 'E':
-+ if (!strcmp(fetchatt.s, "ENVELOPE")) {
-+ fetchitems |= FETCH_ENVELOPE;
-+ }
-+ else goto badatt;
-+ break;
-+
-+ case 'F':
-+ if (!inlist && !strcmp(fetchatt.s, "FAST")) {
-+ fetchitems |= FETCH_FAST;
-+ }
-+ else if (!inlist && !strcmp(fetchatt.s, "FULL")) {
-+ fetchitems |= FETCH_FULL;
-+ }
-+ else if (!strcmp(fetchatt.s, "FLAGS")) {
-+ fetchitems |= FETCH_FLAGS;
-+ }
-+ else goto badatt;
-+ break;
-+
-+ case 'I':
-+ if (!strcmp(fetchatt.s, "INTERNALDATE")) {
-+ fetchitems |= FETCH_INTERNALDATE;
-+ }
-+ else goto badatt;
-+ break;
-+
-+ case 'R':
-+ if (!strcmp(fetchatt.s, "RFC822")) {
-+ fetchitems |= FETCH_RFC822|FETCH_SETSEEN;
-+ }
-+ else if (!strcmp(fetchatt.s, "RFC822.HEADER")) {
-+ fetchitems |= FETCH_HEADER;
-+ }
-+ else if (!strcmp(fetchatt.s, "RFC822.PEEK")) {
-+ fetchitems |= FETCH_RFC822;
-+ }
-+ else if (!strcmp(fetchatt.s, "RFC822.SIZE")) {
-+ fetchitems |= FETCH_SIZE;
-+ }
-+ else if (!strcmp(fetchatt.s, "RFC822.TEXT")) {
-+ fetchitems |= FETCH_TEXT|FETCH_SETSEEN;
-+ }
-+ else if (!strcmp(fetchatt.s, "RFC822.TEXT.PEEK")) {
-+ fetchitems |= FETCH_TEXT;
-+ }
-+ else if (!strcmp(fetchatt.s, "RFC822.HEADER.LINES") ||
-+ !strcmp(fetchatt.s, "RFC822.HEADER.LINES.NOT")) {
-+ if (c != ' ') {
-+ prot_printf(imapd_out, "%s BAD Missing required argument to %s %s\r\n",
-+ tag, cmd, fetchatt.s);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+ c = prot_getc(imapd_in);
-+ if (c != '(') {
-+ prot_printf(imapd_out, "%s BAD Missing required open parenthesis in %s %s\r\n",
-+ tag, cmd, fetchatt.s);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+ do {
-+ c = getastring(imapd_in, imapd_out, &fieldname);
-+ for (p = fieldname.s; *p; p++) {
-+ if (*p <= ' ' || *p & 0x80 || *p == ':') break;
-+ }
-+ if (*p || !*fieldname.s) {
-+ prot_printf(imapd_out, "%s BAD Invalid field-name in %s %s\r\n",
-+ tag, cmd, fetchatt.s);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+ lcase(fieldname.s);;
-+ /* 19 is magic number -- length of
-+ * "RFC822.HEADERS.NOT" */
-+ appendstrlist(strlen(fetchatt.s) == 19 ?
-+ &fetchargs.headers : &fetchargs.headers_not,
-+ fieldname.s);
-+ if (strlen(fetchatt.s) != 19) {
-+ fetchargs.cache_atleast = BIT32_MAX;
-+ }
-+ if (fetchargs.cache_atleast < BIT32_MAX) {
-+ bit32 this_ver =
-+ mailbox_cached_header(fieldname.s);
-+ if(this_ver > fetchargs.cache_atleast)
-+ fetchargs.cache_atleast = this_ver;
-+ }
-+ } while (c == ' ');
-+ if (c != ')') {
-+ prot_printf(imapd_out, "%s BAD Missing required close parenthesis in %s %s\r\n",
-+ tag, cmd, fetchatt.s);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+ c = prot_getc(imapd_in);
-+ }
-+ else goto badatt;
-+ break;
-+
-+ case 'U':
-+ if (!strcmp(fetchatt.s, "UID")) {
-+ fetchitems |= FETCH_UID;
-+ }
-+ else goto badatt;
-+ break;
-+
-+ default:
-+ badatt:
-+ prot_printf(imapd_out, "%s BAD Invalid %s attribute %s\r\n", tag, cmd, fetchatt.s);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+
-+ if (inlist && c == ' ') c = getword(imapd_in, &fetchatt);
-+ else break;
-+ }
-+
-+ if (inlist && c == ')') {
-+ inlist = 0;
-+ c = prot_getc(imapd_in);
-+ }
-+ if (inlist) {
-+ prot_printf(imapd_out, "%s BAD Missing close parenthesis in %s\r\n", tag, cmd);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') {
-+ prot_printf(imapd_out, "%s BAD Unexpected extra arguments to %s\r\n", tag, cmd);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+
-+ if (!fetchitems && !fetchargs.bodysections && !fetchargs.fsections &&
-+ !fetchargs.binsections && !fetchargs.sizesections &&
-+ !fetchargs.headers && !fetchargs.headers_not) {
-+ prot_printf(imapd_out, "%s BAD Missing required argument to %s\r\n", tag, cmd);
-+ goto freeargs;
-+ }
-+
-+ if (usinguid) {
-+ fetchitems |= FETCH_UID;
-+ }
-+ index_check(imapd_mailbox, 1, 0);
-+
-+ fetchargs.fetchitems = fetchitems;
-+ r = index_fetch(imapd_mailbox, sequence, usinguid, &fetchargs,
-+ &fetchedsomething);
-+
-+ snprintf(mytime, sizeof(mytime), "%2.3f",
-+ (clock() - start) / (double) CLOCKS_PER_SEC);
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s (%s sec)\r\n", tag,
-+ error_message(r), mytime);
-+ } else if (fetchedsomething || usinguid) {
-+ prot_printf(imapd_out, "%s OK %s (%s sec)\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED), mytime);
-+ if(fetchargs.fetchitems & FETCH_SETSEEN) {
-+ index_check(imapd_mailbox,usinguid,1);
-+ }
-+ } else {
-+ /* normal FETCH, nothing came back */
-+ prot_printf(imapd_out, "%s NO %s (%s sec)\r\n", tag,
-+ error_message(IMAP_NO_NOSUCHMSG), mytime);
-+ }
-+
-+ freeargs:
-+ freestrlist(newfields);
-+ freestrlist(fetchargs.bodysections);
-+ freefieldlist(fetchargs.fsections);
-+ freestrlist(fetchargs.headers);
-+ freestrlist(fetchargs.headers_not);
-+}
-+
-+#undef PARSE_PARTIAL /* cleanup */
-+
-+/*
-+ * Perform a PARTIAL command
-+ */
-+void cmd_partial(const char *tag, const char *msgno, char *data,
-+ const char *start, const char *count)
-+{
-+ const char *pc;
-+ char *p;
-+ struct fetchargs fetchargs;
-+ char *section;
-+ int prev;
-+ int fetchedsomething;
-+
-+ memset(&fetchargs, 0, sizeof(struct fetchargs));
-+
-+ for (pc = msgno; *pc; pc++) {
-+ if (!isdigit((int) *pc)) break;
-+ }
-+ if (*pc || !*msgno) {
-+ prot_printf(imapd_out, "%s BAD Invalid message number\r\n", tag);
-+ return;
-+ }
-+
-+ lcase(data);
-+ if (!strcmp(data, "rfc822")) {
-+ fetchargs.fetchitems = FETCH_RFC822|FETCH_SETSEEN;
-+ }
-+ else if (!strcmp(data, "rfc822.header")) {
-+ fetchargs.fetchitems = FETCH_HEADER;
-+ }
-+ else if (!strcmp(data, "rfc822.peek")) {
-+ fetchargs.fetchitems = FETCH_RFC822;
-+ }
-+ else if (!strcmp(data, "rfc822.text")) {
-+ fetchargs.fetchitems = FETCH_TEXT|FETCH_SETSEEN;
-+ }
-+ else if (!strcmp(data, "rfc822.text.peek")) {
-+ fetchargs.fetchitems = FETCH_TEXT;
-+ }
-+ else if (!strncmp(data, "body[", 5) ||
-+ !strncmp(data, "body.peek[", 10)) {
-+ p = section = data + 5;
-+ if (!strncmp(p, "peek[", 5)) {
-+ p = section += 5;
-+ }
-+ else {
-+ fetchargs.fetchitems = FETCH_SETSEEN;
-+ }
-+ while (isdigit((int) *p) || *p == '.') {
-+ if (*p == '.' && (p == section || !isdigit((int) p[1]))) break;
-+ p++;
-+ }
-+ if (p == section || *p != ']' || p[1]) {
-+ prot_printf(imapd_out, "%s BAD Invalid body section\r\n", tag);
-+ freestrlist(fetchargs.bodysections);
-+ return;
-+ }
-+ *(p+1) = '\0'; /* Keep the closing bracket in place */
-+ appendstrlist(&fetchargs.bodysections, section);
-+ }
-+ else {
-+ prot_printf(imapd_out, "%s BAD Invalid Partial item\r\n", tag);
-+ freestrlist(fetchargs.bodysections);
-+ return;
-+ }
-+
-+ for (pc = start; *pc; pc++) {
-+ if (!isdigit((int) *pc)) break;
-+ prev = fetchargs.start_octet;
-+ fetchargs.start_octet = fetchargs.start_octet*10 + *pc - '0';
-+ if(fetchargs.start_octet < prev) {
-+ fetchargs.start_octet = 0;
-+ break;
-+ }
-+ }
-+ if (*pc || !fetchargs.start_octet) {
-+ prot_printf(imapd_out, "%s BAD Invalid starting octet\r\n", tag);
-+ freestrlist(fetchargs.bodysections);
-+ return;
-+ }
-+ fetchargs.start_octet--; /* Normalize to be 0-based */
-+
-+ prev = fetchargs.octet_count;
-+ for (pc = count; *pc; pc++) {
-+ if (!isdigit((int) *pc)) break;
-+ prev = fetchargs.octet_count;
-+ fetchargs.octet_count = fetchargs.octet_count*10 + *pc - '0';
-+ if(fetchargs.octet_count < prev) {
-+ prev = -1;
-+ break;
-+ }
-+ }
-+ if (*pc || !*count || prev == -1) {
-+ prot_printf(imapd_out, "%s BAD Invalid octet count\r\n", tag);
-+ freestrlist(fetchargs.bodysections);
-+ return;
-+ }
-+
-+ fetchargs.fetchitems |= FETCH_IS_PARTIAL;
-+
-+ index_fetch(imapd_mailbox, msgno, 0, &fetchargs, &fetchedsomething);
-+
-+ index_check(imapd_mailbox, 0,
-+ fetchedsomething && (fetchargs.fetchitems & FETCH_SETSEEN));
-+
-+ if (fetchedsomething) {
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ } else {
-+ prot_printf(imapd_out,
-+ "%s BAD Invalid sequence in PARTIAL command\r\n",
-+ tag);
-+ }
-+
-+ freestrlist(fetchargs.bodysections);
-+}
-+
-+/*
-+ * Parse and perform a STORE/UID STORE command
-+ * The command has been parsed up to and including
-+ * the FLAGS/+FLAGS/-FLAGS
-+ */
-+void cmd_store(char *tag, char *sequence, char *operation, int usinguid)
-+{
-+ char *cmd = usinguid ? "UID Store" : "Store";
-+ struct storeargs storeargs;
-+ static struct buf flagname;
-+ int len, c;
-+ char **flag = 0;
-+ int nflags = 0, flagalloc = 0;
-+ int flagsparsed = 0, inlist = 0;
-+ int r;
-+
-+ memset(&storeargs, 0, sizeof storeargs);
-+
-+ lcase(operation);
-+
-+ len = strlen(operation);
-+ if (len > 7 && !strcmp(operation+len-7, ".silent")) {
-+ storeargs.silent = 1;
-+ operation[len-7] = '\0';
-+ }
-+
-+ if (!strcmp(operation, "+flags")) {
-+ storeargs.operation = STORE_ADD;
-+ }
-+ else if (!strcmp(operation, "-flags")) {
-+ storeargs.operation = STORE_REMOVE;
-+ }
-+ else if (!strcmp(operation, "flags")) {
-+ storeargs.operation = STORE_REPLACE;
-+ }
-+ else {
-+ prot_printf(imapd_out, "%s BAD Invalid %s attribute\r\n", tag, cmd);
-+ eatline(imapd_in, ' ');
-+ return;
-+ }
-+
-+ for (;;) {
-+ c = getword(imapd_in, &flagname);
-+ if (c == '(' && !flagname.s[0] && !flagsparsed && !inlist) {
-+ inlist = 1;
-+ continue;
-+ }
-+
-+ if (!flagname.s[0]) break;
-+
-+ if (flagname.s[0] == '\\') {
-+ lcase(flagname.s);
-+ if (!strcmp(flagname.s, "\\seen")) {
-+ storeargs.seen = 1;
-+ }
-+ else if (!strcmp(flagname.s, "\\answered")) {
-+ storeargs.system_flags |= FLAG_ANSWERED;
-+ }
-+ else if (!strcmp(flagname.s, "\\flagged")) {
-+ storeargs.system_flags |= FLAG_FLAGGED;
-+ }
-+ else if (!strcmp(flagname.s, "\\deleted")) {
-+ storeargs.system_flags |= FLAG_DELETED;
-+ }
-+ else if (!strcmp(flagname.s, "\\draft")) {
-+ storeargs.system_flags |= FLAG_DRAFT;
-+ }
-+ else {
-+ prot_printf(imapd_out, "%s BAD Invalid system flag in %s command\r\n",
-+ tag, cmd);
-+ eatline(imapd_in, c);
-+ goto freeflags;
-+ }
-+ }
-+ else if (!imparse_isatom(flagname.s)) {
-+ prot_printf(imapd_out, "%s BAD Invalid flag name %s in %s command\r\n",
-+ tag, flagname.s, cmd);
-+ eatline(imapd_in, c);
-+ goto freeflags;
-+ }
-+ else {
-+ if (nflags == flagalloc) {
-+ flagalloc += FLAGGROW;
-+ flag = (char **)xrealloc((char *)flag,
-+ flagalloc*sizeof(char *));
-+ }
-+ flag[nflags] = xstrdup(flagname.s);
-+ nflags++;
-+ }
-+
-+ flagsparsed++;
-+ if (c != ' ') break;
-+ }
-+
-+ if (!inlist && !flagsparsed) {
-+ prot_printf(imapd_out, "%s BAD Missing required argument to %s\r\n", tag, cmd);
-+ eatline(imapd_in, c);
-+ return;
-+ }
-+ if (inlist && c == ')') {
-+ inlist = 0;
-+ c = prot_getc(imapd_in);
-+ }
-+ if (inlist) {
-+ prot_printf(imapd_out, "%s BAD Missing close parenthesis in %s\r\n", tag, cmd);
-+ eatline(imapd_in, c);
-+ goto freeflags;
-+ }
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') {
-+ prot_printf(imapd_out, "%s BAD Unexpected extra arguments to %s\r\n", tag, cmd);
-+ eatline(imapd_in, c);
-+ goto freeflags;
-+ }
-+
-+ r = index_store(imapd_mailbox, sequence, usinguid, &storeargs,
-+ flag, nflags);
-+
-+ if(storeargs.seen || storeargs.operation==STORE_REPLACE) {
-+ index_check(imapd_mailbox, usinguid, 1);
-+ } else if (usinguid) {
-+ index_check(imapd_mailbox, 1, 0);
-+ }
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ }
-+ else {
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ }
-+
-+ freeflags:
-+ while (nflags--) {
-+ free(flag[nflags]);
-+ }
-+ if (flag) free((char *)flag);
-+}
-+
-+void
-+cmd_search(tag, usinguid)
-+char *tag;
-+int usinguid;
-+{
-+ int c;
-+ int charset = 0;
-+ struct searchargs *searchargs;
-+ clock_t start = clock();
-+ char mytime[100];
-+ int n;
-+
-+ searchargs = (struct searchargs *)xzmalloc(sizeof(struct searchargs));
-+
-+ c = getsearchprogram(tag, searchargs, &charset, 1);
-+ if (c == EOF) {
-+ eatline(imapd_in, ' ');
-+ freesearchargs(searchargs);
-+ return;
-+ }
-+
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') {
-+ prot_printf(imapd_out, "%s BAD Unexpected extra arguments to Search\r\n", tag);
-+ eatline(imapd_in, c);
-+ freesearchargs(searchargs);
-+ return;
-+ }
-+
-+ if (charset == -1) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag,
-+ error_message(IMAP_UNRECOGNIZED_CHARSET));
-+ }
-+ else {
-+ n = index_search(imapd_mailbox, searchargs, usinguid);
-+ snprintf(mytime, sizeof(mytime), "%2.3f",
-+ (clock() - start) / (double) CLOCKS_PER_SEC);
-+ prot_printf(imapd_out, "%s OK %s (%d msgs in %s secs)\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED), n, mytime);
-+ }
-+
-+ freesearchargs(searchargs);
-+}
-+
-+/*
-+ * Perform a SORT/UID SORT command
-+ */
-+void
-+cmd_sort(tag, usinguid)
-+char *tag;
-+int usinguid;
-+{
-+ int c;
-+ struct sortcrit *sortcrit = NULL;
-+ static struct buf arg;
-+ int charset = 0;
-+ struct searchargs *searchargs;
-+ clock_t start = clock();
-+ char mytime[100];
-+ int n;
-+
-+ c = getsortcriteria(tag, &sortcrit);
-+ if (c == EOF) {
-+ eatline(imapd_in, ' ');
-+ freesortcrit(sortcrit);
-+ return;
-+ }
-+
-+ /* get charset */
-+ if (c != ' ') {
-+ prot_printf(imapd_out, "%s BAD Missing charset in Sort\r\n",
-+ tag);
-+ eatline(imapd_in, c);
-+ freesortcrit(sortcrit);
-+ return;
-+ }
-+
-+ c = getword(imapd_in, &arg);
-+ if (c != ' ') {
-+ prot_printf(imapd_out, "%s BAD Missing search criteria in Sort\r\n",
-+ tag);
-+ eatline(imapd_in, c);
-+ freesortcrit(sortcrit);
-+ return;
-+ }
-+ lcase(arg.s);
-+ charset = charset_lookupname(arg.s);
-+
-+ if (charset == -1) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag,
-+ error_message(IMAP_UNRECOGNIZED_CHARSET));
-+ eatline(imapd_in, c);
-+ freesortcrit(sortcrit);
-+ return;
-+ }
-+
-+ searchargs = (struct searchargs *)xzmalloc(sizeof(struct searchargs));
-+
-+ c = getsearchprogram(tag, searchargs, &charset, 0);
-+ if (c == EOF) {
-+ eatline(imapd_in, ' ');
-+ freesearchargs(searchargs);
-+ freesortcrit(sortcrit);
-+ return;
-+ }
-+
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') {
-+ prot_printf(imapd_out,
-+ "%s BAD Unexpected extra arguments to Sort\r\n", tag);
-+ eatline(imapd_in, c);
-+ freesearchargs(searchargs);
-+ freesortcrit(sortcrit);
-+ return;
-+ }
-+
-+ n = index_sort(imapd_mailbox, sortcrit, searchargs, usinguid);
-+ snprintf(mytime, sizeof(mytime), "%2.3f",
-+ (clock() - start) / (double) CLOCKS_PER_SEC);
-+ prot_printf(imapd_out, "%s OK %s (%d msgs in %s secs)\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED), n, mytime);
-+
-+ freesortcrit(sortcrit);
-+ freesearchargs(searchargs);
-+ return;
-+}
-+
-+/*
-+ * Perform a THREAD/UID THREAD command
-+ */
-+void
-+cmd_thread(tag, usinguid)
-+char *tag;
-+int usinguid;
-+{
-+ static struct buf arg;
-+ int c;
-+ int charset = 0;
-+ int alg;
-+ struct searchargs *searchargs;
-+ clock_t start = clock();
-+ char mytime[100];
-+ int n;
-+
-+ /* get algorithm */
-+ c = getword(imapd_in, &arg);
-+ if (c != ' ') {
-+ prot_printf(imapd_out, "%s BAD Missing algorithm in Thread\r\n", tag);
-+ eatline(imapd_in, c);
-+ return;
-+ }
-+
-+ if ((alg = find_thread_algorithm(arg.s)) == -1) {
-+ prot_printf(imapd_out, "%s BAD Invalid Thread algorithm %s\r\n",
-+ tag, arg.s);
-+ eatline(imapd_in, c);
-+ return;
-+ }
-+
-+ /* get charset */
-+ c = getword(imapd_in, &arg);
-+ if (c != ' ') {
-+ prot_printf(imapd_out, "%s BAD Missing charset in Thread\r\n",
-+ tag);
-+ eatline(imapd_in, c);
-+ return;
-+ }
-+ lcase(arg.s);
-+ charset = charset_lookupname(arg.s);
-+
-+ if (charset == -1) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag,
-+ error_message(IMAP_UNRECOGNIZED_CHARSET));
-+ eatline(imapd_in, c);
-+ return;
-+ }
-+
-+ searchargs = (struct searchargs *)xzmalloc(sizeof(struct searchargs));
-+
-+ c = getsearchprogram(tag, searchargs, &charset, 0);
-+ if (c == EOF) {
-+ eatline(imapd_in, ' ');
-+ freesearchargs(searchargs);
-+ return;
-+ }
-+
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') {
-+ prot_printf(imapd_out,
-+ "%s BAD Unexpected extra arguments to Thread\r\n", tag);
-+ eatline(imapd_in, c);
-+ freesearchargs(searchargs);
-+ return;
-+ }
-+
-+ n = index_thread(imapd_mailbox, alg, searchargs, usinguid);
-+ snprintf(mytime, sizeof(mytime), "%2.3f",
-+ (clock() - start) / (double) CLOCKS_PER_SEC);
-+ prot_printf(imapd_out, "%s OK %s (%d msgs in %s secs)\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED), n, mytime);
-+
-+ freesearchargs(searchargs);
-+ return;
-+}
-+
-+/*
-+ * Perform a COPY/UID COPY command
-+ */
-+void
-+cmd_copy(tag, sequence, name, usinguid)
-+char *tag;
-+char *sequence;
-+char *name;
-+int usinguid;
-+{
-+ int r;
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+ char *copyuid;
-+
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+ if (!r) {
-+ r = index_copy(imapd_mailbox, sequence, usinguid, mailboxname,
-+ ©uid);
-+ }
-+
-+ index_check(imapd_mailbox, usinguid, 0);
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s%s\r\n", tag,
-+ (r == IMAP_MAILBOX_NONEXISTENT &&
-+ mboxlist_createmailboxcheck(mailboxname, 0, 0,
-+ imapd_userisadmin,
-+ imapd_userid, imapd_authstate,
-+ (char **)0, (char **)0) == 0)
-+ ? "[TRYCREATE] " : "", error_message(r));
-+ }
-+ else {
-+ if (copyuid) {
-+ prot_printf(imapd_out, "%s OK [COPYUID %s] %s\r\n", tag,
-+ copyuid, error_message(IMAP_OK_COMPLETED));
-+ free(copyuid);
-+ }
-+ else if (usinguid) {
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ }
-+ else {
-+ /* normal COPY, message doesn't exist */
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag,
-+ error_message(IMAP_NO_NOSUCHMSG));
-+ }
-+ }
-+}
-+
-+/*
-+ * Perform an EXPUNGE command
-+ */
-+void
-+cmd_expunge(tag, sequence)
-+char *tag;
-+char *sequence;
-+{
-+ int r;
-+
-+ if (!(imapd_mailbox->myrights & ACL_DELETE)) r = IMAP_PERMISSION_DENIED;
-+ else if (sequence) {
-+ r = mailbox_expunge(imapd_mailbox, 1, index_expungeuidlist, sequence);
-+ }
-+ else {
-+ r = mailbox_expunge(imapd_mailbox, 1, (mailbox_decideproc_t *)0,
-+ (void *)0);
-+ }
-+
-+ index_check(imapd_mailbox, 0, 0);
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ }
-+ else {
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ }
-+}
-+
-+/*
-+ * Perform a CREATE command
-+ */
-+void
-+cmd_create(char *tag, char *name, char *partition, int localonly)
-+{
-+ int r = 0;
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+ int autocreatequota;
-+
-+ if (partition && !imapd_userisadmin) {
-+ r = IMAP_PERMISSION_DENIED;
-+ }
-+
-+ if (name[0] && name[strlen(name)-1] == imapd_namespace.hier_sep) {
-+ /* We don't care about trailing hierarchy delimiters. */
-+ name[strlen(name)-1] = '\0';
-+ }
-+
-+ if (!r) {
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+ }
-+
-+ if (!r) {
-+ /* xxx we do forced user creates on LOCALCREATE to facilitate
-+ * mailbox moves */
-+ r = mboxlist_createmailbox(mailboxname, 0, partition,
-+ imapd_userisadmin,
-+ imapd_userid, imapd_authstate,
-+ localonly, localonly, 0);
-+
-+ if (r == IMAP_PERMISSION_DENIED && !strcasecmp(name, "INBOX") &&
-+ (autocreatequota = config_getint(IMAPOPT_AUTOCREATEQUOTA))) {
-+
-+ /* Auto create */
-+ r = mboxlist_createmailbox(mailboxname, 0,
-+ partition, 1, imapd_userid,
-+ imapd_authstate, 0, 0, 0);
-+
-+ if (!r && autocreatequota > 0) {
-+ (void) mboxlist_setquota(mailboxname, autocreatequota, 0);
-+ }
-+ }
-+ }
-+
-+ if (imapd_mailbox) {
-+ index_check(imapd_mailbox, 0, 0);
-+ }
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ }
-+ else {
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ }
-+}
-+
-+/* Callback for use by cmd_delete */
-+static int delmbox(char *name,
-+ int matchlen __attribute__((unused)),
-+ int maycreate __attribute__((unused)),
-+ void *rock __attribute__((unused)))
-+{
-+ int r;
-+
-+ r = mboxlist_deletemailbox(name, imapd_userisadmin,
-+ imapd_userid, imapd_authstate,
-+ 0, 0, 0);
-+
-+ if(r) {
-+ prot_printf(imapd_out, "* NO delete %s: %s\r\n",
-+ name, error_message(r));
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * Perform a DELETE command
-+ */
-+void cmd_delete(char *tag, char *name, int localonly)
-+{
-+ int r;
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+ char *p;
-+ int domainlen = 0;
-+
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+
-+ if (!r) {
-+ if (config_virtdomains && (p = strchr(mailboxname, '!')))
-+ domainlen = p - mailboxname + 1;
-+
-+ r = mboxlist_deletemailbox(mailboxname, imapd_userisadmin,
-+ imapd_userid, imapd_authstate, 1,
-+ localonly, 0);
-+ }
-+
-+ /* was it a top-level user mailbox? */
-+ /* localonly deletes are only per-mailbox */
-+ if (!r && !localonly &&
-+ !strncmp(mailboxname+domainlen, "user.", 5) &&
-+ !strchr(mailboxname+domainlen+5, '.')) {
-+ int mailboxname_len = strlen(mailboxname);
-+
-+ /* If we aren't too close to MAX_MAILBOX_NAME, append .* */
-+ p = mailboxname + mailboxname_len; /* end of mailboxname */
-+ if (mailboxname_len < sizeof(mailboxname) - 3) {
-+ strcpy(p, ".*");
-+ }
-+
-+ /* build a list of mailboxes - we're using internal names here */
-+ mboxlist_findall(NULL, mailboxname, imapd_userisadmin, imapd_userid,
-+ imapd_authstate, delmbox, NULL);
-+
-+ /* take care of deleting ACLs, subscriptions, seen state and quotas */
-+ *p = '\0'; /* clip off pattern */
-+ if ((!domainlen) ||
-+ (domainlen+1 < (sizeof(mailboxname) - mailboxname_len))) {
-+ if (domainlen) {
-+ /* fully qualify the userid */
-+ snprintf(p, (sizeof(mailboxname) - mailboxname_len), "@%.*s",
-+ domainlen-1, mailboxname);
-+ }
-+ user_deletedata(mailboxname+domainlen+5, imapd_userid,
-+ imapd_authstate, 1);
-+ }
-+ }
-+
-+ if (imapd_mailbox) {
-+ index_check(imapd_mailbox, 0, 0);
-+ }
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ }
-+ else {
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ }
-+}
-+
-+struct renrock
-+{
-+ int ol;
-+ int nl;
-+ int rename_user;
-+ char *olduser, *newuser;
-+ char *acl_olduser, *acl_newuser;
-+ char *newmailboxname;
-+ char *partition;
-+};
-+
-+/* Callback for use by cmd_rename */
-+static int renmbox(char *name,
-+ int matchlen __attribute__((unused)),
-+ int maycreate __attribute__((unused)),
-+ void *rock)
-+{
-+ char oldextname[MAX_MAILBOX_NAME+1];
-+ char newextname[MAX_MAILBOX_NAME+1];
-+ struct renrock *text = (struct renrock *)rock;
-+ int r;
-+
-+ if((text->nl + strlen(name + text->ol)) > MAX_MAILBOX_NAME)
-+ return 0;
-+
-+ strcpy(text->newmailboxname + text->nl, name + text->ol);
-+
-+ r = mboxlist_renamemailbox(name, text->newmailboxname,
-+ text->partition,
-+ 1, imapd_userid, imapd_authstate);
-+
-+ (*imapd_namespace.mboxname_toexternal)(&imapd_namespace,
-+ name,
-+ imapd_userid, oldextname);
-+ (*imapd_namespace.mboxname_toexternal)(&imapd_namespace,
-+ text->newmailboxname,
-+ imapd_userid, newextname);
-+
-+ if(r) {
-+ prot_printf(imapd_out, "* NO rename %s %s: %s\r\n",
-+ oldextname, newextname, error_message(r));
-+ if (RENAME_STOP_ON_ERROR) return r;
-+ } else {
-+ /* If we're renaming a user, change quotaroot and ACL */
-+ if (text->rename_user) {
-+ user_copyquotaroot(name, text->newmailboxname);
-+ user_renameacl(text->newmailboxname,
-+ text->acl_olduser, text->acl_newuser);
-+ }
-+
-+ /* Rename mailbox annotations */
-+ annotatemore_rename(name, text->newmailboxname,
-+ text->rename_user ? text->olduser : NULL,
-+ text->newuser);
-+
-+ prot_printf(imapd_out, "* OK rename %s %s\r\n",
-+ oldextname, newextname);
-+ }
-+
-+ prot_flush(imapd_out);
-+
-+ return 0;
-+}
-+
-+/*
-+ * Perform a RENAME command
-+ */
-+void cmd_rename(const char *tag,
-+ char *oldname, char *newname, char *partition)
-+{
-+ int r = 0;
-+ char oldmailboxname[MAX_MAILBOX_NAME+3];
-+ char newmailboxname[MAX_MAILBOX_NAME+2];
-+ char oldextname[MAX_MAILBOX_NAME+1];
-+ char newextname[MAX_MAILBOX_NAME+1];
-+ int omlen, nmlen;
-+ char *p;
-+ int recursive_rename = 1;
-+ int rename_user = 0;
-+ char olduser[128], newuser[128];
-+ char acl_olduser[128], acl_newuser[128];
-+
-+ /* canonicalize names */
-+ if (partition && !imapd_userisadmin) {
-+ r = IMAP_PERMISSION_DENIED;
-+ }
-+
-+ if (!r)
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, oldname,
-+ imapd_userid, oldmailboxname);
-+ if (!r)
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, newname,
-+ imapd_userid, newmailboxname);
-+
-+ /* if this is my inbox, don't do recursive renames */
-+ if (!strcasecmp(oldname, "inbox")) {
-+ recursive_rename = 0;
-+ }
-+ /* check if we're an admin renaming a user */
-+ else if (config_getswitch(IMAPOPT_ALLOWUSERMOVES) &&
-+ mboxname_isusermailbox(oldmailboxname, 1) &&
-+ mboxname_isusermailbox(newmailboxname, 1) &&
-+ strcmp(oldmailboxname, newmailboxname) && /* different user */
-+ imapd_userisadmin) {
-+ rename_user = 1;
-+ }
-+
-+ /* if we're renaming something inside of something else,
-+ don't recursively rename stuff */
-+ omlen = strlen(oldmailboxname);
-+ nmlen = strlen(newmailboxname);
-+ if (omlen < nmlen) {
-+ if (!strncmp(oldmailboxname, newmailboxname, omlen) &&
-+ newmailboxname[omlen] == '.') {
-+ recursive_rename = 0;
-+ }
-+ } else {
-+ if (!strncmp(oldmailboxname, newmailboxname, nmlen) &&
-+ oldmailboxname[nmlen] == '.') {
-+ recursive_rename = 0;
-+ }
-+ }
-+
-+ /* verify that the mailbox doesn't have a wildcard in it */
-+ for (p = oldmailboxname; !r && *p; p++) {
-+ if (*p == '*' || *p == '%') r = IMAP_MAILBOX_BADNAME;
-+ }
-+
-+ /* attempt to rename the base mailbox */
-+ if (!r) {
-+ r = mboxlist_renamemailbox(oldmailboxname, newmailboxname, partition,
-+ imapd_userisadmin,
-+ imapd_userid, imapd_authstate);
-+ }
-+
-+ /* If we're renaming a user, take care of changing quotaroot, ACL,
-+ seen state, subscriptions and sieve scripts */
-+ if (!r && rename_user) {
-+ char *domain;
-+
-+ /* create canonified userids */
-+
-+ domain = strchr(oldmailboxname, '!');
-+ strcpy(olduser, domain ? domain+6 : oldmailboxname+5);
-+ if (domain)
-+ sprintf(olduser+strlen(olduser), "@%.*s",
-+ domain - oldmailboxname, oldmailboxname);
-+ strcpy(acl_olduser, olduser);
-+
-+ /* Translate any separators in source old userid (for ACLs) */
-+ mboxname_hiersep_toexternal(&imapd_namespace, acl_olduser,
-+ config_virtdomains ?
-+ strcspn(acl_olduser, "@") : 0);
-+
-+ domain = strchr(newmailboxname, '!');
-+ strcpy(newuser, domain ? domain+6 : newmailboxname+5);
-+ if (domain)
-+ sprintf(newuser+strlen(newuser), "@%.*s",
-+ domain - newmailboxname, newmailboxname);
-+ strcpy(acl_newuser, newuser);
-+
-+ /* Translate any separators in destination new userid (for ACLs) */
-+ mboxname_hiersep_toexternal(&imapd_namespace, acl_newuser,
-+ config_virtdomains ?
-+ strcspn(acl_newuser, "@") : 0);
-+
-+ user_copyquotaroot(oldmailboxname, newmailboxname);
-+ user_renameacl(newmailboxname, acl_olduser, acl_newuser);
-+ user_renamedata(olduser, newuser, imapd_userid, imapd_authstate);
-+
-+ /* XXX report status/progress of meta-data */
-+ }
-+
-+ if (!r) {
-+ /* Rename mailbox annotations */
-+ annotatemore_rename(oldmailboxname, newmailboxname,
-+ rename_user ? olduser : NULL,
-+ newuser);
-+ }
-+
-+ /* rename all mailboxes matching this */
-+ if (!r && recursive_rename) {
-+ struct renrock rock;
-+ int ol = omlen + 1;
-+ int nl = nmlen + 1;
-+
-+ (*imapd_namespace.mboxname_toexternal)(&imapd_namespace,
-+ oldmailboxname,
-+ imapd_userid, oldextname);
-+ (*imapd_namespace.mboxname_toexternal)(&imapd_namespace,
-+ newmailboxname,
-+ imapd_userid, newextname);
-+
-+ prot_printf(imapd_out, "* OK rename %s %s\r\n",
-+ oldextname, newextname);
-+ prot_flush(imapd_out);
-+
-+ strcat(oldmailboxname, ".*");
-+ strcat(newmailboxname, ".");
-+
-+ /* setup the rock */
-+ rock.newmailboxname = newmailboxname;
-+ rock.ol = ol;
-+ rock.nl = nl;
-+ rock.olduser = olduser;
-+ rock.newuser = newuser;
-+ rock.acl_olduser = acl_olduser;
-+ rock.acl_newuser = acl_newuser;
-+ rock.partition = partition;
-+ rock.rename_user = rename_user;
-+
-+ /* add submailboxes; we pretend we're an admin since we successfully
-+ renamed the parent - we're using internal names here */
-+ r = mboxlist_findall(NULL, oldmailboxname, 1, imapd_userid,
-+ imapd_authstate, renmbox, &rock);
-+ }
-+
-+ /* take care of deleting old ACLs, subscriptions, seen state and quotas */
-+ if (!r && rename_user)
-+ user_deletedata(olduser, imapd_userid, imapd_authstate, 1);
-+
-+ if (imapd_mailbox) {
-+ index_check(imapd_mailbox, 0, 0);
-+ }
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ } else {
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ }
-+}
-+
-+/*
-+ * Perform a RECONSTRUCT command
-+ */
-+void
-+cmd_reconstruct(const char *tag, const char *name, int recursive)
-+{
-+ int r = 0;
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+ char quotaroot[MAX_MAILBOX_NAME+1];
-+ struct mailbox mailbox;
-+
-+ /* administrators only please */
-+ if (!imapd_userisadmin) {
-+ r = IMAP_PERMISSION_DENIED;
-+ }
-+
-+ if (!r) {
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+ }
-+
-+ if (!r) {
-+ r = mlookup(tag, name, mailboxname, NULL, NULL, NULL, NULL, NULL);
-+ }
-+ if (r == IMAP_MAILBOX_MOVED) return;
-+
-+ if (!r) {
-+ int pid;
-+
-+ /* Reconstruct it */
-+
-+ pid = fork();
-+ if(pid == -1) {
-+ r = IMAP_SYS_ERROR;
-+ } else if(pid == 0) {
-+ char buf[4096];
-+ int ret;
-+
-+ /* Child - exec reconstruct*/
-+ syslog(LOG_NOTICE, "Reconstructing '%s' (%s) for user '%s'",
-+ mailboxname, recursive ? "recursive" : "not recursive",
-+ imapd_userid);
-+
-+ fclose(stdin);
-+ fclose(stdout);
-+ fclose(stderr);
-+
-+ ret = snprintf(buf, sizeof(buf), "%s/reconstruct", SERVICE_PATH);
-+ if(ret < 0 || ret >= sizeof(buf)) {
-+ /* in child, so fatailing won't disconnect our user */
-+ fatal("reconstruct buffer not sufficiently big", EC_CONFIG);
-+ }
-+
-+ if(recursive) {
-+ execl(buf, buf, "-C", config_filename, "-r", "-f",
-+ mailboxname, NULL);
-+ } else {
-+ execl(buf, buf, "-C", config_filename, mailboxname, NULL);
-+ }
-+
-+ /* if we are here, we have a problem */
-+ exit(-1);
-+ } else {
-+ int status;
-+
-+ /* Parent, wait on child */
-+ if(waitpid(pid, &status, 0) < 0) r = IMAP_SYS_ERROR;
-+
-+ /* Did we fail? */
-+ if(WEXITSTATUS(status) != 0) r = IMAP_SYS_ERROR;
-+ }
-+ }
-+
-+ /* Still in parent, need to re-quota the mailbox*/
-+
-+ /* Find its quota root */
-+ if (!r) {
-+ r = mailbox_open_header(mailboxname, imapd_authstate, &mailbox);
-+ }
-+
-+ if(!r) {
-+ if(mailbox.quota.root) {
-+ strcpy(quotaroot, mailbox.quota.root);
-+ } else {
-+ strcpy(quotaroot, mailboxname);
-+ }
-+ mailbox_close(&mailbox);
-+ }
-+
-+ /* Run quota -f */
-+ if (!r) {
-+ int pid;
-+
-+ pid = fork();
-+ if(pid == -1) {
-+ r = IMAP_SYS_ERROR;
-+ } else if(pid == 0) {
-+ char buf[4096];
-+ int ret;
-+
-+ /* Child - exec reconstruct*/
-+ syslog(LOG_NOTICE,
-+ "Regenerating quota roots starting with '%s' for user '%s'",
-+ mailboxname, imapd_userid);
-+
-+ fclose(stdin);
-+ fclose(stdout);
-+ fclose(stderr);
-+
-+ ret = snprintf(buf, sizeof(buf), "%s/quota", SERVICE_PATH);
-+ if(ret < 0 || ret >= sizeof(buf)) {
-+ /* in child, so fatailing won't disconnect our user */
-+ fatal("quota buffer not sufficiently big", EC_CONFIG);
-+ }
-+
-+ execl(buf, buf, "-C", config_filename, "-f", quotaroot, NULL);
-+
-+ /* if we are here, we have a problem */
-+ exit(-1);
-+ } else {
-+ int status;
-+
-+ /* Parent, wait on child */
-+ if(waitpid(pid, &status, 0) < 0) r = IMAP_SYS_ERROR;
-+
-+ /* Did we fail? */
-+ if(WEXITSTATUS(status) != 0) r = IMAP_SYS_ERROR;
-+ }
-+ }
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ } else {
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ }
-+}
-+
-+/*
-+ * Perform a FIND command
-+ */
-+void
-+cmd_find(tag, namespace, pattern)
-+char *tag;
-+char *namespace;
-+char *pattern;
-+{
-+ char *p;
-+ lcase(namespace);
-+
-+ for (p = pattern; *p; p++) {
-+ if (*p == '%') *p = '?';
-+ }
-+
-+ /* Translate any separators in pattern */
-+ mboxname_hiersep_tointernal(&imapd_namespace, pattern,
-+ config_virtdomains ?
-+ strcspn(pattern, "@") : 0);
-+
-+ if (!strcasecmp(namespace, "mailboxes")) {
-+ int force = config_getswitch(IMAPOPT_ALLOWALLSUBSCRIBE);
-+
-+ (*imapd_namespace.mboxlist_findsub)(&imapd_namespace, pattern,
-+ imapd_userisadmin, imapd_userid,
-+ imapd_authstate, mailboxdata,
-+ NULL, force);
-+ }
-+ else if (!strcasecmp(namespace, "all.mailboxes")) {
-+ (*imapd_namespace.mboxlist_findall)(&imapd_namespace, pattern,
-+ imapd_userisadmin, imapd_userid,
-+ imapd_authstate, mailboxdata, NULL);
-+ }
-+ else if (!strcasecmp(namespace, "bboards")
-+ || !strcasecmp(namespace, "all.bboards")) {
-+ ;
-+ }
-+ else {
-+ prot_printf(imapd_out, "%s BAD Invalid FIND subcommand\r\n", tag);
-+ return;
-+ }
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+}
-+
-+static int mstringdatacalls;
-+
-+/*
-+ * Perform a LIST or LSUB command
-+ */
-+void cmd_list(char *tag, int listopts, char *reference, char *pattern)
-+{
-+ char *buf = NULL;
-+ int patlen = 0;
-+ int reflen = 0;
-+ static int ignorereference = 0;
-+ clock_t start = clock();
-+ char mytime[100];
-+ int (*findall)(struct namespace *namespace,
-+ const char *pattern, int isadmin, char *userid,
-+ struct auth_state *auth_state, int (*proc)(),
-+ void *rock);
-+ int (*findsub)(struct namespace *namespace,
-+ const char *pattern, int isadmin, char *userid,
-+ struct auth_state *auth_state, int (*proc)(),
-+ void *rock, int force);
-+
-+ /* Ignore the reference argument?
-+ (the behavior in 1.5.10 & older) */
-+ if (ignorereference == 0) {
-+ ignorereference = config_getswitch(IMAPOPT_IGNOREREFERENCE);
-+ }
-+
-+ /* Reset state in mstringdata */
-+ mstringdata(NULL, NULL, 0, 0, 0);
-+
-+ if (!pattern[0] && !(listopts & LIST_LSUB)) {
-+ /* Special case: query top-level hierarchy separator */
-+ prot_printf(imapd_out, "* LIST (\\Noselect) \"%c\" \"\"\r\n",
-+ imapd_namespace.hier_sep);
-+ } else {
-+ /* Do we need to concatenate fields? */
-+ if (!ignorereference || pattern[0] == imapd_namespace.hier_sep) {
-+ /* Either
-+ * - name begins with dot
-+ * - we're configured to honor the reference argument */
-+
-+ /* Allocate a buffer, figure out how to stick the arguments
-+ together, do it, then do that instead of using pattern. */
-+ patlen = strlen(pattern);
-+ reflen = strlen(reference);
-+
-+ buf = xmalloc(patlen + reflen + 1);
-+ buf[0] = '\0';
-+
-+ if (*reference) {
-+ /* check for LIST A. .B, change to LIST "" A.B */
-+ if (reference[reflen-1] == imapd_namespace.hier_sep &&
-+ pattern[0] == imapd_namespace.hier_sep) {
-+ reference[--reflen] = '\0';
-+ }
-+ strcpy(buf, reference);
-+ }
-+ strcat(buf, pattern);
-+ pattern = buf;
-+ }
-+
-+ /* Translate any separators in pattern */
-+ mboxname_hiersep_tointernal(&imapd_namespace, pattern,
-+ config_virtdomains ?
-+ strcspn(pattern, "@") : 0);
-+
-+ /* Check to see if we should only list the personal namespace */
-+ if (!strcmp(pattern, "*")
-+ && config_getswitch(IMAPOPT_FOOLSTUPIDCLIENTS)) {
-+ if (buf) free(buf);
-+ buf = xstrdup("INBOX*");
-+ pattern = buf;
-+ findsub = mboxlist_findsub;
-+ findall = mboxlist_findall;
-+ }
-+ else {
-+ findsub = imapd_namespace.mboxlist_findsub;
-+ findall = imapd_namespace.mboxlist_findall;
-+ }
-+
-+ if (listopts & (LIST_LSUB | LIST_SUBSCRIBED)) {
-+ int force = config_getswitch(IMAPOPT_ALLOWALLSUBSCRIBE);
-+
-+ (*findsub)(&imapd_namespace, pattern,
-+ imapd_userisadmin, imapd_userid, imapd_authstate,
-+ listdata, &listopts, force);
-+ }
-+ else {
-+ (*findall)(&imapd_namespace, pattern,
-+ imapd_userisadmin, imapd_userid, imapd_authstate,
-+ listdata, &listopts);
-+ }
-+
-+ listdata((char *)0, 0, 0, &listopts);
-+
-+ if (buf) free(buf);
-+ }
-+ snprintf(mytime, sizeof(mytime), "%2.3f",
-+ (clock() - start) / (double) CLOCKS_PER_SEC);
-+ prot_printf(imapd_out, "%s OK %s (%s secs %d calls)\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED), mytime, mstringdatacalls);
-+}
-+
-+/*
-+ * Perform a SUBSCRIBE (add is nonzero) or
-+ * UNSUBSCRIBE (add is zero) command
-+ */
-+void cmd_changesub(char *tag, char *namespace,
-+ char *name, int add)
-+{
-+ int r;
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+ int force = config_getswitch(IMAPOPT_ALLOWALLSUBSCRIBE);
-+
-+ if (namespace) lcase(namespace);
-+ if (!namespace || !strcmp(namespace, "mailbox")) {
-+ int len = strlen(name);
-+ if (force && imapd_namespace.isalt &&
-+ (((len == strlen(imapd_namespace.prefix[NAMESPACE_USER]) - 1) &&
-+ !strncmp(name, imapd_namespace.prefix[NAMESPACE_USER], len)) ||
-+ ((len == strlen(imapd_namespace.prefix[NAMESPACE_SHARED]) - 1) &&
-+ !strncmp(name, imapd_namespace.prefix[NAMESPACE_SHARED], len)))) {
-+ r = 0;
-+ }
-+ else {
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+ if (!r) {
-+ r = mboxlist_changesub(mailboxname, imapd_userid,
-+ imapd_authstate, add, force);
-+ }
-+ }
-+ }
-+ else if (!strcmp(namespace, "bboard")) {
-+ r = add ? IMAP_MAILBOX_NONEXISTENT : 0;
-+ }
-+ else {
-+ prot_printf(imapd_out, "%s BAD Invalid %s subcommand\r\n", tag,
-+ add ? "Subscribe" : "Unsubscribe");
-+ return;
-+ }
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s: %s\r\n", tag,
-+ add ? "Subscribe" : "Unsubscribe", error_message(r));
-+ }
-+ else {
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ }
-+}
-+
-+/*
-+ * Perform a GETACL command
-+ */
-+void cmd_getacl(const char *tag, const char *name)
-+{
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+ int r, access;
-+ char *acl;
-+ char *rights, *nextid;
-+
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+
-+ if (!r) {
-+ r = mlookup(tag, name, mailboxname, NULL, NULL, NULL, &acl, NULL);
-+ }
-+ if (r == IMAP_MAILBOX_MOVED) return;
-+
-+ if (!r) {
-+ access = cyrus_acl_myrights(imapd_authstate, acl);
-+
-+ if (!(access & (ACL_READ|ACL_ADMIN)) &&
-+ !imapd_userisadmin &&
-+ !mboxname_userownsmailbox(imapd_userid, mailboxname)) {
-+ r = (access&ACL_LOOKUP) ?
-+ IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
-+ }
-+ }
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ return;
-+ }
-+
-+ prot_printf(imapd_out, "* ACL ");
-+ printastring(name);
-+
-+ while (acl) {
-+ rights = strchr(acl, '\t');
-+ if (!rights) break;
-+ *rights++ = '\0';
-+
-+ nextid = strchr(rights, '\t');
-+ if (!nextid) break;
-+ *nextid++ = '\0';
-+
-+ prot_printf(imapd_out, " ");
-+ printastring(acl);
-+ prot_printf(imapd_out, " ");
-+ printastring(rights);
-+ acl = nextid;
-+ }
-+ prot_printf(imapd_out, "\r\n");
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+}
-+
-+/*
-+ * Perform a LISTRIGHTS command
-+ */
-+void
-+cmd_listrights(tag, name, identifier)
-+char *tag;
-+char *name;
-+char *identifier;
-+{
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+ int r, rights;
-+ char *acl;
-+
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+
-+ if (!r) {
-+ r = mlookup(tag, name, mailboxname, NULL, NULL, NULL, &acl, NULL);
-+ }
-+ if (r == IMAP_MAILBOX_MOVED) return;
-+
-+ if (!r) {
-+ rights = cyrus_acl_myrights(imapd_authstate, acl);
-+
-+ if (!rights && !imapd_userisadmin &&
-+ !mboxname_userownsmailbox(imapd_userid, mailboxname)) {
-+ r = IMAP_MAILBOX_NONEXISTENT;
-+ }
-+ }
-+
-+ if (!r) {
-+ struct auth_state *authstate = auth_newstate(identifier);
-+ char *canon_identifier;
-+ int canonidlen = 0;
-+ int implicit;
-+ char rightsdesc[100], optional[33];
-+
-+ if (global_authisa(authstate, IMAPOPT_ADMINS))
-+ canon_identifier = identifier; /* don't canonify global admins */
-+ else
-+ canon_identifier = canonify_userid(identifier, imapd_userid, NULL);
-+ auth_freestate(authstate);
-+
-+ if (canon_identifier) canonidlen = strlen(canon_identifier);
-+
-+ if (!canon_identifier) {
-+ implicit = 0;
-+ }
-+ else if (mboxname_userownsmailbox(canon_identifier, mailboxname)) {
-+ /* identifier's personal mailbox */
-+ implicit = config_implicitrights;
-+ }
-+ else if (mboxname_isusermailbox(mailboxname, 1)) {
-+ /* anyone can post to an INBOX */
-+ implicit = ACL_POST;
-+ }
-+ else {
-+ implicit = 0;
-+ }
-+
-+ /* calculate optional rights */
-+ cyrus_acl_masktostr(implicit ^ (canon_identifier ? ACL_FULL : 0),
-+ optional);
-+
-+ /* build the rights string */
-+ if (implicit) {
-+ cyrus_acl_masktostr(implicit, rightsdesc);
-+ }
-+ else {
-+ strcpy(rightsdesc, "\"\"");
-+ }
-+
-+ if (*optional) {
-+ int i, n = strlen(optional);
-+ char *p = rightsdesc + strlen(rightsdesc);
-+
-+ for (i = 0; i < n; i++) {
-+ *p++ = ' ';
-+ *p++ = optional[i];
-+ }
-+ *p = '\0';
-+ }
-+
-+ prot_printf(imapd_out, "* LISTRIGHTS ");
-+ printastring(name);
-+ prot_putc(' ', imapd_out);
-+ printastring(identifier);
-+ prot_printf(imapd_out, " %s", rightsdesc);
-+
-+ prot_printf(imapd_out, "\r\n%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ return;
-+ }
-+
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+}
-+
-+/*
-+ * Perform a MYRIGHTS command
-+ */
-+void cmd_myrights(const char *tag, const char *name)
-+{
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+ int r, rights = 0;
-+ char *acl;
-+ char str[ACL_MAXSTR];
-+
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+
-+ if (!r) {
-+ r = mlookup(tag, name, mailboxname, NULL, NULL, NULL, &acl, NULL);
-+ }
-+ if (r == IMAP_MAILBOX_MOVED) return;
-+
-+ if (!r) {
-+ rights = cyrus_acl_myrights(imapd_authstate, acl);
-+
-+ /* Add in implicit rights */
-+ if (imapd_userisadmin) {
-+ rights |= ACL_LOOKUP|ACL_ADMIN;
-+ }
-+ else if (mboxname_userownsmailbox(imapd_userid, mailboxname)) {
-+ rights |= config_implicitrights;
-+ }
-+
-+ if (!rights) {
-+ r = IMAP_MAILBOX_NONEXISTENT;
-+ }
-+ }
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ return;
-+ }
-+
-+ prot_printf(imapd_out, "* MYRIGHTS ");
-+ printastring(name);
-+ prot_printf(imapd_out, " ");
-+ printastring(cyrus_acl_masktostr(rights, str));
-+ prot_printf(imapd_out, "\r\n%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+}
-+
-+/*
-+ * Perform a SETACL command
-+ */
-+void cmd_setacl(const char *tag, const char *name,
-+ const char *identifier, const char *rights)
-+{
-+ int r;
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+
-+ /* is it remote? */
-+ if (!r) {
-+ r = mlookup(tag, name, mailboxname, NULL, NULL, NULL, NULL, NULL);
-+ }
-+ if (r == IMAP_MAILBOX_MOVED) return;
-+
-+ if (!r) {
-+ r = mboxlist_setacl(mailboxname, identifier, rights,
-+ imapd_userisadmin, imapd_userid, imapd_authstate);
-+ }
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ return;
-+ }
-+
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+}
-+
-+/*
-+ * Perform a GETQUOTA command
-+ */
-+void
-+cmd_getquota(const char *tag, const char *name)
-+{
-+ int r;
-+ struct quota quota;
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+
-+ if (!imapd_userisadmin) r = IMAP_PERMISSION_DENIED;
-+ else {
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+ if (!r) {
-+ quota.root = mailboxname;
-+ r = quota_read("a, NULL, 0);
-+ }
-+ }
-+
-+ if (!r) {
-+ prot_printf(imapd_out, "* QUOTA ");
-+ printastring(name);
-+ prot_printf(imapd_out, " (");
-+ if (quota.limit >= 0) {
-+ prot_printf(imapd_out, "STORAGE %lu %d",
-+ quota.used/QUOTA_UNITS, quota.limit);
-+ }
-+ prot_printf(imapd_out, ")\r\n");
-+ }
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ return;
-+ }
-+
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+}
-+
-+
-+/*
-+ * Perform a GETQUOTAROOT command
-+ */
-+void
-+cmd_getquotaroot(const char *tag, const char *name)
-+{
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+ struct mailbox mailbox;
-+ int r;
-+ int doclose = 0;
-+
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+
-+ if (!r) {
-+ r = mlookup(tag, name, mailboxname, NULL, NULL, NULL, NULL, NULL);
-+ }
-+ if (r == IMAP_MAILBOX_MOVED) return;
-+
-+ if (!r) {
-+ r = mailbox_open_header(mailboxname, imapd_authstate, &mailbox);
-+ }
-+
-+ if (!r) {
-+ doclose = 1;
-+ if (!imapd_userisadmin && !(mailbox.myrights & ACL_READ)) {
-+ r = (mailbox.myrights & ACL_LOOKUP) ?
-+ IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
-+ }
-+ }
-+
-+ if (!r) {
-+ prot_printf(imapd_out, "* QUOTAROOT ");
-+ printastring(name);
-+ if (mailbox.quota.root) {
-+ (*imapd_namespace.mboxname_toexternal)(&imapd_namespace,
-+ mailbox.quota.root,
-+ imapd_userid, mailboxname);
-+ prot_printf(imapd_out, " ");
-+ printastring(mailboxname);
-+ r = quota_read(&mailbox.quota, NULL, 0);
-+ if (!r) {
-+ prot_printf(imapd_out, "\r\n* QUOTA ");
-+ printastring(mailboxname);
-+ prot_printf(imapd_out, " (");
-+ if (mailbox.quota.limit >= 0) {
-+ prot_printf(imapd_out, "STORAGE %lu %d",
-+ mailbox.quota.used/QUOTA_UNITS,
-+ mailbox.quota.limit);
-+ }
-+ prot_putc(')', imapd_out);
-+ }
-+ }
-+ prot_printf(imapd_out, "\r\n");
-+ }
-+
-+ if (doclose) mailbox_close(&mailbox);
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ return;
-+ }
-+
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+}
-+
-+/*
-+ * Parse and perform a SETQUOTA command
-+ * The command has been parsed up to the resource list
-+ */
-+void
-+cmd_setquota(const char *tag, const char *quotaroot)
-+{
-+ int newquota = -1;
-+ int badresource = 0;
-+ int c;
-+ int force = 0;
-+ static struct buf arg;
-+ char *p;
-+ int r;
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+
-+ c = prot_getc(imapd_in);
-+ if (c != '(') goto badlist;
-+
-+ c = getword(imapd_in, &arg);
-+ if (c != ')' || arg.s[0] != '\0') {
-+ for (;;) {
-+ if (c != ' ') goto badlist;
-+ if (strcasecmp(arg.s, "storage") != 0) badresource = 1;
-+ c = getword(imapd_in, &arg);
-+ if (c != ' ' && c != ')') goto badlist;
-+ if (arg.s[0] == '\0') goto badlist;
-+ newquota = 0;
-+ for (p = arg.s; *p; p++) {
-+ if (!isdigit((int) *p)) goto badlist;
-+ newquota = newquota * 10 + *p - '0';
-+ if (newquota < 0) goto badlist; /* overflow */
-+ }
-+ if (c == ')') break;
-+ }
-+ }
-+ c = prot_getc(imapd_in);
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') {
-+ prot_printf(imapd_out, "%s BAD Unexpected extra arguments to SETQUOTA\r\n", tag);
-+ eatline(imapd_in, c);
-+ return;
-+ }
-+
-+ if (badresource) r = IMAP_UNSUPPORTED_QUOTA;
-+ else if (!imapd_userisadmin && !imapd_userisproxyadmin) {
-+ /* need to allow proxies so that mailbox moves can set initial quota
-+ * roots */
-+ r = IMAP_PERMISSION_DENIED;
-+ } else {
-+ /* are we forcing the creation of a quotaroot by having a leading +? */
-+ if(quotaroot[0] == '+') {
-+ force = 1;
-+ quotaroot++;
-+ }
-+
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, quotaroot,
-+ imapd_userid, mailboxname);
-+
-+ if (!r) {
-+ r = mboxlist_setquota(mailboxname, newquota, force);
-+ }
-+ }
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ return;
-+ }
-+
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ return;
-+
-+ badlist:
-+ prot_printf(imapd_out, "%s BAD Invalid quota list in Setquota\r\n", tag);
-+ eatline(imapd_in, c);
-+}
-+
-+#ifdef HAVE_SSL
-+/*
-+ * this implements the STARTTLS command, as described in RFC 2595.
-+ * one caveat: it assumes that no external layer is currently present.
-+ * if a client executes this command, information about the external
-+ * layer that was passed on the command line is disgarded. this should
-+ * be fixed.
-+ */
-+/* imaps - whether this is an imaps transaction or not */
-+void cmd_starttls(char *tag, int imaps)
-+{
-+ int result;
-+ int *layerp;
-+
-+ char *auth_id;
-+ sasl_ssf_t ssf;
-+
-+ /* SASL and openssl have different ideas about whether ssf is signed */
-+ layerp = (int *) &ssf;
-+
-+ if (imapd_starttls_done == 1)
-+ {
-+ prot_printf(imapd_out, "%s NO TLS already active\r\n", tag);
-+ return;
-+ }
-+
-+ result=tls_init_serverengine("imap",
-+ 5, /* depth to verify */
-+ !imaps, /* can client auth? */
-+ !imaps); /* TLS only? */
-+
-+ if (result == -1) {
-+
-+ syslog(LOG_ERR, "error initializing TLS");
-+
-+ if (imaps == 0) {
-+ prot_printf(imapd_out, "%s NO Error initializing TLS\r\n", tag);
-+ } else {
-+ fatal("tls_init() failed", EC_CONFIG);
-+ }
-+
-+ return;
-+ }
-+
-+ if (imaps == 0)
-+ {
-+ prot_printf(imapd_out, "%s OK Begin TLS negotiation now\r\n", tag);
-+ /* must flush our buffers before starting tls */
-+ prot_flush(imapd_out);
-+ }
-+
-+ result=tls_start_servertls(0, /* read */
-+ 1, /* write */
-+ layerp,
-+ &auth_id,
-+ &tls_conn);
-+
-+ /* if error */
-+ if (result==-1) {
-+ if (imaps == 0) {
-+ prot_printf(imapd_out, "%s NO Starttls negotiation failed\r\n",
-+ tag);
-+ syslog(LOG_NOTICE, "STARTTLS negotiation failed: %s",
-+ imapd_clienthost);
-+ return;
-+ } else {
-+ syslog(LOG_NOTICE, "imaps TLS negotiation failed: %s",
-+ imapd_clienthost);
-+ fatal("tls_start_servertls() failed", EC_TEMPFAIL);
-+ return;
-+ }
-+ }
-+
-+ /* tell SASL about the negotiated layer */
-+ result = sasl_setprop(imapd_saslconn, SASL_SSF_EXTERNAL, &ssf);
-+ if (result != SASL_OK) {
-+ fatal("sasl_setprop() failed: cmd_starttls()", EC_TEMPFAIL);
-+ }
-+ saslprops.ssf = ssf;
-+
-+ result = sasl_setprop(imapd_saslconn, SASL_AUTH_EXTERNAL, auth_id);
-+ if (result != SASL_OK) {
-+ fatal("sasl_setprop() failed: cmd_starttls()", EC_TEMPFAIL);
-+ }
-+ if(saslprops.authid) {
-+ free(saslprops.authid);
-+ saslprops.authid = NULL;
-+ }
-+ if(auth_id)
-+ saslprops.authid = xstrdup(auth_id);
-+
-+ /* tell the prot layer about our new layers */
-+ prot_settls(imapd_in, tls_conn);
-+ prot_settls(imapd_out, tls_conn);
-+
-+ imapd_starttls_done = 1;
-+}
-+#else
-+void cmd_starttls(char *tag, int imaps)
-+{
-+ fatal("cmd_starttls() executed, but starttls isn't implemented!",
-+ EC_SOFTWARE);
-+}
-+#endif /* HAVE_SSL */
-+
-+/*
-+ * Parse and perform a STATUS command
-+ * The command has been parsed up to the attribute list
-+ */
-+void
-+cmd_status(tag, name)
-+char *tag;
-+char *name;
-+{
-+ int c;
-+ int statusitems = 0;
-+ static struct buf arg;
-+ struct mailbox mailbox;
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+ int r = 0;
-+ int doclose = 0;
-+
-+ c = prot_getc(imapd_in);
-+ if (c != '(') goto badlist;
-+
-+ c = getword(imapd_in, &arg);
-+ if (arg.s[0] == '\0') goto badlist;
-+ for (;;) {
-+ lcase(arg.s);
-+ if (!strcmp(arg.s, "messages")) {
-+ statusitems |= STATUS_MESSAGES;
-+ }
-+ else if (!strcmp(arg.s, "recent")) {
-+ statusitems |= STATUS_RECENT;
-+ }
-+ else if (!strcmp(arg.s, "uidnext")) {
-+ statusitems |= STATUS_UIDNEXT;
-+ }
-+ else if (!strcmp(arg.s, "uidvalidity")) {
-+ statusitems |= STATUS_UIDVALIDITY;
-+ }
-+ else if (!strcmp(arg.s, "unseen")) {
-+ statusitems |= STATUS_UNSEEN;
-+ }
-+ else {
-+ prot_printf(imapd_out, "%s BAD Invalid Status attribute %s\r\n",
-+ tag, arg.s);
-+ eatline(imapd_in, c);
-+ return;
-+ }
-+
-+ if (c == ' ') c = getword(imapd_in, &arg);
-+ else break;
-+ }
-+
-+ if (c != ')') {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing close parenthesis in Status\r\n", tag);
-+ eatline(imapd_in, c);
-+ return;
-+ }
-+
-+ c = prot_getc(imapd_in);
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') {
-+ prot_printf(imapd_out,
-+ "%s BAD Unexpected extra arguments to Status\r\n", tag);
-+ eatline(imapd_in, c);
-+ return;
-+ }
-+
-+ /*
-+ * Perform a full checkpoint of any open mailbox, in case we're
-+ * doing a STATUS check of the current mailbox.
-+ */
-+ if (imapd_mailbox) {
-+ index_check(imapd_mailbox, 0, 1);
-+ }
-+
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+
-+ if (!r) {
-+ r = mlookup(tag, name, mailboxname, NULL, NULL, NULL, NULL, NULL);
-+ }
-+ if (r == IMAP_MAILBOX_MOVED) return;
-+
-+ if (!r) {
-+ r = mailbox_open_header(mailboxname, imapd_authstate, &mailbox);
-+ }
-+
-+ if (!r) {
-+ doclose = 1;
-+ r = mailbox_open_index(&mailbox);
-+ }
-+ if (!r && !(mailbox.myrights & ACL_READ)) {
-+ r = (imapd_userisadmin || (mailbox.myrights & ACL_LOOKUP)) ?
-+ IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
-+ }
-+
-+ if (!r) {
-+ r = index_status(&mailbox, name, statusitems);
-+ }
-+
-+ if (doclose) mailbox_close(&mailbox);
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ return;
-+ }
-+
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ return;
-+
-+ badlist:
-+ prot_printf(imapd_out, "%s BAD Invalid status list in Status\r\n", tag);
-+ eatline(imapd_in, c);
-+}
-+
-+#ifdef ENABLE_X_NETSCAPE_HACK
-+/*
-+ * Reply to Netscape's crock with a crock of my own
-+ */
-+void cmd_netscrape(char *tag)
-+{
-+ const char *url;
-+
-+ url = config_getstring(IMAPOPT_NETSCAPEURL);
-+
-+ /* I only know of three things to reply with: */
-+ prot_printf(imapd_out,
-+ "* OK [NETSCAPE] Carnegie Mellon Cyrus IMAP\r\n"
-+ "* VERSION %s\r\n",
-+ CYRUS_VERSION);
-+ if (url) prot_printf(imapd_out, "* ACCOUNT-URL %s\r\n", url);
-+ prot_printf(imapd_out, "%s OK %s\r\n",
-+ tag, error_message(IMAP_OK_COMPLETED));
-+}
-+#endif /* ENABLE_X_NETSCAPE_HACK */
-+
-+/* Callback for cmd_namespace to be passed to mboxlist_findall.
-+ * For each top-level mailbox found, print a bit of the response
-+ * if it is a shared namespace. The rock is used as an integer in
-+ * order to ensure the namespace response is correct on a server with
-+ * no shared namespace.
-+ */
-+static int namespacedata(char *name,
-+ int matchlen __attribute__((unused)),
-+ int maycreate __attribute__((unused)),
-+ void *rock)
-+{
-+ int* sawone = (int*) rock;
-+
-+ if (!name) {
-+ return 0;
-+ }
-+
-+ if (!(strncmp(name, "INBOX.", 6))) {
-+ /* The user has a "personal" namespace. */
-+ sawone[NAMESPACE_INBOX] = 1;
-+ } else if (mboxname_isusermailbox(name, 0)) {
-+ /* The user can see the "other users" namespace. */
-+ sawone[NAMESPACE_USER] = 1;
-+ } else {
-+ /* The user can see the "shared" namespace. */
-+ sawone[NAMESPACE_SHARED] = 1;
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * Print out a response to the NAMESPACE command defined by
-+ * RFC 2342.
-+ */
-+void cmd_namespace(tag)
-+ char* tag;
-+{
-+ int sawone[3] = {0, 0, 0};
-+ char* pattern;
-+
-+ if (SLEEZY_NAMESPACE) {
-+ char inboxname[MAX_MAILBOX_NAME+1];
-+
-+ if (strlen(imapd_userid) + 5 > MAX_MAILBOX_NAME)
-+ sawone[NAMESPACE_INBOX] = 0;
-+ else {
-+ (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, "INBOX",
-+ imapd_userid, inboxname);
-+ sawone[NAMESPACE_INBOX] =
-+ !mboxlist_lookup(inboxname, NULL, NULL, NULL);
-+ }
-+ sawone[NAMESPACE_USER] = 1;
-+ sawone[NAMESPACE_SHARED] = 1;
-+ } else {
-+ pattern = xstrdup("%");
-+ /* now find all the exciting toplevel namespaces -
-+ * we're using internal names here
-+ */
-+ mboxlist_findall(NULL, pattern, imapd_userisadmin, imapd_userid,
-+ imapd_authstate, namespacedata, (void*) sawone);
-+ free(pattern);
-+ }
-+
-+ prot_printf(imapd_out, "* NAMESPACE");
-+ if (sawone[NAMESPACE_INBOX]) {
-+ prot_printf(imapd_out, " ((\"%s\" \"%c\"))",
-+ imapd_namespace.prefix[NAMESPACE_INBOX],
-+ imapd_namespace.hier_sep);
-+ } else {
-+ prot_printf(imapd_out, " NIL");
-+ }
-+ if (sawone[NAMESPACE_USER]) {
-+ prot_printf(imapd_out, " ((\"%s\" \"%c\"))",
-+ imapd_namespace.prefix[NAMESPACE_USER],
-+ imapd_namespace.hier_sep);
-+ } else {
-+ prot_printf(imapd_out, " NIL");
-+ }
-+ if (sawone[NAMESPACE_SHARED]) {
-+ prot_printf(imapd_out, " ((\"%s\" \"%c\"))",
-+ imapd_namespace.prefix[NAMESPACE_SHARED],
-+ imapd_namespace.hier_sep);
-+ } else {
-+ prot_printf(imapd_out, " NIL");
-+ }
-+ prot_printf(imapd_out, "\r\n");
-+
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+}
-+
-+/*
-+ * Parse annotate fetch data.
-+ *
-+ * This is a generic routine which parses just the annotation data.
-+ * Any surrounding command text must be parsed elsewhere, ie,
-+ * GETANNOTATION, FETCH.
-+ */
-+
-+int getannotatefetchdata(char *tag,
-+ struct strlist **entries, struct strlist **attribs)
-+{
-+ int c;
-+ static struct buf arg;
-+
-+ *entries = *attribs = NULL;
-+
-+ c = prot_getc(imapd_in);
-+ if (c == EOF) {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing annotation entry\r\n", tag);
-+ goto baddata;
-+ }
-+ else if (c == '(') {
-+ /* entry list */
-+ do {
-+ c = getqstring(imapd_in, imapd_out, &arg);
-+ if (c == EOF) {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing annotation entry\r\n", tag);
-+ goto baddata;
-+ }
-+
-+ /* add the entry to the list */
-+ appendstrlist(entries, arg.s);
-+
-+ } while (c == ' ');
-+
-+ if (c != ')') {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing close paren in annotation entry list \r\n",
-+ tag);
-+ goto baddata;
-+ }
-+
-+ c = prot_getc(imapd_in);
-+ }
-+ else {
-+ /* single entry -- add it to the list */
-+ prot_ungetc(c, imapd_in);
-+ c = getqstring(imapd_in, imapd_out, &arg);
-+ if (c == EOF) {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing annotation entry\r\n", tag);
-+ goto baddata;
-+ }
-+
-+ appendstrlist(entries, arg.s);
-+ }
-+
-+ if (c != ' ' || (c = prot_getc(imapd_in)) == EOF) {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing annotation attribute(s)\r\n", tag);
-+ goto baddata;
-+ }
-+
-+ if (c == '(') {
-+ /* attrib list */
-+ do {
-+ c = getnstring(imapd_in, imapd_out, &arg);
-+ if (c == EOF) {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing annotation attribute(s)\r\n", tag);
-+ goto baddata;
-+ }
-+
-+ /* add the attrib to the list */
-+ appendstrlist(attribs, arg.s);
-+
-+ } while (c == ' ');
-+
-+ if (c != ')') {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing close paren in "
-+ "annotation attribute list\r\n", tag);
-+ goto baddata;
-+ }
-+
-+ c = prot_getc(imapd_in);
-+ }
-+ else {
-+ /* single attrib */
-+ prot_ungetc(c, imapd_in);
-+ c = getqstring(imapd_in, imapd_out, &arg);
-+ if (c == EOF) {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing annotation attribute\r\n", tag);
-+ goto baddata;
-+ }
-+
-+ appendstrlist(attribs, arg.s);
-+ }
-+
-+ return c;
-+
-+ baddata:
-+ if (c != EOF) prot_ungetc(c, imapd_in);
-+ return EOF;
-+}
-+
-+/*
-+ * Parse annotate store data.
-+ *
-+ * This is a generic routine which parses just the annotation data.
-+ * Any surrounding command text must be parsed elsewhere, ie,
-+ * SETANNOTATION, STORE, APPEND.
-+ */
-+
-+int getannotatestoredata(char *tag, struct entryattlist **entryatts)
-+{
-+ int c, islist = 0;
-+ static struct buf entry, attrib, value;
-+ struct attvaluelist *attvalues = NULL;
-+
-+ *entryatts = NULL;
-+
-+ c = prot_getc(imapd_in);
-+ if (c == EOF) {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing annotation entry\r\n", tag);
-+ goto baddata;
-+ }
-+ else if (c == '(') {
-+ /* entry list */
-+ islist = 1;
-+ }
-+ else {
-+ /* single entry -- put the char back */
-+ prot_ungetc(c, imapd_in);
-+ }
-+
-+ do {
-+ /* get entry */
-+ c = getqstring(imapd_in, imapd_out, &entry);
-+ if (c == EOF) {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing annotation entry\r\n", tag);
-+ goto baddata;
-+ }
-+
-+ /* parse att-value list */
-+ if (c != ' ' || (c = prot_getc(imapd_in)) != '(') {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing annotation attribute-values list\r\n",
-+ tag);
-+ goto baddata;
-+ }
-+
-+ do {
-+ /* get attrib */
-+ c = getqstring(imapd_in, imapd_out, &attrib);
-+ if (c == EOF) {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing annotation attribute\r\n", tag);
-+ goto baddata;
-+ }
-+
-+ /* get value */
-+ if (c != ' ' ||
-+ (c = getnstring(imapd_in, imapd_out, &value)) == EOF) {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing annotation value\r\n", tag);
-+ goto baddata;
-+ }
-+
-+ /* add the attrib-value pair to the list */
-+ appendattvalue(&attvalues, attrib.s, value.s);
-+
-+ } while (c == ' ');
-+
-+ if (c != ')') {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing close paren in annotation "
-+ "attribute-values list\r\n", tag);
-+ goto baddata;
-+ }
-+
-+ /* add the entry to the list */
-+ appendentryatt(entryatts, entry.s, attvalues);
-+ attvalues = NULL;
-+
-+ c = prot_getc(imapd_in);
-+
-+ } while (c == ' ');
-+
-+ if (islist) {
-+ if (c != ')') {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing close paren in annotation entry list \r\n",
-+ tag);
-+ goto baddata;
-+ }
-+
-+ c = prot_getc(imapd_in);
-+ }
-+
-+ return c;
-+
-+ baddata:
-+ if (attvalues) freeattvalues(attvalues);
-+ if (c != EOF) prot_ungetc(c, imapd_in);
-+ return EOF;
-+}
-+
-+/*
-+ * Output an entry/attribute-value list response.
-+ *
-+ * This is a generic routine which outputs just the annotation data.
-+ * Any surrounding response text must be output elsewhere, ie,
-+ * GETANNOTATION, FETCH.
-+ */
-+void annotate_response(struct entryattlist *l)
-+{
-+ int islist; /* do we have more than one entry? */
-+
-+ if (!l) return;
-+
-+ islist = (l->next != NULL);
-+
-+ if (islist) prot_printf(imapd_out, "(");
-+
-+ while (l) {
-+ prot_printf(imapd_out, "\"%s\"", l->entry);
-+
-+ /* do we have attributes? solicited vs. unsolicited */
-+ if (l->attvalues) {
-+ struct attvaluelist *av = l->attvalues;
-+
-+ prot_printf(imapd_out, " (");
-+ while (av) {
-+ prot_printf(imapd_out, "\"%s\" ", av->attrib);
-+ if (!strcasecmp(av->value, "NIL"))
-+ prot_printf(imapd_out, "NIL");
-+ else
-+ prot_printf(imapd_out, "\"%s\"", av->value);
-+
-+ if ((av = av->next) == NULL)
-+ prot_printf(imapd_out, ")");
-+ else
-+ prot_printf(imapd_out, " ");
-+ }
-+ }
-+
-+ if ((l = l->next) != NULL)
-+ prot_printf(imapd_out, " ");
-+ }
-+
-+ if (islist) prot_printf(imapd_out, ")");
-+}
-+
-+/*
-+ * Perform a GETANNOTATION command
-+ *
-+ * The command has been parsed up to the entries
-+ */
-+void cmd_getannotation(char *tag, char *mboxpat)
-+{
-+ int c, r = 0;
-+ struct strlist *entries = NULL, *attribs = NULL;
-+
-+ c = getannotatefetchdata(tag, &entries, &attribs);
-+ if (c == EOF) {
-+ eatline(imapd_in, c);
-+ return;
-+ }
-+
-+ /* check for CRLF */
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') {
-+ prot_printf(imapd_out,
-+ "%s BAD Unexpected extra arguments to Getannotation\r\n",
-+ tag);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+
-+ r = annotatemore_fetch(mboxpat, entries, attribs, &imapd_namespace,
-+ imapd_userisadmin || imapd_userisproxyadmin,
-+ imapd_userid, imapd_authstate, imapd_out);
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ } else {
-+ prot_printf(imapd_out, "%s OK %s\r\n",
-+ tag, error_message(IMAP_OK_COMPLETED));
-+ }
-+
-+ freeargs:
-+ if (entries) freestrlist(entries);
-+ if (attribs) freestrlist(attribs);
-+
-+ return;
-+}
-+
-+/*
-+ * Perform a SETANNOTATION command
-+ *
-+ * The command has been parsed up to the entry-att list
-+ */
-+void cmd_setannotation(char *tag, char *mboxpat)
-+{
-+ int c, r = 0;
-+ struct entryattlist *entryatts = NULL;
-+
-+ c = getannotatestoredata(tag, &entryatts);
-+ if (c == EOF) {
-+ eatline(imapd_in, c);
-+ return;
-+ }
-+
-+ /* check for CRLF */
-+ if (c == '\r') c = prot_getc(imapd_in);
-+ if (c != '\n') {
-+ prot_printf(imapd_out,
-+ "%s BAD Unexpected extra arguments to Setannotation\r\n",
-+ tag);
-+ eatline(imapd_in, c);
-+ goto freeargs;
-+ }
-+
-+ r = annotatemore_store(mboxpat,
-+ entryatts, &imapd_namespace, imapd_userisadmin,
-+ imapd_userid, imapd_authstate);
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ } else {
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ }
-+
-+ freeargs:
-+ if (entryatts) freeentryatts(entryatts);
-+ return;
-+}
-+
-+/*
-+ * Parse a search program
-+ */
-+int getsearchprogram(tag, searchargs, charset, parsecharset)
-+char *tag;
-+struct searchargs *searchargs;
-+int *charset;
-+int parsecharset;
-+{
-+ int c;
-+
-+ do {
-+ c = getsearchcriteria(tag, searchargs, charset, parsecharset);
-+ parsecharset = 0;
-+ } while (c == ' ');
-+ return c;
-+}
-+
-+/*
-+ * Parse a search criteria
-+ */
-+int getsearchcriteria(tag, searchargs, charset, parsecharset)
-+char *tag;
-+struct searchargs *searchargs;
-+int *charset;
-+int parsecharset;
-+{
-+ static struct buf criteria, arg;
-+ struct searchargs *sub1, *sub2;
-+ char *p, *str;
-+ int c, flag;
-+ unsigned size;
-+ time_t start, end;
-+
-+ c = getword(imapd_in, &criteria);
-+ lcase(criteria.s);
-+ switch (criteria.s[0]) {
-+ case '\0':
-+ if (c != '(') goto badcri;
-+ c = getsearchprogram(tag, searchargs, charset, 0);
-+ if (c == EOF) return EOF;
-+ if (c != ')') {
-+ prot_printf(imapd_out, "%s BAD Missing required close paren in Search command\r\n",
-+ tag);
-+ if (c != EOF) prot_ungetc(c, imapd_in);
-+ return EOF;
-+ }
-+ c = prot_getc(imapd_in);
-+ break;
-+
-+ case '0': case '1': case '2': case '3': case '4':
-+ case '5': case '6': case '7': case '8': case '9':
-+ case '*':
-+ if (imparse_issequence(criteria.s)) {
-+ appendstrlist(&searchargs->sequence, criteria.s);
-+ }
-+ else goto badcri;
-+ break;
-+
-+ case 'a':
-+ if (!strcmp(criteria.s, "answered")) {
-+ searchargs->system_flags_set |= FLAG_ANSWERED;
-+ }
-+ else if (!strcmp(criteria.s, "all")) {
-+ break;
-+ }
-+ else goto badcri;
-+ break;
-+
-+ case 'b':
-+ if (!strcmp(criteria.s, "before")) {
-+ if (c != ' ') goto missingarg;
-+ c = getsearchdate(&start, &end);
-+ if (c == EOF) goto baddate;
-+ if (!searchargs->before || searchargs->before > start) {
-+ searchargs->before = start;
-+ }
-+ }
-+ else if (!strcmp(criteria.s, "bcc")) {
-+ if (c != ' ') goto missingarg;
-+ c = getastring(imapd_in, imapd_out, &arg);
-+ if (c == EOF) goto missingarg;
-+ str = charset_convert(arg.s, *charset, NULL, 0);
-+ if (strchr(str, EMPTY)) {
-+ /* Force failure */
-+ searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
-+ }
-+ else {
-+ appendstrlistpat(&searchargs->bcc, str);
-+ }
-+ }
-+ else if (!strcmp(criteria.s, "body")) {
-+ if (c != ' ') goto missingarg;
-+ c = getastring(imapd_in, imapd_out, &arg);
-+ if (c == EOF) goto missingarg;
-+ str = charset_convert(arg.s, *charset, NULL, 0);
-+ if (strchr(str, EMPTY)) {
-+ /* Force failure */
-+ searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
-+ }
-+ else {
-+ appendstrlistpat(&searchargs->body, str);
-+ }
-+ }
-+ else goto badcri;
-+ break;
-+
-+ case 'c':
-+ if (!strcmp(criteria.s, "cc")) {
-+ if (c != ' ') goto missingarg;
-+ c = getastring(imapd_in, imapd_out, &arg);
-+ if (c == EOF) goto missingarg;
-+ str = charset_convert(arg.s, *charset, NULL, 0);
-+ if (strchr(str, EMPTY)) {
-+ /* Force failure */
-+ searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
-+ }
-+ else {
-+ appendstrlistpat(&searchargs->cc, str);
-+ }
-+ }
-+ else if (parsecharset && !strcmp(criteria.s, "charset")) {
-+ if (c != ' ') goto missingarg;
-+ c = getastring(imapd_in, imapd_out, &arg);
-+ if (c != ' ') goto missingarg;
-+ lcase(arg.s);
-+ *charset = charset_lookupname(arg.s);
-+ }
-+ else goto badcri;
-+ break;
-+
-+ case 'd':
-+ if (!strcmp(criteria.s, "deleted")) {
-+ searchargs->system_flags_set |= FLAG_DELETED;
-+ }
-+ else if (!strcmp(criteria.s, "draft")) {
-+ searchargs->system_flags_set |= FLAG_DRAFT;
-+ }
-+ else goto badcri;
-+ break;
-+
-+ case 'f':
-+ if (!strcmp(criteria.s, "flagged")) {
-+ searchargs->system_flags_set |= FLAG_FLAGGED;
-+ }
-+ else if (!strcmp(criteria.s, "from")) {
-+ if (c != ' ') goto missingarg;
-+ c = getastring(imapd_in, imapd_out, &arg);
-+ if (c == EOF) goto missingarg;
-+ str = charset_convert(arg.s, *charset, NULL, 0);
-+ if (strchr(str, EMPTY)) {
-+ /* Force failure */
-+ searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
-+ }
-+ else {
-+ appendstrlistpat(&searchargs->from, str);
-+ }
-+ }
-+ else goto badcri;
-+ break;
-+
-+ case 'h':
-+ if (!strcmp(criteria.s, "header")) {
-+ struct strlist **patlist;
-+
-+ if (c != ' ') goto missingarg;
-+ c = getastring(imapd_in, imapd_out, &arg);
-+ if (c != ' ') goto missingarg;
-+ lcase(arg.s);
-+
-+ /* some headers can be reduced to search terms */
-+ if (!strcmp(arg.s, "bcc")) {
-+ patlist = &searchargs->bcc;
-+ }
-+ else if (!strcmp(arg.s, "cc")) {
-+ patlist = &searchargs->cc;
-+ }
-+ else if (!strcmp(arg.s, "to")) {
-+ patlist = &searchargs->to;
-+ }
-+ else if (!strcmp(arg.s, "from")) {
-+ patlist = &searchargs->from;
-+ }
-+ else if (!strcmp(arg.s, "subject")) {
-+ patlist = &searchargs->subject;
-+ }
-+
-+ /* we look message-id up in the envelope */
-+ else if (!strcmp(arg.s, "message-id")) {
-+ patlist = &searchargs->messageid;
-+ }
-+
-+ /* all other headers we handle normally */
-+ else {
-+ if (searchargs->cache_atleast < BIT32_MAX) {
-+ bit32 this_ver =
-+ mailbox_cached_header(arg.s);
-+ if(this_ver > searchargs->cache_atleast)
-+ searchargs->cache_atleast = this_ver;
-+ }
-+ appendstrlist(&searchargs->header_name, arg.s);
-+ patlist = &searchargs->header;
-+ }
-+
-+ c = getastring(imapd_in, imapd_out, &arg);
-+ if (c == EOF) goto missingarg;
-+ str = charset_convert(arg.s, *charset, NULL, 0);
-+ if (strchr(str, EMPTY)) {
-+ /* Force failure */
-+ searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
-+ }
-+ else {
-+ appendstrlistpat(patlist, str);
-+ }
-+ }
-+ else goto badcri;
-+ break;
-+
-+ case 'k':
-+ if (!strcmp(criteria.s, "keyword")) {
-+ if (c != ' ') goto missingarg;
-+ c = getword(imapd_in, &arg);
-+ if (!imparse_isatom(arg.s)) goto badflag;
-+ lcase(arg.s);
-+ for (flag=0; flag < MAX_USER_FLAGS; flag++) {
-+ if (imapd_mailbox->flagname[flag] &&
-+ !strcasecmp(imapd_mailbox->flagname[flag], arg.s)) break;
-+ }
-+ if (flag == MAX_USER_FLAGS) {
-+ /* Force failure */
-+ searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
-+ break;
-+ }
-+ searchargs->user_flags_set[flag/32] |= 1<<(flag&31);
-+ }
-+ else goto badcri;
-+ break;
-+
-+ case 'l':
-+ if (!strcmp(criteria.s, "larger")) {
-+ if (c != ' ') goto missingarg;
-+ c = getword(imapd_in, &arg);
-+ size = 0;
-+ for (p = arg.s; *p && isdigit((int) *p); p++) {
-+ size = size * 10 + *p - '0';
-+ /* if (size < 0) goto badnumber; */
-+ }
-+ if (!arg.s || *p) goto badnumber;
-+ if (size > searchargs->larger) searchargs->larger = size;
-+ }
-+ else goto badcri;
-+ break;
-+
-+ case 'n':
-+ if (!strcmp(criteria.s, "not")) {
-+ if (c != ' ') goto missingarg;
-+ sub1 = (struct searchargs *)xzmalloc(sizeof(struct searchargs));
-+ c = getsearchcriteria(tag, sub1, charset, 0);
-+ if (c == EOF) {
-+ freesearchargs(sub1);
-+ return EOF;
-+ }
-+
-+ appendsearchargs(searchargs, sub1, (struct searchargs *)0);
-+ }
-+ else if (!strcmp(criteria.s, "new")) {
-+ searchargs->flags |= (SEARCH_SEEN_UNSET|SEARCH_RECENT_SET);
-+ }
-+ else goto badcri;
-+ break;
-+
-+ case 'o':
-+ if (!strcmp(criteria.s, "or")) {
-+ if (c != ' ') goto missingarg;
-+ sub1 = (struct searchargs *)xzmalloc(sizeof(struct searchargs));
-+ c = getsearchcriteria(tag, sub1, charset, 0);
-+ if (c == EOF) {
-+ freesearchargs(sub1);
-+ return EOF;
-+ }
-+ if (c != ' ') goto missingarg;
-+ sub2 = (struct searchargs *)xzmalloc(sizeof(struct searchargs));
-+ c = getsearchcriteria(tag, sub2, charset, 0);
-+ if (c == EOF) {
-+ freesearchargs(sub1);
-+ freesearchargs(sub2);
-+ return EOF;
-+ }
-+ appendsearchargs(searchargs, sub1, sub2);
-+ }
-+ else if (!strcmp(criteria.s, "old")) {
-+ searchargs->flags |= SEARCH_RECENT_UNSET;
-+ }
-+ else if (!strcmp(criteria.s, "on")) {
-+ if (c != ' ') goto missingarg;
-+ c = getsearchdate(&start, &end);
-+ if (c == EOF) goto baddate;
-+ if (!searchargs->before || searchargs->before > end) {
-+ searchargs->before = end;
-+ }
-+ if (!searchargs->after || searchargs->after < start) {
-+ searchargs->after = start;
-+ }
-+ }
-+ else goto badcri;
-+ break;
-+
-+ case 'r':
-+ if (!strcmp(criteria.s, "recent")) {
-+ searchargs->flags |= SEARCH_RECENT_SET;
-+ }
-+ else goto badcri;
-+ break;
-+
-+ case 's':
-+ if (!strcmp(criteria.s, "seen")) {
-+ searchargs->flags |= SEARCH_SEEN_SET;
-+ }
-+ else if (!strcmp(criteria.s, "sentbefore")) {
-+ if (c != ' ') goto missingarg;
-+ c = getsearchdate(&start, &end);
-+ if (c == EOF) goto baddate;
-+ if (!searchargs->sentbefore || searchargs->sentbefore > start) {
-+ searchargs->sentbefore = start;
-+ }
-+ }
-+ else if (!strcmp(criteria.s, "senton")) {
-+ if (c != ' ') goto missingarg;
-+ c = getsearchdate(&start, &end);
-+ if (c == EOF) goto baddate;
-+ if (!searchargs->sentbefore || searchargs->sentbefore > end) {
-+ searchargs->sentbefore = end;
-+ }
-+ if (!searchargs->sentafter || searchargs->sentafter < start) {
-+ searchargs->sentafter = start;
-+ }
-+ }
-+ else if (!strcmp(criteria.s, "sentsince")) {
-+ if (c != ' ') goto missingarg;
-+ c = getsearchdate(&start, &end);
-+ if (c == EOF) goto baddate;
-+ if (!searchargs->sentafter || searchargs->sentafter < start) {
-+ searchargs->sentafter = start;
-+ }
-+ }
-+ else if (!strcmp(criteria.s, "since")) {
-+ if (c != ' ') goto missingarg;
-+ c = getsearchdate(&start, &end);
-+ if (c == EOF) goto baddate;
-+ if (!searchargs->after || searchargs->after < start) {
-+ searchargs->after = start;
-+ }
-+ }
-+ else if (!strcmp(criteria.s, "smaller")) {
-+ if (c != ' ') goto missingarg;
-+ c = getword(imapd_in, &arg);
-+ size = 0;
-+ for (p = arg.s; *p && isdigit((int) *p); p++) {
-+ size = size * 10 + *p - '0';
-+ /* if (size < 0) goto badnumber; */
-+ }
-+ if (!arg.s || *p) goto badnumber;
-+ if (size == 0) size = 1;
-+ if (!searchargs->smaller || size < searchargs->smaller)
-+ searchargs->smaller = size;
-+ }
-+ else if (!strcmp(criteria.s, "subject")) {
-+ if (c != ' ') goto missingarg;
-+ c = getastring(imapd_in, imapd_out, &arg);
-+ if (c == EOF) goto missingarg;
-+ str = charset_convert(arg.s, *charset, NULL, 0);
-+ if (strchr(str, EMPTY)) {
-+ /* Force failure */
-+ searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
-+ }
-+ else {
-+ appendstrlistpat(&searchargs->subject, str);
-+ }
-+ }
-+ else goto badcri;
-+ break;
-+
-+ case 't':
-+ if (!strcmp(criteria.s, "to")) {
-+ if (c != ' ') goto missingarg;
-+ c = getastring(imapd_in, imapd_out, &arg);
-+ if (c == EOF) goto missingarg;
-+ str = charset_convert(arg.s, *charset, NULL, 0);
-+ if (strchr(str, EMPTY)) {
-+ /* Force failure */
-+ searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
-+ }
-+ else {
-+ appendstrlistpat(&searchargs->to, str);
-+ }
-+ }
-+ else if (!strcmp(criteria.s, "text")) {
-+ if (c != ' ') goto missingarg;
-+ c = getastring(imapd_in, imapd_out, &arg);
-+ if (c == EOF) goto missingarg;
-+ str = charset_convert(arg.s, *charset, NULL, 0);
-+ if (strchr(str, EMPTY)) {
-+ /* Force failure */
-+ searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
-+ }
-+ else {
-+ appendstrlistpat(&searchargs->text, str);
-+ }
-+ }
-+ else goto badcri;
-+ break;
-+
-+ case 'u':
-+ if (!strcmp(criteria.s, "uid")) {
-+ if (c != ' ') goto missingarg;
-+ c = getword(imapd_in, &arg);
-+ if (!imparse_issequence(arg.s)) goto badcri;
-+ appendstrlist(&searchargs->uidsequence, arg.s);
-+ }
-+ else if (!strcmp(criteria.s, "unseen")) {
-+ searchargs->flags |= SEARCH_SEEN_UNSET;
-+ }
-+ else if (!strcmp(criteria.s, "unanswered")) {
-+ searchargs->system_flags_unset |= FLAG_ANSWERED;
-+ }
-+ else if (!strcmp(criteria.s, "undeleted")) {
-+ searchargs->system_flags_unset |= FLAG_DELETED;
-+ }
-+ else if (!strcmp(criteria.s, "undraft")) {
-+ searchargs->system_flags_unset |= FLAG_DRAFT;
-+ }
-+ else if (!strcmp(criteria.s, "unflagged")) {
-+ searchargs->system_flags_unset |= FLAG_FLAGGED;
-+ }
-+ else if (!strcmp(criteria.s, "unkeyword")) {
-+ if (c != ' ') goto missingarg;
-+ c = getword(imapd_in, &arg);
-+ if (!imparse_isatom(arg.s)) goto badflag;
-+ lcase(arg.s);
-+ for (flag=0; flag < MAX_USER_FLAGS; flag++) {
-+ if (imapd_mailbox->flagname[flag] &&
-+ !strcasecmp(imapd_mailbox->flagname[flag], arg.s)) break;
-+ }
-+ if (flag != MAX_USER_FLAGS) {
-+ searchargs->user_flags_unset[flag/32] |= 1<<(flag&31);
-+ }
-+ }
-+ else goto badcri;
-+ break;
-+
-+ default:
-+ badcri:
-+ prot_printf(imapd_out, "%s BAD Invalid Search criteria\r\n", tag);
-+ if (c != EOF) prot_ungetc(c, imapd_in);
-+ return EOF;
-+ }
-+
-+ return c;
-+
-+ missingarg:
-+ prot_printf(imapd_out, "%s BAD Missing required argument to Search %s\r\n",
-+ tag, criteria.s);
-+ if (c != EOF) prot_ungetc(c, imapd_in);
-+ return EOF;
-+
-+ badflag:
-+ prot_printf(imapd_out, "%s BAD Invalid flag name %s in Search command\r\n",
-+ tag, arg.s);
-+ if (c != EOF) prot_ungetc(c, imapd_in);
-+ return EOF;
-+
-+ baddate:
-+ prot_printf(imapd_out, "%s BAD Invalid date in Search command\r\n", tag);
-+ if (c != EOF) prot_ungetc(c, imapd_in);
-+ return EOF;
-+
-+ badnumber:
-+ prot_printf(imapd_out, "%s BAD Invalid number in Search command\r\n", tag);
-+ if (c != EOF) prot_ungetc(c, imapd_in);
-+ return EOF;
-+}
-+
-+void cmd_dump(char *tag, char *name, int uid_start)
-+{
-+ int r = 0;
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+ char *path, *acl;
-+
-+ /* administrators only please */
-+ if (!imapd_userisadmin) {
-+ r = IMAP_PERMISSION_DENIED;
-+ }
-+
-+ if (!r) {
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+ }
-+
-+ if (!r) {
-+ r = mlookup(tag, name, mailboxname, NULL, &path, NULL, &acl, NULL);
-+ }
-+ if (r == IMAP_MAILBOX_MOVED) return;
-+
-+ if(!r) {
-+ r = dump_mailbox(tag, mailboxname, path, acl, uid_start, imapd_in,
-+ imapd_out, imapd_authstate);
-+ }
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ } else {
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ }
-+}
-+
-+void cmd_undump(char *tag, char *name)
-+{
-+ int r = 0;
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+ char *path, *acl;
-+
-+ /* administrators only please */
-+ if (!imapd_userisadmin) {
-+ r = IMAP_PERMISSION_DENIED;
-+ }
-+
-+ if (!r) {
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+ }
-+
-+ if (!r) {
-+ r = mlookup(tag, name, mailboxname, NULL, &path, NULL, &acl, NULL);
-+ }
-+ if (r == IMAP_MAILBOX_MOVED) return;
-+
-+ if(!r) {
-+ /* save this stuff from additional mlookups */
-+ char *safe_path = xstrdup(path);
-+ char *safe_acl = xstrdup(acl);
-+ r = undump_mailbox(mailboxname, safe_path, safe_acl,
-+ imapd_in, imapd_out,
-+ imapd_authstate);
-+ free(safe_path);
-+ free(safe_acl);
-+ }
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s%s\r\n",
-+ tag,
-+ (r == IMAP_MAILBOX_NONEXISTENT &&
-+ mboxlist_createmailboxcheck(mailboxname, 0, 0,
-+ imapd_userisadmin,
-+ imapd_userid, imapd_authstate,
-+ NULL, NULL) == 0)
-+ ? "[TRYCREATE] " : "", error_message(r));
-+ } else {
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ }
-+}
-+
-+static int getresult(struct protstream *p, char *tag)
-+{
-+ char buf[4096];
-+ char *str = (char *) buf;
-+
-+ while(1) {
-+ if (!prot_fgets(str, sizeof(buf), p)) {
-+ return IMAP_SERVER_UNAVAILABLE;
-+ }
-+ if (!strncmp(str, tag, strlen(tag))) {
-+ str += strlen(tag);
-+ if(!*str) {
-+ /* We got a tag, but no response */
-+ return IMAP_SERVER_UNAVAILABLE;
-+ }
-+ str++;
-+ if (!strncasecmp(str, "OK ", 3)) { return 0; }
-+ if (!strncasecmp(str, "NO ", 3)) { return IMAP_REMOTE_DENIED; }
-+ return IMAP_SERVER_UNAVAILABLE; /* huh? */
-+ }
-+ /* skip this line, we don't really care */
-+ }
-+}
-+
-+/* given 2 protstreams and a mailbox, gets the acl and then wipes it */
-+static int trashacl(struct protstream *pin, struct protstream *pout,
-+ char *mailbox)
-+{
-+ int i=0, j=0;
-+ char tagbuf[128];
-+ int c; /* getword() returns an int */
-+ struct buf tag, cmd, tmp, user;
-+ int r = 0;
-+
-+ memset(&tag, 0, sizeof(struct buf));
-+ memset(&cmd, 0, sizeof(struct buf));
-+ memset(&tmp, 0, sizeof(struct buf));
-+ memset(&user, 0, sizeof(struct buf));
-+
-+ prot_printf(pout, "ACL0 GETACL {%lu+}\r\n%s\r\n",
-+ (unsigned long) strlen(mailbox), mailbox);
-+
-+ while(1) {
-+ c = getword(pin, &tag);
-+ if (c == EOF) {
-+ r = IMAP_SERVER_UNAVAILABLE;
-+ break;
-+ }
-+
-+ c = getword(pin, &cmd);
-+ if (c == EOF) {
-+ r = IMAP_SERVER_UNAVAILABLE;
-+ break;
-+ }
-+
-+ if(c == '\r') {
-+ c = prot_getc(pin);
-+ if(c != '\n') {
-+ r = IMAP_SERVER_UNAVAILABLE;
-+ goto cleanup;
-+ }
-+ }
-+ if(c == '\n') goto cleanup;
-+
-+ if (tag.s[0] == '*' && !strncmp(cmd.s, "ACL", 3)) {
-+ while(c != '\n') {
-+ /* An ACL response, we should send a DELETEACL command */
-+ c = getastring(pin, pout, &tmp);
-+ if (c == EOF) {
-+ r = IMAP_SERVER_UNAVAILABLE;
-+ goto cleanup;
-+ }
-+
-+ if(c == '\r') {
-+ c = prot_getc(pin);
-+ if(c != '\n') {
-+ r = IMAP_SERVER_UNAVAILABLE;
-+ goto cleanup;
-+ }
-+ }
-+ if(c == '\n') goto cleanup;
-+
-+ c = getastring(pin, pout, &user);
-+ if (c == EOF) {
-+ r = IMAP_SERVER_UNAVAILABLE;
-+ goto cleanup;
-+ }
-+
-+ snprintf(tagbuf, sizeof(tagbuf), "ACL%d", ++i);
-+
-+ prot_printf(pout, "%s DELETEACL {%lu+}\r\n%s {%lu+}\r\n%s\r\n",
-+ tagbuf, (unsigned long) strlen(mailbox), mailbox,
-+ (unsigned long) strlen(user.s), user.s);
-+ if(c == '\r') {
-+ c = prot_getc(pin);
-+ if(c != '\n') {
-+ r = IMAP_SERVER_UNAVAILABLE;
-+ goto cleanup;
-+ }
-+ }
-+ /* if the next character is \n, we'll exit the loop */
-+ }
-+ continue;
-+ } else if (!strncmp(tag.s, "ACL0", 4)) {
-+ /* end of this command */
-+ if (!strcasecmp(cmd.s, "OK")) { break; }
-+ if (!strcasecmp(cmd.s, "NO")) { r = IMAP_REMOTE_DENIED; break; }
-+ r = IMAP_SERVER_UNAVAILABLE;
-+ break;
-+ }
-+ }
-+
-+ cleanup:
-+
-+ /* Now cleanup after all the DELETEACL commands */
-+ if(!r) {
-+ while(j < i) {
-+ c = getword(pin, &tag);
-+ if (c == EOF) {
-+ r = IMAP_SERVER_UNAVAILABLE;
-+ break;
-+ }
-+
-+ eatline(pin, c);
-+
-+ if(!strncmp("ACL", tag.s, 3)) {
-+ j++;
-+ }
-+ }
-+ }
-+
-+ if(r) eatline(pin, c);
-+
-+ freebuf(&user);
-+ freebuf(&tmp);
-+ freebuf(&cmd);
-+ freebuf(&tag);
-+
-+ return r;
-+}
-+
-+static int dumpacl(struct protstream *pin, struct protstream *pout,
-+ char *mailbox, char *acl_in)
-+{
-+ int r = 0;
-+ int c; /* getword() returns an int */
-+ char tag[128];
-+ int tagnum = 1;
-+ char *rights, *nextid;
-+ int mailboxlen = strlen(mailbox);
-+ char *acl_safe = acl_in ? xstrdup(acl_in) : NULL;
-+ char *acl = acl_safe;
-+ struct buf inbuf;
-+
-+ memset(&inbuf, 0, sizeof(struct buf));
-+
-+ while (acl) {
-+ rights = strchr(acl, '\t');
-+ if (!rights) break;
-+ *rights++ = '\0';
-+
-+ nextid = strchr(rights, '\t');
-+ if (!nextid) break;
-+ *nextid++ = '\0';
-+
-+ snprintf(tag, sizeof(tag), "SACL%d", tagnum++);
-+
-+ prot_printf(pout, "%s SETACL {%d+}\r\n%s {%lu+}\r\n%s {%lu+}\r\n%s\r\n",
-+ tag,
-+ mailboxlen, mailbox,
-+ (unsigned long) strlen(acl), acl,
-+ (unsigned long) strlen(rights), rights);
-+
-+ while(1) {
-+ c = getword(pin, &inbuf);
-+ if (c == EOF) {
-+ r = IMAP_SERVER_UNAVAILABLE;
-+ break;
-+ }
-+ if(strncmp(tag, inbuf.s, strlen(tag))) {
-+ eatline(pin, c);
-+ continue;
-+ } else {
-+ /* this is our line */
-+ break;
-+ }
-+ }
-+
-+ /* Are we OK? */
-+
-+ c = getword(pin, &inbuf);
-+ if (c == EOF) {
-+ r = IMAP_SERVER_UNAVAILABLE;
-+ break;
-+ }
-+
-+ if(strncmp("OK", inbuf.s, 2)) {
-+ r = IMAP_REMOTE_DENIED;
-+ break;
-+ }
-+
-+ /* Eat the line and get the next one */
-+ eatline(pin, c);
-+ acl = nextid;
-+ }
-+
-+ freebuf(&inbuf);
-+ if(acl_safe) free(acl_safe);
-+
-+ return r;
-+}
-+
-+static int do_xfer_single(char *toserver, char *topart,
-+ char *name, char *mailboxname,
-+ int mbflags,
-+ char *path, char *part, char *acl,
-+ int prereserved,
-+ mupdate_handle *h_in,
-+ struct backend *be_in)
-+{
-+ int r = 0, rerr = 0;
-+ char buf[MAX_PARTITION_LEN+HOSTNAME_SIZE+2];
-+ struct backend *be = NULL;
-+ mupdate_handle *mupdate_h = NULL;
-+ int backout_mupdate = 0;
-+ int backout_remotebox = 0;
-+ int backout_remoteflag = 0;
-+
-+ /* Make sure we're given a sane value */
-+ if(topart && !imparse_isatom(topart)) {
-+ return IMAP_PARTITION_UNKNOWN;
-+ }
-+
-+ if(!strcmp(toserver, config_servername)) {
-+ return IMAP_BAD_SERVER;
-+ }
-+
-+ /* Okay, we have the mailbox, now the order of steps is:
-+ *
-+ * 1) Connect to remote server.
-+ * 2) LOCALCREATE on remote server
-+ * 2.5) Set mailbox as REMOTE on local server
-+ * 3) mupdate.DEACTIVATE(mailbox, remoteserver) xxx what partition?
-+ * 4) undump mailbox from local to remote
-+ * 5) Sync remote acl
-+ * 6) mupdate.ACTIVATE(mailbox, remoteserver)
-+ * ** MAILBOX NOW LIVING ON REMOTE SERVER
-+ * 6.5) force remote server to push the final mupdate entry to ensure
-+ * that the state of the world is correct (required if we do not
-+ * know the remote partition, but worst case it will be caught
-+ * when they next sync)
-+ * 7) local delete of mailbox
-+ * 8) remove local remote mailbox entry??????
-+ */
-+
-+ /* Step 1: Connect to remote server */
-+ if(!r && !be_in) {
-+ /* Just authorize as the IMAP server, so pass "" as our authzid */
-+ be = backend_connect(NULL, toserver, &protocol[PROTOCOL_IMAP], "", NULL);
-+ if(!be) r = IMAP_SERVER_UNAVAILABLE;
-+ if(r) syslog(LOG_ERR,
-+ "Could not move mailbox: %s, Backend connect failed",
-+ mailboxname);
-+ } else if(!r) {
-+ be = be_in;
-+ }
-+
-+ /* Step 1a: Connect to mupdate (as needed) */
-+ if(h_in) {
-+ mupdate_h = h_in;
-+ } else if (config_mupdate_server) {
-+ r = mupdate_connect(config_mupdate_server, NULL, &mupdate_h, NULL);
-+ if(r) {
-+ syslog(LOG_ERR,
-+ "Could not move mailbox: %s, MUPDATE connect failed",
-+ mailboxname);
-+ goto done;
-+ }
-+
-+ }
-+
-+ /* Step 2: LOCALCREATE on remote server */
-+ if(!r) {
-+ if(topart) {
-+ /* need to send partition as an atom */
-+ prot_printf(be->out, "LC1 LOCALCREATE {%lu+}\r\n%s %s\r\n",
-+ (unsigned long) strlen(name), name, topart);
-+ } else {
-+ prot_printf(be->out, "LC1 LOCALCREATE {%lu+}\r\n%s\r\n",
-+ (unsigned long) strlen(name), name);
-+ }
-+ r = getresult(be->in, "LC1");
-+ if(r) syslog(LOG_ERR, "Could not move mailbox: %s, LOCALCREATE failed",
-+ mailboxname);
-+ else backout_remotebox = 1;
-+ }
-+
-+ /* Step 2.5: Set mailbox as REMOTE on local server */
-+ if(!r) {
-+ snprintf(buf, sizeof(buf), "%s!%s", toserver, part);
-+ r = mboxlist_update(mailboxname, mbflags|MBTYPE_MOVING, buf, acl, 1);
-+ if(r) syslog(LOG_ERR, "Could not move mailbox: %s, " \
-+ "mboxlist_update failed", mailboxname);
-+ }
-+
-+ /* Step 3: mupdate.DEACTIVATE(mailbox, newserver) */
-+ /* (only if mailbox has not been already deactivated by our caller) */
-+ if(!r && mupdate_h && !prereserved) {
-+ backout_remoteflag = 1;
-+
-+ /* Note we are making the reservation on OUR host so that recovery
-+ * make sense */
-+ snprintf(buf, sizeof(buf), "%s!%s", config_servername, part);
-+ r = mupdate_deactivate(mupdate_h, mailboxname, buf);
-+ if(r) syslog(LOG_ERR,
-+ "Could not move mailbox: %s, MUPDATE DEACTIVATE failed",
-+ mailboxname);
-+ }
-+
-+ /* Step 4: Dump local -> remote */
-+ if(!r) {
-+ backout_mupdate = 1;
-+
-+ prot_printf(be->out, "D01 UNDUMP {%lu+}\r\n%s ",
-+ (unsigned long) strlen(name), name);
-+
-+ r = dump_mailbox(NULL, mailboxname, path, acl, 0, be->in, be->out,
-+ imapd_authstate);
-+
-+ if(r)
-+ syslog(LOG_ERR,
-+ "Could not move mailbox: %s, dump_mailbox() failed",
-+ mailboxname);
-+ }
-+
-+ if(!r) {
-+ r = getresult(be->in, "D01");
-+ if(r) syslog(LOG_ERR, "Could not move mailbox: %s, UNDUMP failed",
-+ mailboxname);
-+ }
-+
-+ /* Step 5: Set ACL on remote */
-+ if(!r) {
-+ r = trashacl(be->in, be->out, name);
-+ if(r) syslog(LOG_ERR, "Could not clear remote acl on %s",
-+ mailboxname);
-+ }
-+ if(!r) {
-+ r = dumpacl(be->in, be->out, name, acl);
-+ if(r) syslog(LOG_ERR, "Could not set remote acl on %s",
-+ mailboxname);
-+ }
-+
-+ /* Step 6: mupdate.activate(mailbox, remote) */
-+ /* We do this from the local server first so that recovery is easier */
-+ if(!r && mupdate_h) {
-+ /* Note the flag that we don't have a valid partiton at the moment */
-+ snprintf(buf, sizeof(buf), "%s!MOVED", toserver);
-+ r = mupdate_activate(mupdate_h, mailboxname, buf, acl);
-+ }
-+
-+ /* MAILBOX NOW LIVES ON REMOTE */
-+ if(!r) {
-+ backout_remotebox = 0;
-+ backout_mupdate = 0;
-+ backout_remoteflag = 0;
-+
-+ /* 6.5) Kick remote server to correct mupdate entry */
-+ /* Note that we don't really care if this succeeds or not */
-+ if (mupdate_h) {
-+ prot_printf(be->out, "MP1 MUPDATEPUSH {%lu+}\r\n%s\r\n",
-+ (unsigned long) strlen(name), name);
-+ rerr = getresult(be->in, "MP1");
-+ if(rerr) {
-+ syslog(LOG_ERR,
-+ "Could not trigger remote push to mupdate server" \
-+ "during move of %s",
-+ mailboxname);
-+ }
-+ }
-+ }
-+
-+ /* 7) local delete of mailbox
-+ * & remove local "remote" mailboxlist entry */
-+ if(!r) {
-+ /* Note that we do not check the ACL, and we don't update MUPDATE */
-+ /* note also that we need to remember to let proxyadmins do this */
-+ r = mboxlist_deletemailbox(mailboxname,
-+ imapd_userisadmin || imapd_userisproxyadmin,
-+ imapd_userid, imapd_authstate, 0, 1, 0);
-+ if(r) syslog(LOG_ERR,
-+ "Could not delete local mailbox during move of %s",
-+ mailboxname);
-+ }
-+
-+done:
-+ if(r && mupdate_h && backout_mupdate) {
-+ rerr = 0;
-+ /* xxx if the mupdate server is what failed, then this won't
-+ help any! */
-+ snprintf(buf, sizeof(buf), "%s!%s", config_servername, part);
-+ rerr = mupdate_activate(mupdate_h, mailboxname, buf, acl);
-+ if(rerr) {
-+ syslog(LOG_ERR,
-+ "Could not back out mupdate during move of %s (%s)",
-+ mailboxname, error_message(rerr));
-+ }
-+ }
-+ if(r && backout_remotebox) {
-+ rerr = 0;
-+ prot_printf(be->out, "LD1 LOCALDELETE {%lu+}\r\n%s\r\n",
-+ (unsigned long) strlen(name), name);
-+ rerr = getresult(be->in, "LD1");
-+ if(rerr) {
-+ syslog(LOG_ERR,
-+ "Could not back out remote mailbox during move of %s (%s)",
-+ name, error_message(rerr));
-+ }
-+ }
-+ if(r && backout_remoteflag) {
-+ rerr = 0;
-+
-+ rerr = mboxlist_update(mailboxname, mbflags, part, acl, 1);
-+ if(rerr) syslog(LOG_ERR, "Could not unset remote flag on mailbox: %s",
-+ mailboxname);
-+ }
-+
-+ /* release the handles we got locally if necessary */
-+ if(mupdate_h && !h_in)
-+ mupdate_disconnect(&mupdate_h);
-+ if(be && !be_in)
-+ backend_disconnect(be, &protocol[PROTOCOL_IMAP]);
-+
-+ return r;
-+}
-+
-+struct xfer_user_rock
-+{
-+ char *toserver;
-+ char *topart;
-+ mupdate_handle *h;
-+ struct backend *be;
-+};
-+
-+static int xfer_user_cb(char *name,
-+ int matchlen __attribute__((unused)),
-+ int maycreate __attribute__((unused)),
-+ void *rock)
-+{
-+ mupdate_handle *mupdate_h = ((struct xfer_user_rock *)rock)->h;
-+ char *toserver = ((struct xfer_user_rock *)rock)->toserver;
-+ char *topart = ((struct xfer_user_rock *)rock)->topart;
-+ struct backend *be = ((struct xfer_user_rock *)rock)->be;
-+ char externalname[MAX_MAILBOX_NAME+1];
-+ int mbflags;
-+ int r = 0;
-+ char *inpath, *inpart, *inacl;
-+ char *path = NULL, *part = NULL, *acl = NULL;
-+
-+ if (!r) {
-+ /* NOTE: NOT mlookup() because we don't want to issue a referral */
-+ /* xxx but what happens if they are remote
-+ * mailboxes? */
-+ r = mboxlist_detail(name, &mbflags,
-+ &inpath, &inpart, &inacl, NULL);
-+ }
-+
-+ if (!r) {
-+ path = xstrdup(inpath);
-+ part = xstrdup(inpart);
-+ acl = xstrdup(inacl);
-+ }
-+
-+ if (!r) {
-+ r = (*imapd_namespace.mboxname_toexternal)(&imapd_namespace,
-+ name,
-+ imapd_userid,
-+ externalname);
-+ }
-+
-+ if(!r) {
-+ r = do_xfer_single(toserver, topart, externalname, name, mbflags,
-+ path, part, acl, 0, mupdate_h, be);
-+ }
-+
-+ if(path) free(path);
-+ if(part) free(part);
-+ if(acl) free(acl);
-+
-+ return r;
-+}
-+
-+
-+void cmd_xfer(char *tag, char *name, char *toserver, char *topart)
-+{
-+ int r = 0;
-+ char buf[MAX_PARTITION_LEN+HOSTNAME_SIZE+2];
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+ int mbflags;
-+ int moving_user = 0;
-+ int backout_mupdate = 0;
-+ mupdate_handle *mupdate_h = NULL;
-+ char *inpath, *inpart, *inacl;
-+ char *path = NULL, *part = NULL, *acl = NULL;
-+ char *p, *mbox = mailboxname;
-+
-+ /* administrators only please */
-+ /* however, proxys can do this, if their authzid is an admin */
-+ if (!imapd_userisadmin && !imapd_userisproxyadmin) {
-+ r = IMAP_PERMISSION_DENIED;
-+ }
-+
-+ if (!r) {
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace,
-+ name,
-+ imapd_userid,
-+ mailboxname);
-+ }
-+
-+ /* NOTE: Since XFER can only be used by an admin, and we always connect
-+ * to the destination backend as an admin, we take advantage of the fact
-+ * that admins *always* use a consistent mailbox naming scheme.
-+ * So, 'name' should be used in any command we send to a backend, and
-+ * 'mailboxname' is the internal name to be used for mupdate and findall.
-+ */
-+
-+ if (config_virtdomains && (p = strchr(mailboxname, '!'))) {
-+ /* pointer to mailbox w/o domain prefix */
-+ mbox = p + 1;
-+ }
-+
-+ if(!strncmp(mbox, "user.", 5) && !strchr(mbox+5, '.')) {
-+ if ((strlen(mbox+5) == (strlen(imapd_userid) - (mbox - mailboxname))) &&
-+ !strncmp(mbox+5, imapd_userid, strlen(mbox+5))) {
-+ /* don't move your own inbox, that could be troublesome */
-+ r = IMAP_MAILBOX_NOTSUPPORTED;
-+ } else if (!config_getswitch(IMAPOPT_ALLOWUSERMOVES)) {
-+ /* not configured to allow user moves */
-+ r = IMAP_MAILBOX_NOTSUPPORTED;
-+ } else {
-+ moving_user = 1;
-+ }
-+ }
-+
-+ if (!r) {
-+ r = mlookup(tag, name, mailboxname, &mbflags,
-+ &inpath, &inpart, &inacl, NULL);
-+ }
-+ if (r == IMAP_MAILBOX_MOVED) return;
-+
-+ if (!r) {
-+ path = xstrdup(inpath);
-+ part = xstrdup(inpart);
-+ acl = xstrdup(inacl);
-+ }
-+
-+ /* if we are not moving a user, just move the one mailbox */
-+ if(!r && !moving_user) {
-+ r = do_xfer_single(toserver, topart, name, mailboxname, mbflags,
-+ path, part, acl, 0, NULL, NULL);
-+ } else if (!r) {
-+ struct backend *be = NULL;
-+
-+ /* we need to reserve the users inbox - connect to mupdate */
-+ if(!r && config_mupdate_server) {
-+ r = mupdate_connect(config_mupdate_server, NULL, &mupdate_h, NULL);
-+ if(r) {
-+ syslog(LOG_ERR,
-+ "Could not move mailbox: %s, MUPDATE connect failed",
-+ mailboxname);
-+ goto done;
-+ }
-+ }
-+
-+ /* Get a single connection to the remote backend */
-+ be = backend_connect(NULL, toserver, &protocol[PROTOCOL_IMAP], "", NULL);
-+ if(!be) {
-+ r = IMAP_SERVER_UNAVAILABLE;
-+ syslog(LOG_ERR,
-+ "Could not move mailbox: %s, " \
-+ "Initial backend connect failed",
-+ mailboxname);
-+ }
-+
-+ /* deactivate their inbox */
-+ if(!r && mupdate_h) {
-+ /* Note we are making the reservation on OUR host so that recovery
-+ * make sense */
-+ snprintf(buf, sizeof(buf), "%s!%s", config_servername, part);
-+ r = mupdate_deactivate(mupdate_h, mailboxname, buf);
-+ if(r) syslog(LOG_ERR,
-+ "Could deactivate mailbox: %s, during move",
-+ mailboxname);
-+ else backout_mupdate = 1;
-+ }
-+
-+ /* If needed, set an uppermost quota root */
-+ if(!r) {
-+ struct quota quota;
-+
-+ quota.root = mailboxname;
-+ r = quota_read("a, NULL, 0);
-+
-+ if(!r) {
-+ /* note use of + to force the setting of a nonexistant
-+ * quotaroot */
-+ prot_printf(be->out, "Q01 SETQUOTA {%lu+}\r\n" \
-+ "+%s (STORAGE %d)\r\n",
-+ (unsigned long) strlen(name)+1,
-+ name, quota.limit);
-+ r = getresult(be->in, "Q01");
-+ if(r) syslog(LOG_ERR,
-+ "Could not move mailbox: %s, " \
-+ "failed setting initial quota root\r\n",
-+ mailboxname);
-+ }
-+ else if (r == IMAP_QUOTAROOT_NONEXISTENT) r = 0;
-+ }
-+
-+
-+ /* recursively move all sub-mailboxes, using internal names */
-+ if(!r) {
-+ struct xfer_user_rock rock;
-+
-+ rock.toserver = toserver;
-+ rock.topart = topart;
-+ rock.h = mupdate_h;
-+ rock.be = be;
-+
-+ snprintf(buf, sizeof(buf), "%s.*", mailboxname);
-+ r = mboxlist_findall(NULL, buf, 1, imapd_userid,
-+ imapd_authstate, xfer_user_cb,
-+ &rock);
-+ }
-+
-+ /* xxx how do you back out if one of the above moves fails? */
-+
-+ /* move this mailbox */
-+ /* ...and seen file, and subs file, and sieve scripts... */
-+ if(!r) {
-+ r = do_xfer_single(toserver, topart, name, mailboxname, mbflags,
-+ path, part, acl, 1, mupdate_h, be);
-+ }
-+
-+ if(be) {
-+ backend_disconnect(be, &protocol[PROTOCOL_IMAP]);
-+ free(be);
-+ }
-+
-+ if(r && mupdate_h && backout_mupdate) {
-+ int rerr = 0;
-+ /* xxx if the mupdate server is what failed, then this won't
-+ help any! */
-+ snprintf(buf, sizeof(buf), "%s!%s", config_servername, part);
-+ rerr = mupdate_activate(mupdate_h, mailboxname, buf, acl);
-+ if(rerr) {
-+ syslog(LOG_ERR,
-+ "Could not back out mupdate during move of %s (%s)",
-+ mailboxname, error_message(rerr));
-+ }
-+ } else if(!r) {
-+ /* this was a successful user delete, and we need to delete
-+ certain user meta-data (but not seen state!) */
-+ user_deletedata(mailboxname+5, imapd_userid, imapd_authstate, 0);
-+ }
-+
-+ if(!r && mupdate_h) {
-+ mupdate_disconnect(&mupdate_h);
-+ }
-+ }
-+
-+ done:
-+ if(part) free(part);
-+ if(path) free(path);
-+ if(acl) free(acl);
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n",
-+ tag,
-+ error_message(r));
-+ } else {
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ }
-+
-+ return;
-+}
-+
-+/*
-+ * Parse a "date", for SEARCH criteria
-+ * The time_t's pointed to by 'start' and 'end' are set to the
-+ * times of the start and end of the parsed date.
-+ */
-+int getsearchdate(start, end)
-+time_t *start, *end;
-+{
-+ int c;
-+ struct tm tm;
-+ int quoted = 0;
-+ char month[4];
-+
-+ memset(&tm, 0, sizeof tm);
-+
-+ c = prot_getc(imapd_in);
-+ if (c == '\"') {
-+ quoted++;
-+ c = prot_getc(imapd_in);
-+ }
-+
-+ /* Day of month */
-+ if (!isdigit(c)) goto baddate;
-+ tm.tm_mday = c - '0';
-+ c = prot_getc(imapd_in);
-+ if (isdigit(c)) {
-+ tm.tm_mday = tm.tm_mday * 10 + c - '0';
-+ c = prot_getc(imapd_in);
-+ }
-+
-+ if (c != '-') goto baddate;
-+ c = prot_getc(imapd_in);
-+
-+ /* Month name */
-+ if (!isalpha(c)) goto baddate;
-+ month[0] = c;
-+ c = prot_getc(imapd_in);
-+ if (!isalpha(c)) goto baddate;
-+ month[1] = c;
-+ c = prot_getc(imapd_in);
-+ if (!isalpha(c)) goto baddate;
-+ month[2] = c;
-+ c = prot_getc(imapd_in);
-+ month[3] = '\0';
-+ lcase(month);
-+
-+ for (tm.tm_mon = 0; tm.tm_mon < 12; tm.tm_mon++) {
-+ if (!strcmp(month, monthname[tm.tm_mon])) break;
-+ }
-+ if (tm.tm_mon == 12) goto baddate;
-+
-+ if (c != '-') goto baddate;
-+ c = prot_getc(imapd_in);
-+
-+ /* Year */
-+ if (!isdigit(c)) goto baddate;
-+ tm.tm_year = c - '0';
-+ c = prot_getc(imapd_in);
-+ if (!isdigit(c)) goto baddate;
-+ tm.tm_year = tm.tm_year * 10 + c - '0';
-+ c = prot_getc(imapd_in);
-+ if (isdigit(c)) {
-+ if (tm.tm_year < 19) goto baddate;
-+ tm.tm_year -= 19;
-+ tm.tm_year = tm.tm_year * 10 + c - '0';
-+ c = prot_getc(imapd_in);
-+ if (!isdigit(c)) goto baddate;
-+ tm.tm_year = tm.tm_year * 10 + c - '0';
-+ c = prot_getc(imapd_in);
-+ }
-+
-+ if (quoted) {
-+ if (c != '\"') goto baddate;
-+ c = prot_getc(imapd_in);
-+ }
-+
-+ tm.tm_isdst = -1;
-+ *start = mktime(&tm);
-+
-+ tm.tm_sec = tm.tm_min = 59;
-+ tm.tm_hour = 23;
-+ tm.tm_isdst = -1;
-+ *end = mktime(&tm);
-+
-+ return c;
-+
-+ baddate:
-+ prot_ungetc(c, imapd_in);
-+ return EOF;
-+}
-+
-+#define SORTGROWSIZE 10
-+
-+/*
-+ * Parse sort criteria
-+ */
-+int getsortcriteria(char *tag, struct sortcrit **sortcrit)
-+{
-+ int c;
-+ static struct buf criteria;
-+ int nsort, n;
-+
-+ *sortcrit = NULL;
-+
-+ c = prot_getc(imapd_in);
-+ if (c != '(') goto missingcrit;
-+
-+ c = getword(imapd_in, &criteria);
-+ if (criteria.s[0] == '\0') goto missingcrit;
-+
-+ nsort = 0;
-+ n = 0;
-+ for (;;) {
-+ if (n >= nsort - 1) { /* leave room for implicit criterion */
-+ /* (Re)allocate an array for sort criteria */
-+ nsort += SORTGROWSIZE;
-+ *sortcrit =
-+ (struct sortcrit *) xrealloc(*sortcrit,
-+ nsort * sizeof(struct sortcrit));
-+ /* Zero out the newly added sortcrit */
-+ memset((*sortcrit)+n, 0, SORTGROWSIZE * sizeof(struct sortcrit));
-+ }
-+
-+ lcase(criteria.s);
-+ if (!strcmp(criteria.s, "reverse")) {
-+ (*sortcrit)[n].flags |= SORT_REVERSE;
-+ goto nextcrit;
-+ }
-+ else if (!strcmp(criteria.s, "arrival"))
-+ (*sortcrit)[n].key = SORT_ARRIVAL;
-+ else if (!strcmp(criteria.s, "cc"))
-+ (*sortcrit)[n].key = SORT_CC;
-+ else if (!strcmp(criteria.s, "date"))
-+ (*sortcrit)[n].key = SORT_DATE;
-+ else if (!strcmp(criteria.s, "from"))
-+ (*sortcrit)[n].key = SORT_FROM;
-+ else if (!strcmp(criteria.s, "size"))
-+ (*sortcrit)[n].key = SORT_SIZE;
-+ else if (!strcmp(criteria.s, "subject"))
-+ (*sortcrit)[n].key = SORT_SUBJECT;
-+ else if (!strcmp(criteria.s, "to"))
-+ (*sortcrit)[n].key = SORT_TO;
-+#if 0
-+ else if (!strcmp(criteria.s, "annotation")) {
-+ (*sortcrit)[n].key = SORT_ANNOTATION;
-+ if (c != ' ') goto missingarg;
-+ c = getstring(imapd_in, &arg);
-+ if (c != ' ') goto missingarg;
-+ (*sortcrit)[n].args.annot.entry = xstrdup(arg.s);
-+ c = getstring(imapd_in, &arg);
-+ if (c == EOF) goto missingarg;
-+ (*sortcrit)[n].args.annot.attrib = xstrdup(arg.s);
-+ }
-+#endif
-+ else {
-+ prot_printf(imapd_out, "%s BAD Invalid Sort criterion %s\r\n",
-+ tag, criteria.s);
-+ if (c != EOF) prot_ungetc(c, imapd_in);
-+ return EOF;
-+ }
-+
-+ n++;
-+
-+ nextcrit:
-+ if (c == ' ') c = getword(imapd_in, &criteria);
-+ else break;
-+ }
-+
-+ if ((*sortcrit)[n].flags & SORT_REVERSE && !(*sortcrit)[n].key) {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing Sort criterion to reverse\r\n", tag);
-+ if (c != EOF) prot_ungetc(c, imapd_in);
-+ return EOF;
-+ }
-+
-+ if (c != ')') {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing close parenthesis in Sort\r\n", tag);
-+ if (c != EOF) prot_ungetc(c, imapd_in);
-+ return EOF;
-+ }
-+
-+ /* Terminate the list with the implicit sort criterion */
-+ (*sortcrit)[n++].key = SORT_SEQUENCE;
-+
-+ c = prot_getc(imapd_in);
-+
-+ return c;
-+
-+ missingcrit:
-+ prot_printf(imapd_out, "%s BAD Missing Sort criteria\r\n", tag);
-+ if (c != EOF) prot_ungetc(c, imapd_in);
-+ return EOF;
-+#if 0 /* For annotations stuff above */
-+ missingarg:
-+ prot_printf(imapd_out, "%s BAD Missing argument to Sort criterion %s\r\n",
-+ tag, criteria.s);
-+ if (c != EOF) prot_ungetc(c, imapd_in);
-+ return EOF;
-+#endif
-+}
-+
-+#ifdef ENABLE_LISTEXT
-+/*
-+ * Parse LIST options.
-+ * The command has been parsed up to and including the opening '('.
-+ */
-+int getlistopts(char *tag, int *listopts)
-+{
-+ int c;
-+ static struct buf arg;
-+
-+ *listopts = LIST_EXT;
-+
-+ for (;;) {
-+ c = getword(imapd_in, &arg);
-+ if (!arg.s[0]) break;
-+
-+ lcase(arg.s);
-+ if (!strcmp(arg.s, "subscribed")) {
-+ *listopts |= LIST_SUBSCRIBED;
-+ }
-+ else if (!strcmp(arg.s, "children")) {
-+ *listopts |= LIST_CHILDREN;
-+ }
-+ else if (!strcmp(arg.s, "remote")) {
-+ *listopts |= LIST_REMOTE;
-+ }
-+ else {
-+ prot_printf(imapd_out, "%s BAD Invalid List option %s\r\n",
-+ tag, arg.s);
-+ return EOF;
-+ }
-+
-+ if (c != ' ') break;
-+ }
-+
-+ if (c != ')') {
-+ prot_printf(imapd_out,
-+ "%s BAD Missing close parenthesis in List\r\n", tag);
-+ return EOF;
-+ }
-+
-+ c = prot_getc(imapd_in);
-+
-+ return c;
-+}
-+#endif /* ENABLE_LISTEXT */
-+
-+/*
-+ * Parse a date_time, for the APPEND command
-+ */
-+int getdatetime(date)
-+time_t *date;
-+{
-+ int c;
-+ struct tm tm;
-+ int old_format = 0;
-+ char month[4], zone[4], *p;
-+ time_t tmp_gmtime;
-+ int zone_off;
-+
-+ memset(&tm, 0, sizeof tm);
-+
-+ c = prot_getc(imapd_in);
-+ if (c != '\"') goto baddate;
-+
-+ /* Day of month */
-+ c = prot_getc(imapd_in);
-+ if (c == ' ') c = '0';
-+ if (!isdigit(c)) goto baddate;
-+ tm.tm_mday = c - '0';
-+ c = prot_getc(imapd_in);
-+ if (isdigit(c)) {
-+ tm.tm_mday = tm.tm_mday * 10 + c - '0';
-+ c = prot_getc(imapd_in);
-+ if(tm.tm_mday <= 0 || tm.tm_mday > 31)
-+ goto baddate;
-+ }
-+
-+ if (c != '-') goto baddate;
-+ c = prot_getc(imapd_in);
-+
-+ /* Month name */
-+ if (!isalpha(c)) goto baddate;
-+ month[0] = c;
-+ c = prot_getc(imapd_in);
-+ if (!isalpha(c)) goto baddate;
-+ month[1] = c;
-+ c = prot_getc(imapd_in);
-+ if (!isalpha(c)) goto baddate;
-+ month[2] = c;
-+ c = prot_getc(imapd_in);
-+ month[3] = '\0';
-+ lcase(month);
-+
-+ for (tm.tm_mon = 0; tm.tm_mon < 12; tm.tm_mon++) {
-+ if (!strcmp(month, monthname[tm.tm_mon])) break;
-+ }
-+ if (tm.tm_mon == 12) goto baddate;
-+ /* xxx this doesn't quite work in leap years */
-+ if (tm.tm_mday > max_monthdays[tm.tm_mon]) goto baddate;
-+
-+ if (c != '-') goto baddate;
-+ c = prot_getc(imapd_in);
-+
-+ /* Year */
-+ if (!isdigit(c)) goto baddate;
-+ tm.tm_year = c - '0';
-+ c = prot_getc(imapd_in);
-+ if (!isdigit(c)) goto baddate;
-+ tm.tm_year = tm.tm_year * 10 + c - '0';
-+ c = prot_getc(imapd_in);
-+ if (isdigit(c)) {
-+ if (tm.tm_year < 19) goto baddate;
-+ tm.tm_year -= 19;
-+ tm.tm_year = tm.tm_year * 10 + c - '0';
-+ c = prot_getc(imapd_in);
-+ if (!isdigit(c)) goto baddate;
-+ tm.tm_year = tm.tm_year * 10 + c - '0';
-+ c = prot_getc(imapd_in);
-+ }
-+ else old_format++;
-+
-+ /* Hour */
-+ if (c != ' ') goto baddate;
-+ c = prot_getc(imapd_in);
-+ if (!isdigit(c)) goto baddate;
-+ tm.tm_hour = c - '0';
-+ c = prot_getc(imapd_in);
-+ if (!isdigit(c)) goto baddate;
-+ tm.tm_hour = tm.tm_hour * 10 + c - '0';
-+ c = prot_getc(imapd_in);
-+ if (tm.tm_hour > 23) goto baddate;
-+
-+ /* Minute */
-+ if (c != ':') goto baddate;
-+ c = prot_getc(imapd_in);
-+ if (!isdigit(c)) goto baddate;
-+ tm.tm_min = c - '0';
-+ c = prot_getc(imapd_in);
-+ if (!isdigit(c)) goto baddate;
-+ tm.tm_min = tm.tm_min * 10 + c - '0';
-+ c = prot_getc(imapd_in);
-+ if (tm.tm_min > 59) goto baddate;
-+
-+ /* Second */
-+ if (c != ':') goto baddate;
-+ c = prot_getc(imapd_in);
-+ if (!isdigit(c)) goto baddate;
-+ tm.tm_sec = c - '0';
-+ c = prot_getc(imapd_in);
-+ if (!isdigit(c)) goto baddate;
-+ tm.tm_sec = tm.tm_sec * 10 + c - '0';
-+ c = prot_getc(imapd_in);
-+ if (tm.tm_min > 60) goto baddate;
-+
-+ /* Time zone */
-+ if (old_format) {
-+ if (c != '-') goto baddate;
-+ c = prot_getc(imapd_in);
-+
-+ if (!isalpha(c)) goto baddate;
-+ zone[0] = c;
-+ c = prot_getc(imapd_in);
-+
-+ if (c == '\"') {
-+ /* Military (single-char) zones */
-+ zone[1] = '\0';
-+ lcase(zone);
-+ if (zone[0] <= 'm') {
-+ zone_off = (zone[0] - 'a' + 1)*60;
-+ }
-+ else if (zone[0] < 'z') {
-+ zone_off = ('m' - zone[0])*60;
-+ }
-+ else zone_off = 0;
-+ }
-+ else {
-+ /* UT (universal time) */
-+ zone[1] = c;
-+ c = prot_getc(imapd_in);
-+ if (c == '\"') {
-+ zone[2] = '\0';
-+ lcase(zone);
-+ if (!strcmp(zone, "ut")) goto baddate;
-+ zone_off = 0;
-+ }
-+ else {
-+ /* 3-char time zone */
-+ zone[2] = c;
-+ c = prot_getc(imapd_in);
-+ if (c != '\"') goto baddate;
-+ zone[3] = '\0';
-+ lcase(zone);
-+ p = strchr("aecmpyhb", zone[0]);
-+ if (c != '\"' || zone[2] != 't' || !p) goto baddate;
-+ zone_off = (strlen(p) - 12)*60;
-+ if (zone[1] == 'd') zone_off -= 60;
-+ else if (zone[1] != 's') goto baddate;
-+ }
-+ }
-+ }
-+ else {
-+ if (c != ' ') goto baddate;
-+ c = prot_getc(imapd_in);
-+
-+ if (c != '+' && c != '-') goto baddate;
-+ zone[0] = c;
-+
-+ c = prot_getc(imapd_in);
-+ if (!isdigit(c)) goto baddate;
-+ zone_off = c - '0';
-+ c = prot_getc(imapd_in);
-+ if (!isdigit(c)) goto baddate;
-+ zone_off = zone_off * 10 + c - '0';
-+ c = prot_getc(imapd_in);
-+ if (!isdigit(c)) goto baddate;
-+ zone_off = zone_off * 6 + c - '0';
-+ c = prot_getc(imapd_in);
-+ if (!isdigit(c)) goto baddate;
-+ zone_off = zone_off * 10 + c - '0';
-+
-+ if (zone[0] == '-') zone_off = -zone_off;
-+
-+ c = prot_getc(imapd_in);
-+ if (c != '\"') goto baddate;
-+
-+ }
-+
-+ c = prot_getc(imapd_in);
-+
-+ tm.tm_isdst = -1;
-+
-+ tmp_gmtime = mkgmtime(&tm);
-+ if(tmp_gmtime == -1) goto baddate;
-+
-+ *date = tmp_gmtime - zone_off*60;
-+
-+ return c;
-+
-+ baddate:
-+ prot_ungetc(c, imapd_in);
-+ return EOF;
-+}
-+
-+/*
-+ * Print 's' as a quoted-string or literal (but not an atom)
-+ */
-+void
-+printstring(s)
-+const char *s;
-+{
-+ const char *p;
-+ int len = 0;
-+
-+ /* Look for any non-QCHAR characters */
-+ for (p = s; *p && len < 1024; p++) {
-+ len++;
-+ if (*p & 0x80 || *p == '\r' || *p == '\n'
-+ || *p == '\"' || *p == '%' || *p == '\\') break;
-+ }
-+
-+ /* if it's too long, literal it */
-+ if (*p || len >= 1024) {
-+ prot_printf(imapd_out, "{%lu}\r\n%s", (unsigned long) strlen(s), s);
-+ } else {
-+ prot_printf(imapd_out, "\"%s\"", s);
-+ }
-+}
-+
-+/*
-+ * Print 's' as an atom, quoted-string, or literal
-+ */
-+void
-+printastring(s)
-+const char *s;
-+{
-+ const char *p;
-+ int len = 0;
-+
-+ if (imparse_isatom(s)) {
-+ prot_printf(imapd_out, "%s", s);
-+ return;
-+ }
-+
-+ /* Look for any non-QCHAR characters */
-+ for (p = s; *p && len < 1024; p++) {
-+ len++;
-+ if (*p & 0x80 || *p == '\r' || *p == '\n'
-+ || *p == '\"' || *p == '%' || *p == '\\') break;
-+ }
-+
-+ /* if it's too long, literal it */
-+ if (*p || len >= 1024) {
-+ prot_printf(imapd_out, "{%lu}\r\n%s", (unsigned long) strlen(s), s);
-+ } else {
-+ prot_printf(imapd_out, "\"%s\"", s);
-+ }
-+}
-+
-+/*
-+ * Append 'section', 'fields', 'trail' to the fieldlist 'l'.
-+ */
-+void
-+appendfieldlist(struct fieldlist **l, char *section,
-+ struct strlist *fields, char *trail,
-+ void *d, size_t size)
-+{
-+ struct fieldlist **tail = l;
-+
-+ while (*tail) tail = &(*tail)->next;
-+
-+ *tail = (struct fieldlist *)xmalloc(sizeof(struct fieldlist));
-+ (*tail)->section = xstrdup(section);
-+ (*tail)->fields = fields;
-+ (*tail)->trail = xstrdup(trail);
-+ if(d && size) {
-+ (*tail)->rock = xmalloc(size);
-+ memcpy((*tail)->rock, d, size);
-+ } else {
-+ (*tail)->rock = NULL;
-+ }
-+ (*tail)->next = 0;
-+}
-+
-+
-+/*
-+ * Free the fieldlist 'l'
-+ */
-+void freefieldlist(struct fieldlist *l)
-+{
-+ struct fieldlist *n;
-+
-+ while (l) {
-+ n = l->next;
-+ free(l->section);
-+ freestrlist(l->fields);
-+ free(l->trail);
-+ if (l->rock) free(l->rock);
-+ free((char *)l);
-+ l = n;
-+ }
-+}
-+
-+/*
-+ * Append the searchargs 's1' and 's2' to the sublist of 's'
-+ */
-+void
-+appendsearchargs(s, s1, s2)
-+struct searchargs *s, *s1, *s2;
-+{
-+ struct searchsub **tail = &s->sublist;
-+
-+ while (*tail) tail = &(*tail)->next;
-+
-+ *tail = (struct searchsub *)xmalloc(sizeof(struct searchsub));
-+ (*tail)->sub1 = s1;
-+ (*tail)->sub2 = s2;
-+ (*tail)->next = 0;
-+}
-+
-+
-+/*
-+ * Free the searchargs 's'
-+ */
-+void
-+freesearchargs(s)
-+struct searchargs *s;
-+{
-+ struct searchsub *sub, *n;
-+
-+ if (!s) return;
-+
-+ freestrlist(s->sequence);
-+ freestrlist(s->uidsequence);
-+ freestrlist(s->from);
-+ freestrlist(s->to);
-+ freestrlist(s->cc);
-+ freestrlist(s->bcc);
-+ freestrlist(s->subject);
-+ freestrlist(s->body);
-+ freestrlist(s->text);
-+ freestrlist(s->header_name);
-+ freestrlist(s->header);
-+
-+ for (sub = s->sublist; sub; sub = n) {
-+ n = sub->next;
-+ freesearchargs(sub->sub1);
-+ freesearchargs(sub->sub2);
-+ free(sub);
-+ }
-+ free(s);
-+}
-+
-+/*
-+ * Free an array of sortcrit
-+ */
-+static void freesortcrit(struct sortcrit *s)
-+{
-+ int i = 0;
-+
-+ if (!s) return;
-+ do {
-+ switch (s[i].key) {
-+ case SORT_ANNOTATION:
-+ free(s[i].args.annot.entry);
-+ free(s[i].args.annot.attrib);
-+ break;
-+ }
-+ i++;
-+ } while (s[i].key != SORT_SEQUENCE);
-+ free(s);
-+}
-+
-+/*
-+ * Issue a MAILBOX untagged response
-+ */
-+static int mailboxdata(char *name,
-+ int matchlen __attribute__((unused)),
-+ int maycreate __attribute__((unused)),
-+ void *rock __attribute__((unused)))
-+{
-+ char mboxname[MAX_MAILBOX_PATH+1];
-+
-+ (*imapd_namespace.mboxname_toexternal)(&imapd_namespace, name,
-+ imapd_userid, mboxname);
-+ prot_printf(imapd_out, "* MAILBOX %s\r\n", mboxname);
-+ return 0;
-+}
-+
-+/*
-+ * Issue a LIST or LSUB untagged response
-+ */
-+static void mstringdata(char *cmd, char *name, int matchlen, int maycreate,
-+ int listopts)
-+{
-+ static char lastname[MAX_MAILBOX_PATH+1];
-+ static int lastnamedelayed = 0;
-+ static int lastnamenoinferiors = 0;
-+ static int nonexistent = 0;
-+ static int sawuser = 0;
-+ int lastnamehassub = 0;
-+ int c, mbtype;
-+ char mboxname[MAX_MAILBOX_PATH+1];
-+
-+ /* We have to reset the sawuser flag before each list command.
-+ * Handle it as a dirty hack.
-+ */
-+ if (cmd == NULL) {
-+ sawuser = 0;
-+ mstringdatacalls = 0;
-+ return;
-+ }
-+ mstringdatacalls++;
-+
-+ if (lastnamedelayed) {
-+ /* Check if lastname has children */
-+ if (name && strncmp(lastname, name, strlen(lastname)) == 0 &&
-+ name[strlen(lastname)] == '.') {
-+ lastnamehassub = 1;
-+ }
-+ prot_printf(imapd_out, "* %s (", cmd);
-+ if (nonexistent == IMAP_MAILBOX_RESERVED) {
-+ /* LISTEXT wants \\PlaceHolder instead of \\Noselect */
-+ if (listopts & LIST_EXT)
-+ prot_printf(imapd_out, "\\PlaceHolder");
-+ else
-+ prot_printf(imapd_out, "\\Noselect");
-+ } else if (nonexistent) {
-+ prot_printf(imapd_out, "\\NonExistent");
-+ }
-+ if (lastnamenoinferiors) {
-+ prot_printf(imapd_out, "%s\\Noinferiors", nonexistent ? " " : "");
-+ }
-+ else if ((listopts & LIST_CHILDREN) &&
-+ /* we can't determine \HasNoChildren for subscriptions */
-+ (lastnamehassub ||
-+ !(listopts & (LIST_LSUB | LIST_SUBSCRIBED)))) {
-+ prot_printf(imapd_out, "%s%s", nonexistent ? " " : "",
-+ lastnamehassub ? "\\HasChildren" : "\\HasNoChildren");
-+ }
-+ prot_printf(imapd_out, ") \"%c\" ", imapd_namespace.hier_sep);
-+
-+ (*imapd_namespace.mboxname_toexternal)(&imapd_namespace, lastname,
-+ imapd_userid, mboxname);
-+ printstring(mboxname);
-+ prot_printf(imapd_out, "\r\n");
-+ lastnamedelayed = lastnamenoinferiors = nonexistent = 0;
-+ }
-+
-+ /* Special-case to flush any final state */
-+ if (!name) {
-+ lastname[0] = '\0';
-+ return;
-+ }
-+
-+ /* Suppress any output of a partial match */
-+ if ((name[matchlen]
-+ && strncmp(lastname, name, matchlen) == 0
-+ && (lastname[matchlen] == '\0' || lastname[matchlen] == '.'))) {
-+ return;
-+ }
-+
-+ /*
-+ * We can get a partial match for "user" multiple times with
-+ * other matches inbetween. Handle it as a special case
-+ */
-+ if (matchlen == 4 && strncasecmp(name, "user", 4) == 0) {
-+ if (sawuser) return;
-+ sawuser = 1;
-+ }
-+
-+ strlcpy(lastname, name, sizeof(lastname));
-+ lastname[matchlen] = '\0';
-+ nonexistent = 0;
-+
-+ /* Now we need to see if this mailbox exists */
-+ /* first convert "INBOX" to "user.<userid>" */
-+ if (!strncasecmp(lastname, "inbox", 5)) {
-+ (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, "INBOX",
-+ imapd_userid, mboxname);
-+ strlcat(mboxname, lastname+5, sizeof(mboxname));
-+ }
-+ else
-+ strlcpy(mboxname, lastname, sizeof(mboxname));
-+
-+ /* Look it up */
-+ nonexistent = mboxlist_detail(mboxname, &mbtype,
-+ NULL, NULL, NULL, NULL);
-+ if(!nonexistent && (mbtype & MBTYPE_RESERVE))
-+ nonexistent = IMAP_MAILBOX_RESERVED;
-+
-+ if (!name[matchlen]) {
-+ lastnamedelayed = 1;
-+ if (!maycreate) lastnamenoinferiors = 1;
-+ return;
-+ }
-+
-+ c = name[matchlen];
-+ if (c) name[matchlen] = '\0';
-+ prot_printf(imapd_out, "* %s (", cmd);
-+ if (c) {
-+ /* Handle namespace prefix as a special case */
-+ if (!strcmp(name, "user") ||
-+ !strcmp(name, imapd_namespace.prefix[NAMESPACE_SHARED])) {
-+ prot_printf(imapd_out, "\\Noselect");
-+ if (listopts & LIST_EXT)
-+ prot_printf(imapd_out, " \\PlaceHolder");
-+ }
-+ else {
-+ if (nonexistent)
-+ prot_printf(imapd_out, "\\NonExistent");
-+ /* LISTEXT uses \PlaceHolder instead of \Noselect */
-+ if (listopts & LIST_EXT)
-+ prot_printf(imapd_out, "%s\\PlaceHolder", nonexistent ? " " : "");
-+ else
-+ prot_printf(imapd_out, "%s\\Noselect", nonexistent ? " " : "");
-+ }
-+ if (listopts & LIST_CHILDREN)
-+ prot_printf(imapd_out, " \\HasChildren");
-+ }
-+ prot_printf(imapd_out, ") \"%c\" ", imapd_namespace.hier_sep);
-+
-+ (*imapd_namespace.mboxname_toexternal)(&imapd_namespace, name,
-+ imapd_userid, mboxname);
-+ printstring(mboxname);
-+ prot_printf(imapd_out, "\r\n");
-+ if (c) name[matchlen] = c;
-+ return;
-+}
-+
-+/*
-+ * Issue a LIST untagged response
-+ */
-+static int listdata(char *name, int matchlen, int maycreate, void *rock)
-+{
-+ int listopts = *((int *)rock);
-+
-+ mstringdata(((listopts & LIST_LSUB) ? "LSUB" : "LIST"),
-+ name, matchlen, maycreate, listopts);
-+
-+ return 0;
-+}
-+
-+/* Reset the given sasl_conn_t to a sane state */
-+static int reset_saslconn(sasl_conn_t **conn)
-+{
-+ int ret;
-+ sasl_security_properties_t *secprops = NULL;
-+
-+ sasl_dispose(conn);
-+ /* do initialization typical of service_main */
-+ ret = sasl_server_new("imap", config_servername,
-+ NULL, NULL, NULL,
-+ NULL, 0, conn);
-+ if(ret != SASL_OK) return ret;
-+
-+ if(saslprops.ipremoteport)
-+ ret = sasl_setprop(*conn, SASL_IPREMOTEPORT,
-+ saslprops.ipremoteport);
-+ if(ret != SASL_OK) return ret;
-+
-+ if(saslprops.iplocalport)
-+ ret = sasl_setprop(*conn, SASL_IPLOCALPORT,
-+ saslprops.iplocalport);
-+ if(ret != SASL_OK) return ret;
-+
-+ secprops = mysasl_secprops(SASL_SEC_NOPLAINTEXT);
-+ ret = sasl_setprop(*conn, SASL_SEC_PROPS, secprops);
-+ if(ret != SASL_OK) return ret;
-+ /* end of service_main initialization excepting SSF */
-+
-+ /* If we have TLS/SSL info, set it */
-+ if(saslprops.ssf) {
-+ ret = sasl_setprop(*conn, SASL_SSF_EXTERNAL, &saslprops.ssf);
-+ } else {
-+ ret = sasl_setprop(*conn, SASL_SSF_EXTERNAL, &extprops_ssf);
-+ }
-+ if(ret != SASL_OK) return ret;
-+
-+ if(saslprops.authid) {
-+ ret = sasl_setprop(*conn, SASL_AUTH_EXTERNAL, saslprops.authid);
-+ if(ret != SASL_OK) return ret;
-+ }
-+ /* End TLS/SSL Info */
-+
-+ return SASL_OK;
-+}
-+
-+void cmd_mupdatepush(char *tag, char *name)
-+{
-+ int r = 0;
-+ char mailboxname[MAX_MAILBOX_NAME+1];
-+ char *part, *acl;
-+ mupdate_handle *mupdate_h = NULL;
-+ char buf[MAX_PARTITION_LEN + HOSTNAME_SIZE + 2];
-+
-+ if (!imapd_userisadmin) {
-+ r = IMAP_PERMISSION_DENIED;
-+ }
-+ if (!config_mupdate_server) {
-+ r = IMAP_SERVER_UNAVAILABLE;
-+ }
-+
-+ if (!r) {
-+ r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
-+ imapd_userid, mailboxname);
-+ }
-+
-+ if (!r) {
-+ r = mlookup(tag, name, mailboxname, NULL, NULL, &part, &acl, NULL);
-+ }
-+ if (r == IMAP_MAILBOX_MOVED) return;
-+
-+ /* Push mailbox to mupdate server */
-+ if (!r) {
-+ r = mupdate_connect(config_mupdate_server, NULL, &mupdate_h, NULL);
-+ }
-+
-+ if (!r) {
-+ snprintf(buf, sizeof(buf), "%s!%s", config_servername, part);
-+
-+ r = mupdate_activate(mupdate_h, mailboxname, buf, acl);
-+ }
-+
-+ if(mupdate_h) {
-+ mupdate_disconnect(&mupdate_h);
-+ }
-+
-+ if (r) {
-+ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
-+ }
-+ else {
-+ prot_printf(imapd_out, "%s OK %s\r\n", tag,
-+ error_message(IMAP_OK_COMPLETED));
-+ }
-+}
-diff -urNad cyrus-imapd-2.2.12/imap/pop3d.c /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/imap/pop3d.c
---- cyrus-imapd-2.2.12/imap/pop3d.c 2005-05-24 20:41:38.000000000 +0200
-+++ /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/imap/pop3d.c 2005-05-24 20:45:11.558995840 +0200
+diff -urNad cyrus-imapd-2.2.12/imap/pop3d.c /tmp/dpep.MaSf95/cyrus-imapd-2.2.12/imap/pop3d.c
+--- cyrus-imapd-2.2.12/imap/pop3d.c 2005-05-24 22:16:17.000000000 +0200
++++ /tmp/dpep.MaSf95/cyrus-imapd-2.2.12/imap/pop3d.c 2005-05-25 00:50:08.172163065 +0200
@@ -44,6 +44,10 @@
*/
#include <config.h>
@@ -9471,1676 +261,9 @@
}
/* Create telemetry log */
-diff -urNad cyrus-imapd-2.2.12/imap/pop3d.c.orig /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/imap/pop3d.c.orig
---- cyrus-imapd-2.2.12/imap/pop3d.c.orig 1970-01-01 01:00:00.000000000 +0100
-+++ /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/imap/pop3d.c.orig 2005-05-24 20:41:38.000000000 +0200
-@@ -0,0 +1,1663 @@
-+/* pop3d.c -- POP3 server protocol parsing
-+ *
-+ * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ *
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ *
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in
-+ * the documentation and/or other materials provided with the
-+ * distribution.
-+ *
-+ * 3. The name "Carnegie Mellon University" must not be used to
-+ * endorse or promote products derived from this software without
-+ * prior written permission. For permission or any other legal
-+ * details, please contact
-+ * Office of Technology Transfer
-+ * Carnegie Mellon University
-+ * 5000 Forbes Avenue
-+ * Pittsburgh, PA 15213-3890
-+ * (412) 268-4387, fax: (412) 268-7395
-+ * tech-transfer at andrew.cmu.edu
-+ *
-+ * 4. Redistributions of any form whatsoever must retain the following
-+ * acknowledgment:
-+ * "This product includes software developed by Computing Services
-+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
-+ *
-+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
-+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
-+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
-+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
-+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+/*
-+ * $Id: pop3d.c,v 1.166 2005/01/04 15:06:13 ken3 Exp $
-+ */
-+#include <config.h>
-+
-+
-+#ifdef HAVE_UNISTD_H
-+#include <unistd.h>
-+#endif
-+#include <stdio.h>
-+#include <errno.h>
-+#include <string.h>
-+#include <fcntl.h>
-+#include <signal.h>
-+#include <assert.h>
-+#include <sys/types.h>
-+#include <sys/param.h>
-+#include <syslog.h>
-+#include <netdb.h>
-+#include <sys/socket.h>
-+#include <netinet/in.h>
-+#include <arpa/inet.h>
-+#include <ctype.h>
-+#include "prot.h"
-+
-+#include <sasl/sasl.h>
-+#include <sasl/saslutil.h>
-+
-+#include "acl.h"
-+#include "util.h"
-+#include "auth.h"
-+#include "iptostring.h"
-+#include "global.h"
-+#include "tls.h"
-+
-+#include "exitcodes.h"
-+#include "imap_err.h"
-+#include "mailbox.h"
-+#include "version.h"
-+#include "xmalloc.h"
-+#include "mboxlist.h"
-+#include "idle.h"
-+#include "telemetry.h"
-+#include "backend.h"
-+
-+#ifdef HAVE_KRB
-+/* kerberos des is purported to conflict with OpenSSL DES */
-+#define DES_DEFS
-+#include <krb.h>
-+
-+/* MIT's kpop authentication kludge */
-+char klrealm[REALM_SZ];
-+AUTH_DAT kdata;
-+#endif /* HAVE_KRB */
-+static int kflag = 0;
-+
-+extern int optind;
-+extern char *optarg;
-+extern int opterr;
-+
-+#ifdef HAVE_SSL
-+static SSL *tls_conn;
-+#endif /* HAVE_SSL */
-+
-+sasl_conn_t *popd_saslconn; /* the sasl connection context */
-+
-+char *popd_userid = 0;
-+struct mailbox *popd_mailbox = 0;
-+struct auth_state *popd_authstate = 0;
-+int config_popuseacl;
-+struct sockaddr_storage popd_localaddr, popd_remoteaddr;
-+int popd_haveaddr = 0;
-+char popd_clienthost[NI_MAXHOST*2+1] = "[local]";
-+struct protstream *popd_out = NULL;
-+struct protstream *popd_in = NULL;
-+static int popd_logfd = -1;
-+unsigned popd_exists = 0;
-+unsigned popd_login_time;
-+struct msg {
-+ unsigned uid;
-+ unsigned size;
-+ int deleted;
-+} *popd_msg = NULL;
-+
-+static int pop3s = 0;
-+int popd_starttls_done = 0;
-+
-+static struct mailbox mboxstruct;
-+
-+static mailbox_decideproc_t expungedeleted;
-+
-+/* the sasl proxy policy context */
-+static struct proxy_context popd_proxyctx = {
-+ 0, 1, &popd_authstate, NULL, NULL
-+};
-+
-+/* signal to config.c */
-+const int config_need_data = CONFIG_NEED_PARTITION_DATA;
-+
-+/* current namespace */
-+static struct namespace popd_namespace;
-+
-+/* PROXY stuff */
-+struct backend *backend = NULL;
-+
-+static void bitpipe(void);
-+/* end PROXY stuff */
-+
-+static char popd_apop_chal[45 + MAXHOSTNAMELEN + 1]; /* <rand.time at hostname> */
-+static void cmd_apop(char *response);
-+
-+static void cmd_auth(char *arg);
-+static void cmd_capa(void);
-+static void cmd_pass(char *pass);
-+static void cmd_user(char *user);
-+static void cmd_starttls(int pop3s);
-+static void blat(int msg,int lines);
-+static int openinbox(void);
-+static void cmdloop(void);
-+static void kpop(void);
-+static int parsenum(char **ptr);
-+void usage(void);
-+void shut_down(int code) __attribute__ ((noreturn));
-+
-+
-+extern void setproctitle_init(int argc, char **argv, char **envp);
-+extern int proc_register(const char *progname, const char *clienthost,
-+ const char *userid, const char *mailbox);
-+extern void proc_cleanup(void);
-+
-+extern int saslserver(sasl_conn_t *conn, const char *mech,
-+ const char *init_resp, const char *resp_prefix,
-+ const char *continuation, const char *empty_chal,
-+ struct protstream *pin, struct protstream *pout,
-+ int *sasl_result, char **success_data);
-+
-+/* Enable the resetting of a sasl_conn_t */
-+static int reset_saslconn(sasl_conn_t **conn);
-+
-+static struct
-+{
-+ char *ipremoteport;
-+ char *iplocalport;
-+ sasl_ssf_t ssf;
-+ char *authid;
-+} saslprops = {NULL,NULL,0,NULL};
-+
-+static struct sasl_callback mysasl_cb[] = {
-+ { SASL_CB_GETOPT, &mysasl_config, NULL },
-+ { SASL_CB_PROXY_POLICY, &mysasl_proxy_policy, (void*) &popd_proxyctx },
-+ { SASL_CB_CANON_USER, &mysasl_canon_user, NULL },
-+ { SASL_CB_LIST_END, NULL, NULL }
-+};
-+
-+static void popd_reset(void)
-+{
-+ proc_cleanup();
-+
-+ /* close local mailbox */
-+ if (popd_mailbox) {
-+ mailbox_close(popd_mailbox);
-+ popd_mailbox = 0;
-+ }
-+
-+ /* close backend connection */
-+ if (backend) {
-+ backend_disconnect(backend, &protocol[PROTOCOL_POP3]);
-+ free(backend);
-+ backend = NULL;
-+ }
-+
-+ if (popd_in) {
-+ prot_NONBLOCK(popd_in);
-+ prot_fill(popd_in);
-+
-+ prot_free(popd_in);
-+ }
-+
-+ if (popd_out) {
-+ prot_flush(popd_out);
-+ prot_free(popd_out);
-+ }
-+
-+ popd_in = popd_out = NULL;
-+
-+#ifdef HAVE_SSL
-+ if (tls_conn) {
-+ tls_reset_servertls(&tls_conn);
-+ tls_conn = NULL;
-+ }
-+#endif
-+
-+ cyrus_reset_stdio();
-+
-+ strcpy(popd_clienthost, "[local]");
-+ if (popd_logfd != -1) {
-+ close(popd_logfd);
-+ popd_logfd = -1;
-+ }
-+ if (popd_userid != NULL) {
-+ free(popd_userid);
-+ popd_userid = NULL;
-+ }
-+ if (popd_authstate) {
-+ auth_freestate(popd_authstate);
-+ popd_authstate = NULL;
-+ }
-+ if (popd_saslconn) {
-+ sasl_dispose(&popd_saslconn);
-+ popd_saslconn = NULL;
-+ }
-+ popd_starttls_done = 0;
-+
-+ if(saslprops.iplocalport) {
-+ free(saslprops.iplocalport);
-+ saslprops.iplocalport = NULL;
-+ }
-+ if(saslprops.ipremoteport) {
-+ free(saslprops.ipremoteport);
-+ saslprops.ipremoteport = NULL;
-+ }
-+ if(saslprops.authid) {
-+ free(saslprops.authid);
-+ saslprops.authid = NULL;
-+ }
-+ saslprops.ssf = 0;
-+
-+ popd_exists = 0;
-+}
-+
-+/*
-+ * run once when process is forked;
-+ * MUST NOT exit directly; must return with non-zero error code
-+ */
-+int service_init(int argc __attribute__((unused)),
-+ char **argv __attribute__((unused)),
-+ char **envp __attribute__((unused)))
-+{
-+ int r;
-+ int opt;
-+
-+ if (geteuid() == 0) fatal("must run as the Cyrus user", EC_USAGE);
-+ setproctitle_init(argc, argv, envp);
-+
-+ /* set signal handlers */
-+ signals_set_shutdown(&shut_down);
-+ signal(SIGPIPE, SIG_IGN);
-+
-+ /* load the SASL plugins */
-+ global_sasl_init(1, 1, mysasl_cb);
-+
-+ /* open the mboxlist, we'll need it for real work */
-+ mboxlist_init(0);
-+ mboxlist_open(NULL);
-+
-+ /* open the quota db, we'll need it for expunge */
-+ quotadb_init(0);
-+ quotadb_open(NULL);
-+
-+ /* setup for sending IMAP IDLE notifications */
-+ idle_enabled();
-+
-+ /* Set namespace */
-+ if ((r = mboxname_init_namespace(&popd_namespace, 0)) != 0) {
-+ syslog(LOG_ERR, error_message(r));
-+ fatal(error_message(r), EC_CONFIG);
-+ }
-+
-+ while ((opt = getopt(argc, argv, "sk")) != EOF) {
-+ switch(opt) {
-+ case 's': /* pop3s (do starttls right away) */
-+ pop3s = 1;
-+ if (!tls_enabled()) {
-+ syslog(LOG_ERR, "pop3s: required OpenSSL options not present");
-+ fatal("pop3s: required OpenSSL options not present",
-+ EC_CONFIG);
-+ }
-+ break;
-+
-+ case 'k':
-+ kflag++;
-+ break;
-+ default:
-+ usage();
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * run for each accepted connection
-+ */
-+int service_main(int argc __attribute__((unused)),
-+ char **argv __attribute__((unused)),
-+ char **envp __attribute__((unused)))
-+{
-+ socklen_t salen;
-+ char hbuf[NI_MAXHOST];
-+ char localip[60], remoteip[60];
-+ int niflags;
-+ int timeout;
-+ sasl_security_properties_t *secprops=NULL;
-+
-+ signals_poll();
-+
-+ popd_in = prot_new(0, 0);
-+ popd_out = prot_new(1, 1);
-+
-+ /* Find out name of client host */
-+ salen = sizeof(popd_remoteaddr);
-+ if (getpeername(0, (struct sockaddr *)&popd_remoteaddr, &salen) == 0 &&
-+ (popd_remoteaddr.ss_family == AF_INET ||
-+ popd_remoteaddr.ss_family == AF_INET6)) {
-+ if (getnameinfo((struct sockaddr *)&popd_remoteaddr, salen,
-+ hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD) == 0) {
-+ strncpy(popd_clienthost, hbuf, sizeof(hbuf));
-+ strlcat(popd_clienthost, " ", sizeof(popd_clienthost));
-+ } else {
-+ popd_clienthost[0] = '\0';
-+ }
-+ niflags = NI_NUMERICHOST;
-+#ifdef NI_WITHSCOPEID
-+ if (((struct sockaddr *)&popd_remoteaddr)->sa_family == AF_INET6)
-+ niflags |= NI_WITHSCOPEID;
-+#endif
-+ if (getnameinfo((struct sockaddr *)&popd_remoteaddr, salen, hbuf,
-+ sizeof(hbuf), NULL, 0, niflags) != 0)
-+ strlcpy(hbuf, "unknown", sizeof(hbuf));
-+ strlcat(popd_clienthost, "[", sizeof(popd_clienthost));
-+ strlcat(popd_clienthost, hbuf, sizeof(popd_clienthost));
-+ strlcat(popd_clienthost, "]", sizeof(popd_clienthost));
-+ salen = sizeof(popd_localaddr);
-+ if (getsockname(0, (struct sockaddr *)&popd_localaddr, &salen) == 0) {
-+ popd_haveaddr = 1;
-+ }
-+ }
-+
-+ /* other params should be filled in */
-+ if (sasl_server_new("pop", config_servername, NULL, NULL, NULL,
-+ NULL, 0, &popd_saslconn) != SASL_OK)
-+ fatal("SASL failed initializing: sasl_server_new()",EC_TEMPFAIL);
-+
-+ /* will always return something valid */
-+ secprops = mysasl_secprops(SASL_SEC_NOPLAINTEXT);
-+ sasl_setprop(popd_saslconn, SASL_SEC_PROPS, secprops);
-+
-+ if(iptostring((struct sockaddr *)&popd_localaddr,
-+ salen, localip, 60) == 0) {
-+ sasl_setprop(popd_saslconn, SASL_IPLOCALPORT, localip);
-+ saslprops.iplocalport = xstrdup(localip);
-+ }
-+
-+ if(iptostring((struct sockaddr *)&popd_remoteaddr,
-+ salen, remoteip, 60) == 0) {
-+ sasl_setprop(popd_saslconn, SASL_IPREMOTEPORT, remoteip);
-+ saslprops.ipremoteport = xstrdup(remoteip);
-+ }
-+
-+ proc_register("pop3d", popd_clienthost, NULL, NULL);
-+
-+ /* Set inactivity timer */
-+ timeout = config_getint(IMAPOPT_POPTIMEOUT);
-+ if (timeout < 10) timeout = 10;
-+ prot_settimeout(popd_in, timeout*60);
-+ prot_setflushonread(popd_in, popd_out);
-+
-+ if (kflag) kpop();
-+
-+ /* we were connected on pop3s port so we should do
-+ TLS negotiation immediatly */
-+ if (pop3s == 1) cmd_starttls(1);
-+
-+ /* Create APOP challenge for banner */
-+ *popd_apop_chal = 0;
-+ if (config_getswitch(IMAPOPT_ALLOWAPOP) &&
-+ (sasl_checkapop(popd_saslconn, NULL, 0, NULL, 0) == SASL_OK) &&
-+ !sasl_mkchal(popd_saslconn,
-+ popd_apop_chal, sizeof(popd_apop_chal), 1)) {
-+ syslog(LOG_WARNING, "APOP disabled: can't create challenge");
-+ }
-+
-+ prot_printf(popd_out, "+OK %s Cyrus POP3%s %s server ready %s\r\n",
-+ config_servername, config_mupdate_server ? " Murder" : "",
-+ CYRUS_VERSION, popd_apop_chal);
-+ cmdloop();
-+
-+ /* QUIT executed */
-+
-+ /* don't bother reusing KPOP connections */
-+ if (kflag) shut_down(0);
-+
-+ /* cleanup */
-+ popd_reset();
-+
-+ return 0;
-+}
-+
-+/* Called by service API to shut down the service */
-+void service_abort(int error)
-+{
-+ shut_down(error);
-+}
-+
-+void usage(void)
-+{
-+ prot_printf(popd_out, "-ERR usage: pop3d [-C <alt_config>] [-k] [-s]\r\n");
-+ prot_flush(popd_out);
-+ exit(EC_USAGE);
-+}
-+
-+/*
-+ * Cleanly shut down and exit
-+ */
-+void shut_down(int code)
-+{
-+ proc_cleanup();
-+
-+ /* close local mailbox */
-+ if (popd_mailbox) {
-+ mailbox_close(popd_mailbox);
-+ }
-+
-+ if (popd_msg) {
-+ free(popd_msg);
-+ }
-+
-+ /* close backend connection */
-+ if (backend) {
-+ backend_disconnect(backend, &protocol[PROTOCOL_POP3]);
-+ free(backend);
-+ }
-+
-+ mboxlist_close();
-+ mboxlist_done();
-+
-+ quotadb_close();
-+ quotadb_done();
-+
-+ if (popd_in) {
-+ prot_NONBLOCK(popd_in);
-+ prot_fill(popd_in);
-+ prot_free(popd_in);
-+ }
-+
-+ if (popd_out) {
-+ prot_flush(popd_out);
-+ prot_free(popd_out);
-+ }
-+
-+#ifdef HAVE_SSL
-+ tls_shutdown_serverengine();
-+#endif
-+
-+ cyrus_done();
-+ cyrus_close_sock(0);
-+ cyrus_close_sock(1);
-+ cyrus_close_sock(2);
-+
-+ exit(code);
-+}
-+
-+void fatal(const char* s, int code)
-+{
-+ static int recurse_code = 0;
-+
-+ if (recurse_code) {
-+ /* We were called recursively. Just give up */
-+ proc_cleanup();
-+ exit(recurse_code);
-+ }
-+ recurse_code = code;
-+ if (popd_out) {
-+ prot_printf(popd_out, "-ERR [SYS/PERM] Fatal error: %s\r\n", s);
-+ prot_flush(popd_out);
-+ }
-+ syslog(LOG_ERR, "Fatal error: %s", s);
-+ shut_down(code);
-+}
-+
-+#ifdef HAVE_KRB
-+/*
-+ * MIT's kludge of a kpop protocol
-+ * Client does a krb_sendauth() first thing
-+ */
-+void kpop(void)
-+{
-+ Key_schedule schedule;
-+ KTEXT_ST ticket;
-+ char instance[INST_SZ];
-+ char version[9];
-+ const char *srvtab;
-+ int r;
-+ socklen_t len;
-+
-+ if (!popd_haveaddr) {
-+ fatal("Cannot get client's IP address", EC_OSERR);
-+ }
-+
-+ srvtab = config_getstring(IMAPOPT_SRVTAB);
-+
-+ sockaddr_unmapped((struct sockaddr *)&popd_remoteaddr, &len);
-+ if (popd_remoteaddr.ss_family != AF_INET) {
-+ prot_printf(popd_out,
-+ "-ERR [AUTH] Kerberos authentication failure: %s\r\n",
-+ "not an IPv4 connection");
-+ shut_down(0);
-+ }
-+
-+ strcpy(instance, "*");
-+ r = krb_recvauth(0L, 0, &ticket, "pop", instance,
-+ (struct sockaddr_in *) &popd_remoteaddr,
-+ (struct sockaddr_in *) NULL,
-+ &kdata, (char*) srvtab, schedule, version);
-+
-+ if (r) {
-+ prot_printf(popd_out, "-ERR [AUTH] Kerberos authentication failure: %s\r\n",
-+ krb_err_txt[r]);
-+ syslog(LOG_NOTICE,
-+ "badlogin: %s kpop ? %s%s%s@%s %s",
-+ popd_clienthost, kdata.pname,
-+ kdata.pinst[0] ? "." : "", kdata.pinst,
-+ kdata.prealm, krb_err_txt[r]);
-+ shut_down(0);
-+ }
-+
-+ r = krb_get_lrealm(klrealm,1);
-+ if (r) {
-+ prot_printf(popd_out, "-ERR [AUTH] Kerberos failure: %s\r\n",
-+ krb_err_txt[r]);
-+ syslog(LOG_NOTICE,
-+ "badlogin: %s kpop ? %s%s%s@%s krb_get_lrealm: %s",
-+ popd_clienthost, kdata.pname,
-+ kdata.pinst[0] ? "." : "", kdata.pinst,
-+ kdata.prealm, krb_err_txt[r]);
-+ shut_down(0);
-+ }
-+}
-+#else
-+void kpop(void)
-+{
-+ usage();
-+}
-+#endif
-+
-+/*
-+ * Top-level command loop parsing
-+ */
-+static void cmdloop(void)
-+{
-+ char inputbuf[8192];
-+ char *p, *arg;
-+ unsigned msg = 0;
-+
-+ for (;;) {
-+ signals_poll();
-+
-+ if (backend) {
-+ /* create a pipe from client to backend */
-+ bitpipe();
-+
-+ /* pipe has been closed */
-+ return;
-+ }
-+
-+ /* check for shutdown file */
-+ if (shutdown_file(inputbuf, sizeof(inputbuf))) {
-+ for (p = inputbuf; *p == '['; p++); /* can't have [ be first char */
-+ prot_printf(popd_out, "-ERR [SYS/TEMP] %s\r\n", p);
-+ shut_down(0);
-+ }
-+
-+ if (!prot_fgets(inputbuf, sizeof(inputbuf), popd_in)) {
-+ shut_down(0);
-+ }
-+
-+ p = inputbuf + strlen(inputbuf);
-+ if (p > inputbuf && p[-1] == '\n') *--p = '\0';
-+ if (p > inputbuf && p[-1] == '\r') *--p = '\0';
-+
-+ /* Parse into keword and argument */
-+ for (p = inputbuf; *p && !isspace((int) *p); p++);
-+ if (*p) {
-+ *p++ = '\0';
-+ arg = p;
-+ if (strcasecmp(inputbuf, "pass") != 0) {
-+ while (*arg && isspace((int) *arg)) {
-+ arg++;
-+ }
-+ }
-+ if (!*arg) {
-+ if (strcasecmp(inputbuf, "auth") == 0) {
-+ /* HACK for MS Outlook's incorrect use of the old-style
-+ * SASL discovery method.
-+ * Outlook uses "AUTH \r\n" instead if "AUTH\r\n"
-+ */
-+ arg = 0;
-+ }
-+ else {
-+ prot_printf(popd_out, "-ERR Syntax error\r\n");
-+ continue;
-+ }
-+ }
-+ }
-+ else {
-+ arg = 0;
-+ }
-+ lcase(inputbuf);
-+
-+ if (!strcmp(inputbuf, "quit")) {
-+ if (!arg) {
-+ if (popd_mailbox) {
-+ if (!mailbox_lock_index(popd_mailbox)) {
-+ popd_mailbox->pop3_last_login = popd_login_time;
-+ mailbox_write_index_header(popd_mailbox);
-+ mailbox_unlock_index(popd_mailbox);
-+ }
-+
-+ for (msg = 1; msg <= popd_exists; msg++) {
-+ if (popd_msg[msg].deleted) break;
-+ }
-+
-+ if (msg <= popd_exists) {
-+ (void) mailbox_expunge(popd_mailbox, 1, expungedeleted, 0);
-+ }
-+ }
-+ prot_printf(popd_out, "+OK\r\n");
-+ return;
-+ }
-+ else prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
-+ }
-+ else if (!strcmp(inputbuf, "capa")) {
-+ if (arg) {
-+ prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
-+ } else {
-+ cmd_capa();
-+ }
-+ }
-+ else if (!strcmp(inputbuf, "stls") && tls_enabled()) {
-+ if (arg) {
-+ prot_printf(popd_out,
-+ "-ERR STLS doesn't take any arguments\r\n");
-+ } else {
-+ cmd_starttls(0);
-+ }
-+ }
-+ else if (!popd_mailbox) {
-+ if (!strcmp(inputbuf, "user")) {
-+ if (!arg) {
-+ prot_printf(popd_out, "-ERR Missing argument\r\n");
-+ }
-+ else {
-+ cmd_user(arg);
-+ }
-+ }
-+ else if (!strcmp(inputbuf, "pass")) {
-+ if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
-+ else cmd_pass(arg);
-+ }
-+ else if (!strcmp(inputbuf, "apop") && *popd_apop_chal) {
-+ if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
-+ else cmd_apop(arg);
-+ }
-+ else if (!strcmp(inputbuf, "auth")) {
-+ cmd_auth(arg);
-+ }
-+ else {
-+ prot_printf(popd_out, "-ERR Unrecognized command\r\n");
-+ }
-+ }
-+ else if (!strcmp(inputbuf, "stat")) {
-+ unsigned nmsgs = 0, totsize = 0;
-+ if (arg) {
-+ prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
-+ }
-+ else {
-+ for (msg = 1; msg <= popd_exists; msg++) {
-+ if (!popd_msg[msg].deleted) {
-+ nmsgs++;
-+ totsize += popd_msg[msg].size;
-+ }
-+ }
-+ prot_printf(popd_out, "+OK %u %u\r\n", nmsgs, totsize);
-+ }
-+ }
-+ else if (!strcmp(inputbuf, "list")) {
-+ if (arg) {
-+ msg = parsenum(&arg);
-+ if (arg) {
-+ prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
-+ }
-+ else if (msg < 1 || msg > popd_exists ||
-+ popd_msg[msg].deleted) {
-+ prot_printf(popd_out, "-ERR No such message\r\n");
-+ }
-+ else {
-+ prot_printf(popd_out, "+OK %u %u\r\n", msg, popd_msg[msg].size);
-+ }
-+ }
-+ else {
-+ prot_printf(popd_out, "+OK scan listing follows\r\n");
-+ for (msg = 1; msg <= popd_exists; msg++) {
-+ if (!popd_msg[msg].deleted) {
-+ prot_printf(popd_out, "%u %u\r\n", msg, popd_msg[msg].size);
-+ }
-+ }
-+ prot_printf(popd_out, ".\r\n");
-+ }
-+ }
-+ else if (!strcmp(inputbuf, "retr")) {
-+ if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
-+ else {
-+ msg = parsenum(&arg);
-+ if (arg) {
-+ prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
-+ }
-+ else if (msg < 1 || msg > popd_exists ||
-+ popd_msg[msg].deleted) {
-+ prot_printf(popd_out, "-ERR No such message\r\n");
-+ }
-+ else {
-+ blat(msg, -1);
-+ }
-+ }
-+ }
-+ else if (!strcmp(inputbuf, "dele")) {
-+ if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
-+ else if (config_popuseacl && !(mboxstruct.myrights & ACL_DELETE)) {
-+ prot_printf(popd_out, "-ERR [SYS/PERM] %s\r\n",
-+ error_message(IMAP_PERMISSION_DENIED));
-+ }
-+ else {
-+ msg = parsenum(&arg);
-+ if (arg) {
-+ prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
-+ }
-+ else if (msg < 1 || msg > popd_exists ||
-+ popd_msg[msg].deleted) {
-+ prot_printf(popd_out, "-ERR No such message\r\n");
-+ }
-+ else {
-+ popd_msg[msg].deleted = 1;
-+ prot_printf(popd_out, "+OK message deleted\r\n");
-+ }
-+ }
-+ }
-+ else if (!strcmp(inputbuf, "noop")) {
-+ if (arg) {
-+ prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
-+ }
-+ else {
-+ prot_printf(popd_out, "+OK\r\n");
-+ }
-+ }
-+ else if (!strcmp(inputbuf, "rset")) {
-+ if (arg) {
-+ prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
-+ }
-+ else {
-+ for (msg = 1; msg <= popd_exists; msg++) {
-+ popd_msg[msg].deleted = 0;
-+ }
-+ prot_printf(popd_out, "+OK\r\n");
-+ }
-+ }
-+ else if (!strcmp(inputbuf, "top")) {
-+ int lines;
-+
-+ if (arg) msg = parsenum(&arg);
-+ if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
-+ else {
-+ lines = parsenum(&arg);
-+ if (arg) {
-+ prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
-+ }
-+ else if (msg < 1 || msg > popd_exists ||
-+ popd_msg[msg].deleted) {
-+ prot_printf(popd_out, "-ERR No such message\r\n");
-+ }
-+ else if (lines < 0) {
-+ prot_printf(popd_out, "-ERR Invalid number of lines\r\n");
-+ }
-+ else {
-+ blat(msg, lines);
-+ }
-+ }
-+ }
-+ else if (!strcmp(inputbuf, "uidl")) {
-+ if (arg) {
-+ msg = parsenum(&arg);
-+ if (arg) {
-+ prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
-+ }
-+ else if (msg < 1 || msg > popd_exists ||
-+ popd_msg[msg].deleted) {
-+ prot_printf(popd_out, "-ERR No such message\r\n");
-+ }
-+ else if (mboxstruct.pop3_new_uidl) {
-+ prot_printf(popd_out, "+OK %u %lu.%u\r\n", msg,
-+ mboxstruct.uidvalidity,
-+ popd_msg[msg].uid);
-+ }
-+ else {
-+ /* old uidl format */
-+ prot_printf(popd_out, "+OK %u %u\r\n",
-+ msg, popd_msg[msg].uid);
-+ }
-+ }
-+ else {
-+ prot_printf(popd_out, "+OK unique-id listing follows\r\n");
-+ for (msg = 1; msg <= popd_exists; msg++) {
-+ if (!popd_msg[msg].deleted) {
-+ if (mboxstruct.pop3_new_uidl) {
-+ prot_printf(popd_out, "%u %lu.%u\r\n", msg,
-+ mboxstruct.uidvalidity,
-+ popd_msg[msg].uid);
-+ } else {
-+ prot_printf(popd_out, "%u %u\r\n", msg,
-+ popd_msg[msg].uid);
-+ }
-+ }
-+ }
-+ prot_printf(popd_out, ".\r\n");
-+ }
-+ }
-+ else {
-+ prot_printf(popd_out, "-ERR Unrecognized command\r\n");
-+ }
-+ }
-+}
-+
-+#ifdef HAVE_SSL
-+static void cmd_starttls(int pop3s)
-+{
-+ int result;
-+ int *layerp;
-+ sasl_ssf_t ssf;
-+ char *auth_id;
-+
-+ /* SASL and openssl have different ideas about whether ssf is signed */
-+ layerp = (int *) &ssf;
-+
-+ if (popd_starttls_done == 1)
-+ {
-+ prot_printf(popd_out, "-ERR %s\r\n",
-+ "Already successfully executed STLS");
-+ return;
-+ }
-+
-+ result=tls_init_serverengine("pop3",
-+ 5, /* depth to verify */
-+ !pop3s, /* can client auth? */
-+ !pop3s); /* TLS only? */
-+
-+ if (result == -1) {
-+
-+ syslog(LOG_ERR, "[pop3d] error initializing TLS");
-+
-+ if (pop3s == 0)
-+ prot_printf(popd_out, "-ERR [SYS/PERM] %s\r\n", "Error initializing TLS");
-+ else
-+ fatal("tls_init() failed",EC_TEMPFAIL);
-+
-+ return;
-+ }
-+
-+ if (pop3s == 0)
-+ {
-+ prot_printf(popd_out, "+OK %s\r\n", "Begin TLS negotiation now");
-+ /* must flush our buffers before starting tls */
-+ prot_flush(popd_out);
-+ }
-+
-+ result=tls_start_servertls(0, /* read */
-+ 1, /* write */
-+ layerp,
-+ &auth_id,
-+ &tls_conn);
-+
-+ /* if error */
-+ if (result==-1) {
-+ if (pop3s == 0) {
-+ prot_printf(popd_out, "-ERR [SYS/PERM] Starttls failed\r\n");
-+ syslog(LOG_NOTICE, "[pop3d] STARTTLS failed: %s", popd_clienthost);
-+ } else {
-+ syslog(LOG_NOTICE, "pop3s failed: %s", popd_clienthost);
-+ fatal("tls_start_servertls() failed", EC_TEMPFAIL);
-+ }
-+ return;
-+ }
-+
-+ /* tell SASL about the negotiated layer */
-+ result = sasl_setprop(popd_saslconn, SASL_SSF_EXTERNAL, &ssf);
-+ if (result != SASL_OK) {
-+ fatal("sasl_setprop() failed: cmd_starttls()", EC_TEMPFAIL);
-+ }
-+ saslprops.ssf = ssf;
-+
-+ result = sasl_setprop(popd_saslconn, SASL_AUTH_EXTERNAL, auth_id);
-+ if (result != SASL_OK) {
-+ fatal("sasl_setprop() failed: cmd_starttls()", EC_TEMPFAIL);
-+ }
-+ if(saslprops.authid) {
-+ free(saslprops.authid);
-+ saslprops.authid = NULL;
-+ }
-+ if(auth_id)
-+ saslprops.authid = xstrdup(auth_id);
-+
-+ /* tell the prot layer about our new layers */
-+ prot_settls(popd_in, tls_conn);
-+ prot_settls(popd_out, tls_conn);
-+
-+ popd_starttls_done = 1;
-+}
-+#else
-+static void cmd_starttls(int pop3s __attribute__((unused)))
-+{
-+ fatal("cmd_starttls() called, but no OpenSSL", EC_SOFTWARE);
-+}
-+#endif /* HAVE_SSL */
-+
-+static void cmd_apop(char *response)
-+{
-+ int sasl_result;
-+ char *canon_user;
-+
-+ assert(response != NULL);
-+
-+ if (popd_userid) {
-+ prot_printf(popd_out, "-ERR [AUTH] Must give PASS command\r\n");
-+ return;
-+ }
-+
-+ sasl_result = sasl_checkapop(popd_saslconn,
-+ popd_apop_chal,
-+ strlen(popd_apop_chal),
-+ response,
-+ strlen(response));
-+
-+ /* failed authentication */
-+ if (sasl_result != SASL_OK)
-+ {
-+ sleep(3);
-+
-+ prot_printf(popd_out, "-ERR [AUTH] authenticating: %s\r\n",
-+ sasl_errstring(sasl_result, NULL, NULL));
-+
-+ syslog(LOG_NOTICE, "badlogin: %s APOP (%s) %s",
-+ popd_clienthost, popd_apop_chal,
-+ sasl_errdetail(popd_saslconn));
-+
-+ return;
-+ }
-+
-+ /* successful authentication */
-+
-+ /*
-+ * get the userid from SASL --- already canonicalized from
-+ * mysasl_proxy_policy()
-+ */
-+ sasl_result = sasl_getprop(popd_saslconn, SASL_USERNAME,
-+ (const void **) &canon_user);
-+ popd_userid = xstrdup(canon_user);
-+ if (sasl_result != SASL_OK) {
-+ prot_printf(popd_out,
-+ "-ERR [AUTH] weird SASL error %d getting SASL_USERNAME\r\n",
-+ sasl_result);
-+ return;
-+ }
-+
-+ syslog(LOG_NOTICE, "login: %s %s APOP%s %s", popd_clienthost,
-+ popd_userid, popd_starttls_done ? "+TLS" : "", "User logged in");
-+
-+ popd_authstate = auth_newstate(popd_userid);
-+
-+ openinbox();
-+}
-+
-+void cmd_user(char *user)
-+{
-+ char *p, *dot, *domain;
-+
-+ /* possibly disallow USER */
-+ if (!(kflag || popd_starttls_done ||
-+ config_getswitch(IMAPOPT_ALLOWPLAINTEXT))) {
-+ prot_printf(popd_out,
-+ "-ERR [AUTH] USER command only available under a layer\r\n");
-+ return;
-+ }
-+
-+ if (popd_userid) {
-+ prot_printf(popd_out, "-ERR [AUTH] Must give PASS command\r\n");
-+ return;
-+ }
-+
-+ if (!(p = canonify_userid(user, NULL, NULL)) ||
-+ /* '.' isn't allowed if '.' is the hierarchy separator */
-+ (popd_namespace.hier_sep == '.' && (dot = strchr(p, '.')) &&
-+ !(config_virtdomains && /* allow '.' in dom.ain */
-+ (domain = strchr(p, '@')) && (dot > domain))) ||
-+ strlen(p) + 6 > MAX_MAILBOX_PATH) {
-+ prot_printf(popd_out, "-ERR [AUTH] Invalid user\r\n");
-+ syslog(LOG_NOTICE,
-+ "badlogin: %s plaintext %s invalid user",
-+ popd_clienthost, beautify_string(user));
-+ }
-+ else {
-+ popd_userid = xstrdup(p);
-+ prot_printf(popd_out, "+OK Name is a valid mailbox\r\n");
-+ }
-+}
-+
-+void cmd_pass(char *pass)
-+{
-+ int plaintextloginpause;
-+
-+ if (!popd_userid) {
-+ prot_printf(popd_out, "-ERR [AUTH] Must give USER command\r\n");
-+ return;
-+ }
-+
-+#ifdef HAVE_KRB
-+ if (kflag) {
-+ if (strcmp(popd_userid, kdata.pname) != 0 ||
-+ kdata.pinst[0] ||
-+ strcmp(klrealm, kdata.prealm) != 0) {
-+ prot_printf(popd_out, "-ERR [AUTH] Invalid login\r\n");
-+ syslog(LOG_NOTICE,
-+ "badlogin: %s kpop %s %s%s%s@%s access denied",
-+ popd_clienthost, popd_userid,
-+ kdata.pname, kdata.pinst[0] ? "." : "",
-+ kdata.pinst, kdata.prealm);
-+ return;
-+ }
-+
-+ syslog(LOG_NOTICE, "login: %s %s kpop", popd_clienthost, popd_userid);
-+
-+ openinbox();
-+ return;
-+ }
-+#endif
-+
-+ if (!strcmp(popd_userid, "anonymous")) {
-+ if (config_getswitch(IMAPOPT_ALLOWANONYMOUSLOGIN)) {
-+ pass = beautify_string(pass);
-+ if (strlen(pass) > 500) pass[500] = '\0';
-+ syslog(LOG_NOTICE, "login: %s anonymous %s",
-+ popd_clienthost, pass);
-+ }
-+ else {
-+ syslog(LOG_NOTICE, "badlogin: %s anonymous login refused",
-+ popd_clienthost);
-+ prot_printf(popd_out, "-ERR [AUTH] Invalid login\r\n");
-+ return;
-+ }
-+ }
-+ else if (sasl_checkpass(popd_saslconn,
-+ popd_userid,
-+ strlen(popd_userid),
-+ pass,
-+ strlen(pass))!=SASL_OK) {
-+ syslog(LOG_NOTICE, "badlogin: %s plaintext %s %s",
-+ popd_clienthost, popd_userid, sasl_errdetail(popd_saslconn));
-+ sleep(3);
-+ prot_printf(popd_out, "-ERR [AUTH] Invalid login\r\n");
-+ free(popd_userid);
-+ popd_userid = 0;
-+
-+ return;
-+ }
-+ else {
-+ syslog(LOG_NOTICE, "login: %s %s plaintext%s %s", popd_clienthost,
-+ popd_userid, popd_starttls_done ? "+TLS" : "",
-+ "User logged in");
-+
-+ if ((plaintextloginpause = config_getint(IMAPOPT_PLAINTEXTLOGINPAUSE))
-+ != 0) {
-+ sleep(plaintextloginpause);
-+ }
-+ }
-+
-+ popd_authstate = auth_newstate(popd_userid);
-+
-+ openinbox();
-+}
-+
-+/* Handle the POP3 Extension extension.
-+ */
-+void cmd_capa()
-+{
-+ int minpoll = config_getint(IMAPOPT_POPMINPOLL) * 60;
-+ int expire = config_getint(IMAPOPT_POPEXPIRETIME);
-+ unsigned mechcount;
-+ const char *mechlist;
-+
-+ prot_printf(popd_out, "+OK List of capabilities follows\r\n");
-+
-+ /* SASL special case: print SASL, then a list of supported capabilities */
-+ if (!popd_mailbox && !backend &&
-+ sasl_listmech(popd_saslconn,
-+ NULL, /* should be id string */
-+ "SASL ", " ", "\r\n",
-+ &mechlist,
-+ NULL, &mechcount) == SASL_OK && mechcount > 0) {
-+ prot_write(popd_out, mechlist, strlen(mechlist));
-+ }
-+
-+ if (tls_enabled() && !popd_starttls_done && !popd_mailbox && !backend) {
-+ prot_printf(popd_out, "STLS\r\n");
-+ }
-+ if (expire < 0) {
-+ prot_printf(popd_out, "EXPIRE NEVER\r\n");
-+ } else {
-+ prot_printf(popd_out, "EXPIRE %d\r\n", expire);
-+ }
-+
-+ prot_printf(popd_out, "LOGIN-DELAY %d\r\n", minpoll);
-+ prot_printf(popd_out, "TOP\r\n");
-+ prot_printf(popd_out, "UIDL\r\n");
-+ prot_printf(popd_out, "PIPELINING\r\n");
-+ prot_printf(popd_out, "RESP-CODES\r\n");
-+ prot_printf(popd_out, "AUTH-RESP-CODE\r\n");
-+
-+ if (!popd_mailbox && !backend &&
-+ (kflag || popd_starttls_done
-+ || config_getswitch(IMAPOPT_ALLOWPLAINTEXT))) {
-+ prot_printf(popd_out, "USER\r\n");
-+ }
-+
-+ prot_printf(popd_out,
-+ "IMPLEMENTATION Cyrus POP3%s server %s\r\n",
-+ config_mupdate_server ? " Murder" : "", CYRUS_VERSION);
-+
-+ prot_printf(popd_out, ".\r\n");
-+ prot_flush(popd_out);
-+}
-+
-+
-+void cmd_auth(char *arg)
-+{
-+ int r, sasl_result;
-+ char *authtype;
-+ char *canon_user;
-+
-+ /* if client didn't specify an argument we give them the list
-+ *
-+ * XXX This method of mechanism discovery is an undocumented feature
-+ * that appeared in draft-myers-sasl-pop3 and is still used by
-+ * some clients.
-+ */
-+ if (!arg) {
-+ const char *sasllist;
-+ unsigned int mechnum;
-+
-+ prot_printf(popd_out, "+OK List of supported mechanisms follows\r\n");
-+
-+ /* CRLF separated, dot terminated */
-+ if (sasl_listmech(popd_saslconn, NULL,
-+ "", "\r\n", "\r\n",
-+ &sasllist,
-+ NULL, &mechnum) == SASL_OK) {
-+ if (mechnum>0) {
-+ prot_printf(popd_out,"%s",sasllist);
-+ }
-+ }
-+
-+ prot_printf(popd_out, ".\r\n");
-+ return;
-+ }
-+
-+ authtype = arg;
-+
-+ /* according to RFC 2449, since we advertise the "SASL" capability, we
-+ * must accept an optional second argument as an initial client
-+ * response (base64 encoded!).
-+ */
-+ while (*arg && !isspace((int) *arg)) {
-+ arg++;
-+ }
-+ if (isspace((int) *arg)) {
-+ /* null terminate authtype, get argument */
-+ *arg++ = '\0';
-+ } else {
-+ /* no optional client response */
-+ arg = NULL;
-+ }
-+
-+ r = saslserver(popd_saslconn, authtype, arg, "", "+ ", "",
-+ popd_in, popd_out, &sasl_result, NULL);
-+
-+ if (r) {
-+ const char *errorstring = NULL;
-+
-+ switch (r) {
-+ case IMAP_SASL_CANCEL:
-+ prot_printf(popd_out,
-+ "-ERR [AUTH] Client canceled authentication\r\n");
-+ break;
-+ case IMAP_SASL_PROTERR:
-+ errorstring = prot_error(popd_in);
-+
-+ prot_printf(popd_out,
-+ "-ERR [AUTH] Error reading client response: %s\r\n",
-+ errorstring ? errorstring : "");
-+ break;
-+ default:
-+ /* failed authentication */
-+ sleep(3);
-+
-+ prot_printf(popd_out, "-ERR [AUTH] authenticating: %s\r\n",
-+ sasl_errstring(sasl_result, NULL, NULL));
-+
-+ if (authtype) {
-+ syslog(LOG_NOTICE, "badlogin: %s %s %s",
-+ popd_clienthost, authtype,
-+ sasl_errstring(sasl_result, NULL, NULL));
-+ } else {
-+ syslog(LOG_NOTICE, "badlogin: %s %s",
-+ popd_clienthost, authtype);
-+ }
-+ }
-+
-+ reset_saslconn(&popd_saslconn);
-+ return;
-+ }
-+
-+ /* successful authentication */
-+
-+ /* get the userid from SASL --- already canonicalized from
-+ * mysasl_proxy_policy()
-+ */
-+ sasl_result = sasl_getprop(popd_saslconn, SASL_USERNAME,
-+ (const void **) &canon_user);
-+ popd_userid = xstrdup(canon_user);
-+ if (sasl_result != SASL_OK) {
-+ prot_printf(popd_out,
-+ "-ERR [AUTH] weird SASL error %d getting SASL_USERNAME\r\n",
-+ sasl_result);
-+ return;
-+ }
-+
-+ syslog(LOG_NOTICE, "login: %s %s %s%s %s", popd_clienthost, popd_userid,
-+ authtype, popd_starttls_done ? "+TLS" : "", "User logged in");
-+
-+ if (!openinbox()) {
-+ prot_setsasl(popd_in, popd_saslconn);
-+ prot_setsasl(popd_out, popd_saslconn);
-+ }
-+ else {
-+ reset_saslconn(&popd_saslconn);
-+ }
-+}
-+
-+/*
-+ * Complete the login process by opening and locking the user's inbox
-+ */
-+int openinbox(void)
-+{
-+ char userid[MAX_MAILBOX_NAME+1], inboxname[MAX_MAILBOX_PATH+1];
-+ int type, myrights = 0;
-+ char *server = NULL, *acl;
-+ int r, log_level = LOG_ERR;
-+ const char *statusline = NULL;
-+
-+ /* Translate any separators in userid
-+ (use a copy since we need the original userid for AUTH to backend) */
-+ strlcpy(userid, popd_userid, sizeof(userid));
-+ mboxname_hiersep_tointernal(&popd_namespace, userid,
-+ config_virtdomains ?
-+ strcspn(userid, "@") : 0);
-+
-+ r = (*popd_namespace.mboxname_tointernal)(&popd_namespace, "INBOX",
-+ userid, inboxname);
-+
-+ if (!r) r = mboxlist_detail(inboxname, &type, NULL, &server, &acl, NULL);
-+ if (!r && (config_popuseacl = config_getswitch(IMAPOPT_POPUSEACL)) &&
-+ (!acl ||
-+ !((myrights = cyrus_acl_myrights(popd_authstate, acl)) & ACL_READ))) {
-+ r = (myrights & ACL_LOOKUP) ?
-+ IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
-+ log_level = LOG_INFO;
-+ }
-+ if (r) {
-+ sleep(3);
-+ syslog(log_level, "Unable to locate maildrop for %s: %s",
-+ popd_userid, error_message(r));
-+ prot_printf(popd_out,
-+ "-ERR [SYS/PERM] Unable to locate maildrop: %s\r\n",
-+ error_message(r));
-+ goto fail;
-+ }
-+
-+ if (type & MBTYPE_REMOTE) {
-+ /* remote mailbox */
-+
-+ /* xxx hide the fact that we are storing partitions */
-+ if (server) {
-+ char *c;
-+ c = strchr(server, '!');
-+ if(c) *c = '\0';
-+ }
-+
-+ backend = backend_connect(NULL, server, &protocol[PROTOCOL_POP3],
-+ popd_userid, &statusline);
-+
-+ if (!backend) {
-+ syslog(LOG_ERR, "couldn't authenticate to backend server");
-+ prot_printf(popd_out, "-ERR%s",
-+ statusline ? statusline :
-+ " Authentication to backend server failed\r\n");
-+ prot_flush(popd_out);
-+
-+ goto fail;
-+ }
-+ }
-+ else {
-+ /* local mailbox */
-+ int msg;
-+ struct index_record record;
-+ int minpoll;
-+ int doclose = 0;
-+
-+ popd_login_time = time(0);
-+
-+ r = mailbox_open_header(inboxname, popd_authstate, &mboxstruct);
-+ if (!r) {
-+ doclose = 1;
-+ if (config_popuseacl && !(mboxstruct.myrights & ACL_READ)) {
-+ r = (mboxstruct.myrights & ACL_LOOKUP) ?
-+ IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
-+ log_level = LOG_INFO;
-+ }
-+ }
-+ if (r) {
-+ sleep(3);
-+ syslog(log_level, "Unable to open maildrop for %s: %s",
-+ popd_userid, error_message(r));
-+ prot_printf(popd_out,
-+ "-ERR [SYS/PERM] Unable to open maildrop: %s\r\n",
-+ error_message(r));
-+ if (doclose) mailbox_close(&mboxstruct);
-+ goto fail;
-+ }
-+
-+ r = mailbox_open_index(&mboxstruct);
-+ if (!r) r = mailbox_lock_pop(&mboxstruct);
-+ if (r) {
-+ mailbox_close(&mboxstruct);
-+ syslog(LOG_ERR, "Unable to lock maildrop for %s: %s",
-+ popd_userid, error_message(r));
-+ prot_printf(popd_out,
-+ "-ERR [IN-USE] Unable to lock maildrop: %s\r\n",
-+ error_message(r));
-+ goto fail;
-+ }
-+
-+ if ((minpoll = config_getint(IMAPOPT_POPMINPOLL)) &&
-+ mboxstruct.pop3_last_login + 60*minpoll > popd_login_time) {
-+ prot_printf(popd_out,
-+ "-ERR [LOGIN-DELAY] Logins must be at least %d minute%s apart\r\n",
-+ minpoll, minpoll > 1 ? "s" : "");
-+ if (!mailbox_lock_index(&mboxstruct)) {
-+ mboxstruct.pop3_last_login = popd_login_time;
-+ mailbox_write_index_header(&mboxstruct);
-+ }
-+ mailbox_close(&mboxstruct);
-+ goto fail;
-+ }
-+
-+ if (chdir(mboxstruct.path)) {
-+ syslog(LOG_ERR, "IOERROR: changing directory to %s: %m",
-+ mboxstruct.path);
-+ r = IMAP_IOERROR;
-+ }
-+ if (!r) {
-+ popd_exists = mboxstruct.exists;
-+ popd_msg = (struct msg *) xrealloc(popd_msg, (popd_exists+1) *
-+ sizeof(struct msg));
-+ for (msg = 1; msg <= popd_exists; msg++) {
-+ if ((r = mailbox_read_index_record(&mboxstruct, msg, &record))!=0)
-+ break;
-+ popd_msg[msg].uid = record.uid;
-+ popd_msg[msg].size = record.size;
-+ popd_msg[msg].deleted = 0;
-+ }
-+ }
-+ if (r) {
-+ mailbox_close(&mboxstruct);
-+ popd_exists = 0;
-+ syslog(LOG_ERR, "Unable to read maildrop for %s", popd_userid);
-+ prot_printf(popd_out,
-+ "-ERR [SYS/PERM] Unable to read maildrop\r\n");
-+ goto fail;
-+ }
-+ popd_mailbox = &mboxstruct;
-+ proc_register("pop3d", popd_clienthost, popd_userid,
-+ popd_mailbox->name);
-+ }
-+
-+ /* Create telemetry log */
-+ popd_logfd = telemetry_log(popd_userid, popd_in, popd_out, 0);
-+
-+ prot_printf(popd_out, "+OK%s",
-+ statusline ? statusline : " Mailbox locked and ready\r\n");
-+ prot_flush(popd_out);
-+ return 0;
-+
-+ fail:
-+ free(popd_userid);
-+ popd_userid = 0;
-+ auth_freestate(popd_authstate);
-+ popd_authstate = NULL;
-+ return 1;
-+}
-+
-+static void blat(int msg,int lines)
-+{
-+ FILE *msgfile;
-+ char buf[4096];
-+ char fnamebuf[MAILBOX_FNAME_LEN];
-+ int thisline = -2;
-+
-+ mailbox_message_get_fname(popd_mailbox, popd_msg[msg].uid, fnamebuf,
-+ sizeof(fnamebuf));
-+ msgfile = fopen(fnamebuf, "r");
-+ if (!msgfile) {
-+ prot_printf(popd_out, "-ERR [SYS/PERM] Could not read message file\r\n");
-+ return;
-+ }
-+ prot_printf(popd_out, "+OK Message follows\r\n");
-+ while (lines != thisline) {
-+ if (!fgets(buf, sizeof(buf), msgfile)) break;
-+
-+ if (thisline < 0) {
-+ if (buf[0] == '\r' && buf[1] == '\n') thisline = 0;
-+ }
-+ else thisline++;
-+
-+ if (buf[0] == '.') prot_putc('.', popd_out);
-+ do {
-+ prot_printf(popd_out, "%s", buf);
-+ }
-+ while (buf[strlen(buf)-1] != '\n' && fgets(buf, sizeof(buf), msgfile));
-+ }
-+ fclose(msgfile);
-+
-+ /* Protect against messages not ending in CRLF */
-+ if (buf[strlen(buf)-1] != '\n') prot_printf(popd_out, "\r\n");
-+
-+ prot_printf(popd_out, ".\r\n");
-+}
-+
-+static int parsenum(char **ptr)
-+{
-+ char *p = *ptr;
-+ int result = 0;
-+
-+ if (!isdigit((int) *p)) {
-+ *ptr = 0;
-+ return -1;
-+ }
-+ while (*p && isdigit((int) *p)) {
-+ result = result * 10 + *p++ - '0';
-+ if (result < 0) {
-+ /* xxx overflow */
-+ }
-+ }
-+
-+ if (*p) {
-+ while (*p && isspace((int) *p)) p++;
-+ *ptr = p;
-+ }
-+ else *ptr = 0;
-+ return result;
-+}
-+
-+static int expungedeleted(struct mailbox *mailbox __attribute__((unused)),
-+ void *rock __attribute__((unused)), char *index)
-+{
-+ int msg;
-+ int uid = ntohl(*((bit32 *)(index+OFFSET_UID)));
-+
-+ for (msg = 1; msg <= popd_exists; msg++) {
-+ if (popd_msg[msg].uid == uid) {
-+ return popd_msg[msg].deleted;
-+ }
-+ }
-+ return 0;
-+}
-+
-+/* Reset the given sasl_conn_t to a sane state */
-+static int reset_saslconn(sasl_conn_t **conn)
-+{
-+ int ret;
-+ sasl_security_properties_t *secprops = NULL;
-+
-+ sasl_dispose(conn);
-+ /* do initialization typical of service_main */
-+ ret = sasl_server_new("pop", config_servername,
-+ NULL, NULL, NULL,
-+ NULL, 0, conn);
-+ if(ret != SASL_OK) return ret;
-+
-+ if(saslprops.ipremoteport)
-+ ret = sasl_setprop(*conn, SASL_IPREMOTEPORT,
-+ saslprops.ipremoteport);
-+ if(ret != SASL_OK) return ret;
-+
-+ if(saslprops.iplocalport)
-+ ret = sasl_setprop(*conn, SASL_IPLOCALPORT,
-+ saslprops.iplocalport);
-+ if(ret != SASL_OK) return ret;
-+ secprops = mysasl_secprops(SASL_SEC_NOPLAINTEXT);
-+ ret = sasl_setprop(*conn, SASL_SEC_PROPS, secprops);
-+ if(ret != SASL_OK) return ret;
-+ /* end of service_main initialization excepting SSF */
-+
-+ /* If we have TLS/SSL info, set it */
-+ if(saslprops.ssf) {
-+ ret = sasl_setprop(*conn, SASL_SSF_EXTERNAL, &saslprops.ssf);
-+ }
-+
-+ if(ret != SASL_OK) return ret;
-+
-+ if(saslprops.authid) {
-+ ret = sasl_setprop(*conn, SASL_AUTH_EXTERNAL, saslprops.authid);
-+ if(ret != SASL_OK) return ret;
-+ }
-+ /* End TLS/SSL Info */
-+
-+ return SASL_OK;
-+}
-+
-+/* we've authenticated the client, we've connected to the backend.
-+ now it's all up to them */
-+static void bitpipe(void)
-+{
-+ struct protgroup *protin = protgroup_new(2);
-+ struct protgroup *protout = NULL;
-+ struct timeval timeout;
-+ int n, shutdown = 0;
-+ char buf[4096];
-+
-+ /* Reset protin to all zeros (to preserve memory allocation) */
-+ protgroup_reset(protin);
-+ protgroup_insert(protin, popd_in);
-+ protgroup_insert(protin, backend->in);
-+
-+ for (;;) {
-+ /* check for shutdown file */
-+ if (shutdown_file(buf, sizeof(buf))) {
-+ shutdown = 1;
-+ goto done;
-+ }
-+
-+ /* Clear protout if needed */
-+ protgroup_free(protout);
-+ protout = NULL;
-+
-+ timeout.tv_sec = 60;
-+ timeout.tv_usec = 0;
-+
-+ n = prot_select(protin, PROT_NO_FD, &protout, NULL, &timeout);
-+ if (n == -1) {
-+ syslog(LOG_ERR, "prot_select() failed in bitpipe(): %m");
-+ fatal("prot_select() failed in bitpipe()", EC_TEMPFAIL);
-+ }
-+ if (n && protout) {
-+ struct protstream *ptmp;
-+
-+ for (; n; n--) {
-+ ptmp = protgroup_getelement(protout, n-1);
-+
-+ if (ptmp == popd_in) {
-+ do {
-+ int c = prot_read(popd_in, buf, sizeof(buf));
-+ if (c == 0 || c < 0) goto done;
-+ prot_write(backend->out, buf, c);
-+ } while (popd_in->cnt > 0);
-+ prot_flush(backend->out);
-+ }
-+ else if (ptmp == backend->in) {
-+ do {
-+ int c = prot_read(backend->in, buf, sizeof(buf));
-+ if (c == 0 || c < 0) goto done;
-+ prot_write(popd_out, buf, c);
-+ } while (backend->in->cnt > 0);
-+ prot_flush(popd_out);
-+ }
-+ else {
-+ /* XXX shouldn't get here !!! */
-+ fatal("unknown protstream returned by prot_select in bitpipe()",
-+ EC_SOFTWARE);
-+ }
-+ }
-+ }
-+ }
-+
-+
-+ done:
-+ /* ok, we're done. */
-+ protgroup_free(protin);
-+ protgroup_free(protout);
-+
-+ if (shutdown) {
-+ char *p;
-+ for (p = buf; *p == '['; p++); /* can't have [ be first char */
-+ prot_printf(popd_out, "-ERR [SYS/TEMP] %s\r\n", p);
-+ shut_down(0);
-+ }
-+
-+ return;
-+}
-+
-+
-+void printstring(const char *s __attribute__((unused)))
-+{
-+ /* needed to link against annotate.o */
-+ fatal("printstring() executed, but its not used for POP3!",
-+ EC_SOFTWARE);
-+}
-diff -urNad cyrus-imapd-2.2.12/imap/version.c /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/imap/version.c
---- cyrus-imapd-2.2.12/imap/version.c 2005-05-24 20:41:38.000000000 +0200
-+++ /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/imap/version.c 2005-05-24 20:45:11.559995930 +0200
+diff -urNad cyrus-imapd-2.2.12/imap/version.c /tmp/dpep.MaSf95/cyrus-imapd-2.2.12/imap/version.c
+--- cyrus-imapd-2.2.12/imap/version.c 2005-05-24 22:16:17.000000000 +0200
++++ /tmp/dpep.MaSf95/cyrus-imapd-2.2.12/imap/version.c 2005-05-25 00:50:08.174163245 +0200
@@ -151,6 +151,10 @@
snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
"; %s", SIEVE_VERSION);
@@ -11152,192 +275,9 @@
#ifdef HAVE_LIBWRAP
snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
"; TCP Wrappers");
-diff -urNad cyrus-imapd-2.2.12/imap/version.c.orig /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/imap/version.c.orig
---- cyrus-imapd-2.2.12/imap/version.c.orig 1970-01-01 01:00:00.000000000 +0100
-+++ /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/imap/version.c.orig 2005-05-24 20:41:38.000000000 +0200
-@@ -0,0 +1,179 @@
-+/* version.c: versioning functions
-+ * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ *
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ *
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in
-+ * the documentation and/or other materials provided with the
-+ * distribution.
-+ *
-+ * 3. The name "Carnegie Mellon University" must not be used to
-+ * endorse or promote products derived from this software without
-+ * prior written permission. For permission or any other legal
-+ * details, please contact
-+ * Office of Technology Transfer
-+ * Carnegie Mellon University
-+ * 5000 Forbes Avenue
-+ * Pittsburgh, PA 15213-3890
-+ * (412) 268-4387, fax: (412) 268-7395
-+ * tech-transfer at andrew.cmu.edu
-+ *
-+ * 4. Redistributions of any form whatsoever must retain the following
-+ * acknowledgment:
-+ * "This product includes software developed by Computing Services
-+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
-+ *
-+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
-+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
-+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
-+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
-+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ *
-+ * $Id: version.c,v 1.18 2004/06/21 15:31:13 rjs3 Exp $
-+ */
-+
-+#include <config.h>
-+
-+#include <sasl/sasl.h>
-+#include <sys/utsname.h>
-+#ifdef HAVE_BDB
-+#include <db.h>
-+#endif
-+#ifdef HAVE_KRB
-+#include <krb.h>
-+#endif
-+#ifdef HAVE_UCDSNMP
-+#include <ucd-snmp/version.h>
-+#endif
-+
-+#include <string.h>
-+#include "version.h"
-+#include "xversion.h"
-+#include "prot.h"
-+#include "cyrusdb.h"
-+#include "map.h"
-+#include "lock.h"
-+#include "nonblock.h"
-+#include "idle.h"
-+
-+#ifdef USE_SIEVE
-+#include "sieve_interface.h"
-+#endif
-+
-+static char id_resp_command[MAXIDVALUELEN];
-+static char id_resp_arguments[MAXIDVALUELEN] = "";
-+
-+/*
-+ * Grab the command line args for the ID response.
-+ */
-+void id_getcmdline(int argc, char **argv)
-+{
-+ snprintf(id_resp_command, MAXIDVALUELEN, *argv);
-+ while (--argc > 0) {
-+ snprintf(id_resp_arguments + strlen(id_resp_arguments),
-+ MAXIDVALUELEN - strlen(id_resp_arguments),
-+ "%s%s", *++argv, (argc > 1) ? " " : "");
-+ }
-+}
-+
-+/*
-+ * Output the ID response.
-+ * We do NOT close the parameter list so other stuff can be added later.
-+ */
-+void id_response(struct protstream *pout)
-+{
-+ struct utsname os;
-+ const char *sasl_imp;
-+ int sasl_ver;
-+ char env_buf[MAXIDVALUELEN+1];
-+
-+ prot_printf(pout, "* ID ("
-+ "\"name\" \"Cyrus IMAPD\""
-+ " \"version\" \"%s %s\""
-+ " \"vendor\" \"Project Cyrus\""
-+ " \"support-url\" \"http://asg.web.cmu.edu/cyrus\"",
-+ CYRUS_VERSION, CYRUS_CVSDATE);
-+
-+ /* add the os info */
-+ if (uname(&os) != -1)
-+ prot_printf(pout,
-+ " \"os\" \"%s\""
-+ " \"os-version\" \"%s\"",
-+ os.sysname, os.release);
-+
-+#ifdef ID_SAVE_CMDLINE
-+ /* add the command line info */
-+ prot_printf(pout, " \"command\" \"%s\"", id_resp_command);
-+ if (strlen(id_resp_arguments)) {
-+ prot_printf(pout, " \"arguments\" \"%s\"", id_resp_arguments);
-+ } else {
-+ prot_printf(pout, " \"arguments\" NIL");
-+ }
-+#endif
-+
-+ /* SASL information */
-+ snprintf(env_buf, MAXIDVALUELEN,"Built w/Cyrus SASL %d.%d.%d",
-+ SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP);
-+
-+ sasl_version(&sasl_imp, &sasl_ver);
-+ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
-+ "; Running w/%s %d.%d.%d", sasl_imp,
-+ (sasl_ver & 0xFF000000) >> 24,
-+ (sasl_ver & 0x00FF0000) >> 16,
-+ (sasl_ver & 0x0000FFFF));
-+
-+ /* add the environment info */
-+#ifdef DB_VERSION_STRING
-+ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
-+ "; Built w/%s", DB_VERSION_STRING);
-+ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
-+ "; Running w/%s", db_version(NULL, NULL, NULL));
-+#endif
-+#ifdef HAVE_SSL
-+ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
-+ "; Built w/%s", OPENSSL_VERSION_TEXT);
-+ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
-+ "; Running w/%s", SSLeay_version(SSLEAY_VERSION));
-+#ifdef EGD_SOCKET
-+ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
-+ " (with EGD)");
-+#endif
-+#endif
-+#ifdef USE_SIEVE
-+ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
-+ "; %s", SIEVE_VERSION);
-+#endif
-+#ifdef HAVE_LIBWRAP
-+ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
-+ "; TCP Wrappers");
-+#endif
-+#ifdef HAVE_UCDSNMP
-+ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
-+ "; UCD-SNMP %s", VersionInfo);
-+#endif
-+ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
-+ "; mmap = %s", map_method_desc);
-+ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
-+ "; lock = %s", lock_method_desc);
-+ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
-+ "; nonblock = %s", nonblock_method_desc);
-+ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
-+ "; auth = %s", auth_method_desc);
-+#ifdef HAVE_KRB
-+ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
-+ " (%s)", krb4_version);
-+#endif
-+ if (idle_method_desc)
-+ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
-+ "; idle = %s", idle_method_desc);
-+
-+ prot_printf(pout, " \"environment\" \"%s\"", env_buf);
-+}
-diff -urNad cyrus-imapd-2.2.12/lib/imapoptions /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/lib/imapoptions
---- cyrus-imapd-2.2.12/lib/imapoptions 2005-05-24 20:41:38.000000000 +0200
-+++ /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/lib/imapoptions 2005-05-24 20:45:11.561996111 +0200
+diff -urNad cyrus-imapd-2.2.12/lib/imapoptions /tmp/dpep.MaSf95/cyrus-imapd-2.2.12/lib/imapoptions
+--- cyrus-imapd-2.2.12/lib/imapoptions 2005-05-24 22:16:17.000000000 +0200
++++ /tmp/dpep.MaSf95/cyrus-imapd-2.2.12/lib/imapoptions 2005-05-25 00:50:08.226167929 +0200
@@ -196,6 +196,14 @@
{ "deleteright", "c", STRING }
/* The right that a user needs to delete a mailbox. */
@@ -11353,876 +293,3 @@
{ "duplicate_db", "berkeley-nosync", STRINGLIST("berkeley", "berkeley-nosync", "skiplist")}
/* The cyrusdb backend to use for the duplicate delivery suppression
and sieve. */
-diff -urNad cyrus-imapd-2.2.12/lib/imapoptions.orig /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/lib/imapoptions.orig
---- cyrus-imapd-2.2.12/lib/imapoptions.orig 1970-01-01 01:00:00.000000000 +0100
-+++ /tmp/dpep.ReZywS/cyrus-imapd-2.2.12/lib/imapoptions.orig 2005-05-24 20:41:38.000000000 +0200
-@@ -0,0 +1,869 @@
-+# things inside of C comments get copied to the manpage
-+# things starting with # are ignored
-+
-+/* .\" -*- nroff -*-
-+.TH IMAPD.CONF 5 "Project Cyrus" CMU
-+.\"
-+.\" Copyright (c) 1998-2000 Carnegie Mellon University. All rights reserved.
-+.\"
-+.\" Redistribution and use in source and binary forms, with or without
-+.\" modification, are permitted provided that the following conditions
-+.\" are met:
-+.\"
-+.\" 1. Redistributions of source code must retain the above copyright
-+.\" notice, this list of conditions and the following disclaimer.
-+.\"
-+.\" 2. Redistributions in binary form must reproduce the above copyright
-+.\" notice, this list of conditions and the following disclaimer in
-+.\" the documentation and/or other materials provided with the
-+.\" distribution.
-+.\"
-+.\" 3. The name "Carnegie Mellon University" must not be used to
-+.\" endorse or promote products derived from this software without
-+.\" prior written permission. For permission or any other legal
-+.\" details, please contact
-+.\" Office of Technology Transfer
-+.\" Carnegie Mellon University
-+.\" 5000 Forbes Avenue
-+.\" Pittsburgh, PA 15213-3890
-+.\" (412) 268-4387, fax: (412) 268-7395
-+.\" tech-transfer at andrew.cmu.edu
-+.\"
-+.\" 4. Redistributions of any form whatsoever must retain the following
-+.\" acknowledgment:
-+.\" "This product includes software developed by Computing Services
-+.\" at Carnegie Mellon University (http://www.cmu.edu/computing/)."
-+.\"
-+.\" CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
-+.\" THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-+.\" AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
-+.\" FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
-+.\" AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
-+.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+.\"
-+.\" $Id: imapoptions,v 1.30 2004/07/21 19:07:45 rjs3 Exp $
-+.SH NAME
-+imapd.conf \- IMAP configuration file
-+.SH DESCRIPTION
-+\fB/etc/imapd.conf\fR
-+is the configuration file for the Cyrus IMAP server. It defines
-+local parameters for IMAP.
-+.PP
-+Each line of the \fB/etc/imapd.conf\fR file has the form
-+.IP
-+\fIoption\fR: \fIvalue\fR
-+.PP
-+where \fIoption\fR is the name of the configuration option being set
-+and \fIvalue\fR is the value that the configuration option is being
-+set to.
-+.PP
-+Blank lines and lines beginning with ``#'' are ignored.
-+.PP
-+For boolean and enumerated options, the values ``yes'', ``on'', ``t'',
-+``true'' and ``1'' turn the option on, the values ``no'', ``off'',
-+``f'', ``false'' and ``0'' turn the option off.
-+.SH FIELD DESCRIPTIONS
-+.PP
-+The sections below detail options that can be placed in the
-+\fB/etc/imapd.conf\fR file, and show each option's default value.
-+Some options have no default value, these are listed with
-+``<no default>''. Some options default to the empty string, these
-+are listed with ``<none>''.
-+*/
-+
-+# OPTIONS
-+
-+{ "admins", "", STRING }
-+/* The list of userids with administrative rights. Separate each userid
-+ with a space. Sites using Kerberos authentication may use
-+ separate "admin" instances.
-+.PP
-+ Note that accounts used by users should not be administrators.
-+ Administrative accounts should not receive mail. That is, if user
-+ "jbRo" is a user reading mail, he should not also be in the admins line.
-+ Some problems may occur otherwise, most notably the ability of
-+ administrators to create top-level mailboxes visible to users,
-+ but not writable by users. */
-+
-+{ "afspts_localrealms", NULL, STRING }
-+/* The list of realms which are to be treated as local, and thus stripped
-+ during identifier canoicalization (for the AFSPTS ptloader module).
-+ This is different from loginrealms in that it occurs later in the
-+ authorization process (as the user id is canonified for PTS lookup) */
-+
-+{ "afspts_mycell", NULL, STRING }
-+/* Cell to use for AFS PTS lookups. Defaults to the local cell. */
-+
-+{ "allowallsubscribe", 0, SWITCH }
-+/* Allow subscription to nonexistent mailboxes. This option is
-+ typically used on backend servers in a Murder so that users can
-+ subscribe to mailboxes that don't reside on their "home" server.
-+ This option can also be used as a workaround for IMAP clients which
-+ don't play well with nonexistent or unselectable mailboxes (eg.
-+ Microsoft Outlook). */
-+
-+{ "allowanonymouslogin", 0, SWITCH }
-+/* Permit logins by the user "anonymous" using any password. Also
-+ allows use of the SASL ANONYMOUS mechanism. */
-+
-+{ "allowapop", 1, SWITCH }
-+/* Allow use of the POP3 APOP authentication command.
-+.PP
-+ Note that this command requires that SASL is compiled with APOP
-+ support, that the plaintext passwords are available in a SASL auxprop
-+ backend (eg. sasldb), and that the system can provide enough entropy
-+ (eg. from /dev/urandom) to create a challenge in the banner. */
-+
-+{ "allownewnews", 0, SWITCH }
-+/* Allow use of the NNTP NEWNEWS command.
-+.PP
-+ Note that this is a very expensive command and should only be
-+ enabled when absolutely necessary. */
-+
-+{ "allowplaintext", 1, SWITCH }
-+/* Allow the use of cleartext passwords on the wire. */
-+
-+{ "allowusermoves", 0, SWITCH }
-+/* Allow moving user accounts (with associated meta-data) via RENAME
-+ or XFER.
-+.PP
-+ Note that measures should be taken to make sure that the user being
-+ moved is not logged in, and can not login during the move. Failure
-+ to do so may result in the user's meta-data (seen state,
-+ subscriptions, etc) being corrupted or out of date. */
-+
-+{ "altnamespace", 0, SWITCH }
-+/* Use the alternate IMAP namespace, where personal folders reside at the
-+ same level in the hierarchy as INBOX.
-+.PP
-+ This option ONLY applies where interaction takes place with the
-+ client/user. Currently this is limited to the IMAP protocol (imapd)
-+ and Sieve scripts (lmtpd). This option does NOT apply to admin tools
-+ such as cyradm (admins ONLY), reconstruct, quota, etc., NOR does it
-+ affect LMTP delivery of messages directly to mailboxes via
-+ plus-addressing. */
-+
-+{ "annotation_db", "skiplist", STRINGLIST("berkeley", "skiplist")}
-+/* The cyrusdb backend to use for mailbox annotations. */
-+
-+{ "autocreatequota", 0, INT }
-+/* If nonzero, normal users may create their own IMAP accounts by
-+ creating the mailbox INBOX. The user's quota is set to the value
-+ if it is positive, otherwise the user has unlimited quota. */
-+
-+{ "berkeley_cachesize", 512, INT }
-+/* Size (in kilobytes) of the shared memory buffer pool (cache) used
-+ by the berkeley environment. The minimum allowed value is 20. The
-+ maximum allowed value is 4194303 (4GB). */
-+
-+{ "berkeley_locks_max", 50000, INT }
-+/* Maximum number of locks to be held or requested in the berkeley
-+ environment. */
-+
-+{ "berkeley_txns_max", 100, INT }
-+/* Maximum number of transactions to be supported in the berkeley
-+ environment. */
-+
-+{ "client_timeout", 10, INT }
-+/* Number of seconds to wait before returning a timeout failure when
-+ performing a client connection (e.g. in a murder enviornment) */
-+
-+{ "configdirectory", NULL, STRING }
-+/* The pathname of the IMAP configuration directory. This field is
-+ required. */
-+
-+{ "debug_command", NULL, STRING }
-+/* Debug command to be used by processes started with -D option. The string
-+ is a C format string that gets 3 options: the first is the name of the
-+ executable (without path). The second is the pid (integer) and the third
-+ is the service ID. Example: /usr/local/bin/gdb /usr/cyrus/bin/%s %d */
-+
-+{ "defaultacl", "anyone lrs", STRING }
-+/* The Access Control List (ACL) placed on a newly-created (non-user)
-+ mailbox that does not have a parent mailbox. */
-+
-+{ "defaultdomain", NULL, STRING }
-+/* The default domain for virtual domain support. Note that this domain
-+ is stripped from the email-address transmitted using LMTP, but it
-+ is not stripped from usernames at login-time. For imapd/pop3d,
-+ "user" and "user at defaultdomain" specify two different users.
-+ Please check install-virtdomains.html for details. */
-+
-+{ "defaultpartition", "default", STRING }
-+/* The partition name used by default for new mailboxes. */
-+
-+{ "deleteright", "c", STRING }
-+/* The right that a user needs to delete a mailbox. */
-+
-+{ "duplicate_db", "berkeley-nosync", STRINGLIST("berkeley", "berkeley-nosync", "skiplist")}
-+/* The cyrusdb backend to use for the duplicate delivery suppression
-+ and sieve. */
-+
-+{ "duplicatesuppression", 1, SWITCH }
-+/* If enabled, lmtpd will suppress delivery of a message to a mailbox if
-+ a message with the same message-id (or resent-message-id) is recorded
-+ as having already been delivered to the mailbox. Records the mailbox
-+ and message-id/resent-message-id of all successful deliveries. */
-+
-+{ "foolstupidclients", 0, SWITCH }
-+/* If enabled, only list the personal namespace when a LIST "*" is performed.
-+ (it changes the request to a LIST "INBOX*" */
-+
-+{ "force_sasl_client_mech", NULL, STRING }
-+/* Force preference of a given SASL mechanism for client side operations
-+ (e.g. murder enviornments). This is separate from (and overridden by)
-+ the ability to use the <host shortname>_mechs option to set prefered
-+ mechanisms for a specific host */
-+
-+{ "fulldirhash", 0, SWITCH }
-+/* If enabled, uses an improved directory hashing scheme which hashes
-+ the entire username instead of using just the first letter. This
-+ changes hash algorithm used for quota and user directories and if
-+ \fIhashimapspool\fR is enabled, the entire mail spool.
-+.PP
-+ Note that this option can NOT be changed on a live system. The
-+ server must be quiesced and then the directories moved with the
-+ \fBrehash\fR utility. */
-+
-+{ "hashimapspool", 0, SWITCH }
-+/* If enabled, the partitions will also be hashed, in addition to the
-+ hashing done on configuration directories. This is recommended if
-+ one partition has a very bushy mailbox tree. */
-+
-+# Commented out - there's no such thing as "hostname_mechs", but we need
-+# this for the man page
-+# { "hostname_mechs", NULL, STRING }
-+/* Force a particuar list of SASL mechanisms to be used when authenticating
-+ to the backend server hostname (where hostname is the short hostname of
-+ the server in question). If it is not specified it will query the server
-+ for available mechanisms and pick one to use. - Cyrus Murder */
-+
-+# Commented out - there's no such thing as "hostname_password", but we need
-+# this for the man page
-+# { "hostname_password", NULL, STRING }
-+/* The password to use for authentication to the backend server hostname
-+ (where hostname is the short hostname of the server) - Cyrus Murder */
-+
-+{ "idlesocket", "{configdirectory}/socket/idle", STRING }
-+/* Unix domain socket that idled listens on. */
-+
-+{ "ignorereference", 0, SWITCH }
-+/* For backwards compatibility with Cyrus 1.5.10 and earlier -- ignore
-+ the reference argument in LIST or LSUB commands. */
-+
-+{ "imapidlepoll", 60, INT }
-+/* The interval (in seconds) for polling the mailbox for changes while
-+ running the IDLE command. This option is used when idled can not
-+ be contacted or when polling is used exclusively. The minimum
-+ value is 1. A value of 0 will disable polling (and disable IDLE if
-+ polling is the only method available). */
-+
-+{ "imapidresponse", 1, SWITCH }
-+/* If enabled, the server responds to an ID command with a parameter
-+ list containing: version, vendor, support-url, os, os-version,
-+ command, arguments, environment. Otherwise the server returns NIL. */
-+
-+{ "imapmagicplus", 0, SWITCH }
-+/* Only list a restricted set of mailboxes via IMAP by using
-+ userid+namespace syntax as the authentication/authorization id.
-+ Using userid+ (with an empty namespace) will list only subscribed
-+ mailboxes. */
-+
-+{ "implicit_owner_rights", "lca", STRING }
-+/* The implicit Access Control List (ACL) for the owner of a mailbox. */
-+
-+# Commented out - there's no such thing as "@include", but we need
-+# this for the man page
-+# { "@include", NULL, STRING }
-+/* Directive which includes the specified file as part of the
-+ configuration. If the path to the file is not absolute, CYRUS_PATH
-+ is prepended. */
-+
-+{ "ldap_authz", NULL, STRING }
-+/* SASL authorization ID for the LDAP server */
-+
-+{ "ldap_base", "", STRING }
-+/* Contains the LDAP base dn for the LDAP ptloader module */
-+
-+{ "ldap_bind_dn", NULL, STRING }
-+/* Bind DN for the connection to the LDAP server (simple bind).
-+ Do not use for anonymous simple binds */
-+
-+{ "ldap_deref", "never", STRINGLIST("search", "find", "always", "never") }
-+/* Specify how aliases dereferencing is handled during search. */
-+
-+{ "ldap_filter", "(uid=%u)", STRING }
-+/* Specify a filter that searches user identifiers. The following tokens can be
-+ used in the filter string:
-+
-+ %% = %
-+ %u = user
-+ %U = user portion of %u (%U = test when %u = test at domain.tld)
-+ %d = domain portion of %u if available (%d = domain.tld when %u =
-+ %test at domain.tld), otherwise same as %r
-+ %D = user dn. (use when ldap_member_method: filter)
-+ %1-9 = domain tokens (%1 = tld, %2 = domain when %d = domain.tld)
-+
-+ ldap_filter is not used when ldap_sasl is enabled. */
-+
-+{ "ldap_group_base", "", STRING }
-+/* LDAP base dn for ldap_group_filter. */
-+
-+{ "ldap_group_filter", "(cn=%u)", STRING }
-+/* Specify a filter that searches for group identifiers.
-+ See ldap_filter for more options. */
-+
-+{ "ldap_group_scope", "sub", STRINGLIST("sub", "one", "base") }
-+/* Specify search scope for ldap_group_filter. */
-+
-+{ "ldap_id", NULL, STRING }
-+/* SASL authentication ID for the LDAP server */
-+
-+{ "ldap_mech", NULL, STRING }
-+/* SASL mechanism for LDAP authentication */
-+
-+{ "ldap_member_attribute", NULL, STRING }
-+/* See ldap_member_method. */
-+
-+{ "ldap_member_base", "", STRING }
-+/* LDAP base dn for ldap_member_filter. */
-+
-+{ "ldap_member_filter", "(member=%D)", STRING }
-+/* Specify a filter for "ldap_member_method: filter".
-+ See ldap_filter for more options. */
-+
-+{ "ldap_member_method", "attribute", STRINGLIST("attribute", "filter") }
-+/* Specify a group method. The "attribute" method retrieves groups from
-+ a multi-valued attributed specified in ldap_member_attribute.
-+ The "filter" method uses a filter, ldap_member_filter, to find groups;
-+ ldap_member_attribute is a single-value attribute group name. */
-+
-+{ "ldap_member_scope", "sub", STRINGLIST("sub", "one", "base") }
-+/* Specify search scope for ldap_member_filter. */
-+
-+{ "ldap_password", NULL, STRING }
-+/* Password for the connection to the LDAP server (SASL and simple bind).
-+ Do not use for anonymous simple binds */
-+
-+{ "ldap_realm", NULL, STRING }
-+/* SASL realm for LDAP authentication */
-+
-+{ "ldap_referrals", 0, SWITCH }
-+/* Specify whether or not the client should follow referrals. */
-+
-+{ "ldap_restart", 1, SWITCH }
-+/* Specify whether or not LDAP I/O operations are automatically restarted
-+ if they abort prematurely. */
-+
-+{ "ldap_sasl", 1, SWITCH }
-+/* Use SASL for LDAP binds in the LDAP PTS module. */
-+
-+{ "ldap_sasl_authc", NULL, STRING }
-+/* Depricated. Use ldap_id */
-+
-+{ "ldap_sasl_authz", NULL, STRING }
-+/* Depricated. Use ldap_authz */
-+
-+{ "ldap_sasl_mech", NULL, STRING }
-+/* Depricated. Use ldap_mech */
-+
-+{ "ldap_sasl_password", NULL, STRING }
-+/* Depricated. User ldap_password */
-+
-+{ "ldap_sasl_realm", NULL, STRING }
-+/* Depricated. Use ldap_realm */
-+
-+{ "ldap_scope", "sub", STRINGLIST("sub", "one", "base") }
-+/* Specify search scope. */
-+
-+{ "ldap_servers", "ldap://localhost/", STRING }
-+/* Depricated. Use ldap_uri */
-+
-+{ "ldap_size_limit", 1, INT }
-+/* Specify a number of entries for a search request to return. */
-+
-+{ "ldap_start_tls", 0, SWITCH }
-+/* Use StartTLS extended operation. Do not use ldaps: ldap_uri when
-+ this option is enabled. */
-+
-+{ "ldap_time_limit", 5, INT }
-+/* Specify a number of seconds for a search request to complete. */
-+
-+{ "ldap_timeout", 5, INT }
-+/* Specify a number of seconds a search can take before timing out. */
-+
-+{ "ldap_tls_cacert_dir", NULL, STRING }
-+/* Path to directory with CA (Certificate Authority) certificates. */
-+
-+{ "ldap_tls_cacert_file", NULL, STRING }
-+/* File containing CA (Certificate Authority) certificate(s). */
-+
-+{ "ldap_tls_cert", NULL, STRING }
-+/* File containing the client certificate. */
-+
-+{ "ldap_tls_check_peer", 0, SWITCH }
-+/* Require and verify server certificate. If this option is yes,
-+ you must specify ldap_tls_cacert_file or ldap_tls_cacert_dir. */
-+
-+{ "ldap_tls_ciphers", NULL, STRING }
-+/* List of SSL/TLS ciphers to allow. The format of the string is
-+ described in ciphers(1). */
-+
-+{ "ldap_tls_key", NULL, STRING }
-+/* File containing the private client key. */
-+
-+{ "ldap_uri", NULL, STRING }
-+/* Contains a list of the URLs of all the LDAP servers when using the
-+ LDAP PTS module. */
-+
-+{ "ldap_version", 3, INT }
-+/* Specify the LDAP protocol version. If ldap_start_tls and/or
-+ ldap_use_sasl are enabled, ldap_version will be automatiacally
-+ set to 3. */
-+
-+{ "lmtp_downcase_rcpt", 0, SWITCH }
-+/* If enabled, lmtpd will convert the recipient address to lowercase
-+ (up to a '+' character, if present). */
-+
-+{ "lmtp_over_quota_perm_failure", 0, SWITCH }
-+/* If enabled, lmtpd returns a permanent failure code when a user's
-+ mailbox is over quota. By default, the failure is temporary,
-+ causing the MTA to queue the message and retry later. */
-+
-+{ "lmtpsocket", "{configdirectory}/socket/lmtp", STRING }
-+/* Unix domain socket that lmtpd listens on, used by deliver(8). This should
-+ match the path specified in cyrus.conf(5). */
-+
-+# xxx how does this tie into virtual domains?
-+{ "loginrealms", "", STRING }
-+/* The list of remote realms whose users may authenticate using cross-realm
-+ authentication identifiers. Seperate each realm name by a space. (A
-+ cross-realm identity is considered any identity returned by SASL
-+ with an "@" in it.) Note that to support multiple virtual domains
-+ on the same interface/IP, you need to list them all as loginreals.
-+ If you don't list them here, your users probably won't be able to
-+ log in. */
-+
-+{ "loginuseacl", 0, SWITCH }
-+/* If enabled, any authentication identity which has \fBa\fR rights on a
-+ user's INBOX may log in as that user. */
-+
-+{ "logtimestamps", 0, SWITCH }
-+/* Include notations in the protocol telemetry logs indicating the number of
-+ seconds since the last command or response. */
-+
-+{ "mailnotifier", NULL, STRING }
-+/* Notifyd(8) method to use for "MAIL" notifications. If not set, "MAIL"
-+ notifications are disabled. */
-+
-+{ "maxmessagesize", 0, INT }
-+/* Maximum incoming LMTP message size. If non-zero, lmtpd will reject
-+ messages larger than \fImaxmessagesize\fR bytes. If set to 0, this
-+ will allow messages of any size (the default). */
-+
-+{ "mboxlist_db", "skiplist", STRINGLIST("flat", "berkeley", "skiplist")}
-+/* The cyrusdb backend to use for the mailbox list. */
-+
-+{ "munge8bit", 1, SWITCH }
-+/* If enabled, lmtpd changes 8-bit characters to `X'. Also see reject8bit.
-+ (A proper soultion to non-ASCII characters in headers is offered by
-+ RFC 2047 and its predecessors.) */
-+
-+# xxx badly worded
-+{ "mupdate_connections_max", 128, INT }
-+/* The max number of connections that a mupdate process will allow, this
-+ is related to the number of file descriptors in the mupdate process.
-+ Beyond this number connections will be immedately issued a BYE response. */
-+
-+{ "mupdate_authname", NULL, STRING }
-+/* The SASL username (Authentication Name) to use when authenticating to the
-+ mupdate server (if needed). */
-+
-+{ "mupdate_password", NULL, STRING }
-+/* The SASL password (if needed) to use when authenticating to the
-+ mupdate server. */
-+
-+{ "mupdate_port", 3905, INT }
-+/* The port of the mupdate server for the Cyrus Murder */
-+
-+{ "mupdate_realm", NULL, STRING }
-+/* The SASL realm (if needed) to use when authenticating to the mupdate
-+ server. */
-+
-+{ "mupdate_retry_delay", 20, INT }
-+/* The base time to wait between connection retries to the mupdate server. */
-+
-+{ "mupdate_server", NULL, STRING }
-+/* The mupdate server for the Cyrus Murder */
-+
-+{ "mupdate_workers_start", 5, INT }
-+/* The number of mupdate worker threads to start */
-+
-+{ "mupdate_workers_minspare", 2, INT }
-+/* The minimum number of idle mupdate worker threads */
-+
-+{ "mupdate_workers_maxspare", 10, INT }
-+/* The maximum number of idle mupdate worker threads */
-+
-+{ "mupdate_workers_max", 50, INT }
-+/* The maximum number of mupdate worker threads (overall) */
-+
-+{ "mupdate_username", "", STRING }
-+/* The SASL username (Authorization Name) to use when authenticating to
-+ the mupdate server */
-+
-+{ "netscapeurl", "http://asg.web.cmu.edu/cyrus/imapd/netscape-admin.html", STRING }
-+/* If enabled at compile time, this specifies a URL to reply when
-+ Netscape asks the server where the mail administration HTTP server
-+ is. The default is a site at CMU with a hopefully informative
-+ message; administrators should set this to a local resource with
-+ some information of greater use. */
-+
-+{ "newsmaster", "news", STRING }
-+/* Userid that is used for checking access controls when executing
-+ Usenet control messages. For instance, to allow articles to be
-+ automatically deleted by cancel messages, give the "news" user
-+ the 'd' right on the desired mailboxes. To allow newsgroups to be
-+ automatically created, deleted and renamed by the corresponding
-+ control messages, give the "news" user the 'c' right on the desired
-+ mailbox hierarchies. */
-+
-+{ "newspeer", NULL, STRING }
-+/* A list of whitespace-separated news server specifications to which
-+ articles should be fed. Each server specification is a string of
-+ the form [user[:pass]@]host[:port][/wildmat] where 'host' is the fully
-+ qualified hostname of the server, 'port' is the port on which the
-+ server is listening, 'user' and 'pass' are the authentication
-+ credentials and 'wildmat' is a pattern that specifies which groups
-+ should be fed. If no 'port' is specified, port 119 is used. If
-+ no 'wildmat' is specified, all groups are fed. If 'user' is specified
-+ (even if empty), then the NNTP POST command will be used to feed
-+ the article to the server, otherwise the IHAVE command will be
-+ used.
-+.br
-+.sp
-+ A '@' may be used in place of '!' in the wildmat to prevent feeding
-+ articles cross-posted to the given group, otherwise cross-posted
-+ articles are fed if any part of the wildmat matches. For example,
-+ the string "peer.example.com:*,!control.*, at local.*" would feed all
-+ groups except control messages and local groups to
-+ peer.example.com. In the case of cross-posting to local groups,
-+ these articles would not be fed. */
-+
-+{ "newspostuser", NULL, STRING }
-+/* Userid used to deliver usenet articles to newsgroup folders
-+ (usually via lmtp2nntp). For example, if set to "post", email sent
-+ to "post+comp.mail.imap" would be delivered to the "comp.mail.imap"
-+ folder.
-+.br
-+.sp
-+ When set, the Cyrus NNTP server will add a \fITo:\fR header to each
-+ incoming usenet article. This \fITo:\fR header will contain email
-+ delivery addresses corresponding to each newsgroup in the
-+ \fINewsgroups:\fR header. By default, a \fITo:\fR header is not
-+ added to usenet articles. */
-+
-+{ "newsprefix", NULL, STRING }
-+/* Prefix to be prepended to newsgroup names to make the corresponding
-+ IMAP mailbox names. */
-+
-+{ "notifysocket", "{configdirectory}/socket/notify", STRING }
-+/* Unix domain socket that the new mail notification daemon listens on. */
-+
-+# Commented out - there's no such thing as "partition-name", but we need
-+# this for the man page
-+# { "partition-name", NULL, STRING }
-+/* The pathname of the partition \fIname\fR. At least one field, for the
-+ partition named in the \fBdefaultpartition\fR option, is required.
-+ For example, if the value of the \fBdefaultpartion\fR option is
-+ \fBdefault\fR, then the \fBpartition-default\fR field is required. */
-+
-+{ "plaintextloginpause", 0, INT }
-+/* Number of seconds to pause after a successful plaintext login. For
-+ systems that support strong authentication, this permits users to
-+ perceive a cost of using plaintext passwords. (This does not
-+ affect the use of PLAIN in SASL authentications.) */
-+
-+{ "popexpiretime", -1, INT }
-+/* The number of days advertised as being the minimum a message may be
-+ left on the POP server before it is deleted (via the CAPA command,
-+ defined in the POP3 Extension Mechanism, which some clients may
-+ support). "NEVER", the default, may be specified with a negative
-+ number. The Cyrus POP3 server never deletes mail, no matter what
-+ the value of this parameter is. However, if a site implements a
-+ less liberal policy, it needs to change this parameter
-+ accordingly. */
-+
-+{ "popminpoll", 0, INT }
-+/* Set the minimum amount of time the server forces users to wait
-+ between successive POP logins, in minutes. */
-+
-+{ "poptimeout", 10, INT }
-+/* Set the length of the POP server's inactivity autologout timer,
-+ in minutes. The minimum value is 10, the default. */
-+
-+{ "popuseacl", 0, SWITCH }
-+/* Enforce IMAP ACLs in the pop server. Due to the nature of the POP3
-+ protocol, the only rights which are used by the pop server are 'r'
-+ and 'd' for the owner of the mailbox. The 'r' right allows the
-+ user to open the mailbox and list/retrieve messages. The 'd' right
-+ allows the user to delete messages. */
-+
-+{ "postmaster", "postmaster", STRING }
-+/* Username that is used as the 'From' address in rejection MDNs produced
-+ by sieve. */
-+
-+{ "postspec", NULL, STRING }
-+
-+{ "postuser", "", STRING }
-+/* Userid used to deliver messages to shared folders. For example, if
-+ set to "bb", email sent to "bb+shared.blah" would be delivered to
-+ the "shared.blah" folder. By default, an email address of
-+ "+shared.blah" would be used. */
-+
-+{ "proxy_authname", "proxy", STRING }
-+/* The authentication name to use when authenticating to a backend server
-+ in the Cyrus Murder. */
-+
-+{ "proxy_password", NULL, STRING }
-+/* The default password to use when authenticating to a backend server
-+ in the Cyrus Murder. May be overridden on a host-specific basis using
-+ the hostname_password option. */
-+
-+{ "proxy_realm", NULL, STRING }
-+/* The authentication realm to use when authenticating to a backend server
-+ in the Cyrus Murder */
-+
-+{ "proxyd_allow_status_referral", 0, SWITCH }
-+/* Set to true to allow proxyd to issue referrals to clients that support it
-+ when answering the STATUS command. This is disabled by default since
-+ some clients issue many STATUS commands in a row, and do not cache the
-+ connections that these referrals would cause, thus resulting in a higher
-+ authentication load on the respective backend server. */
-+
-+{ "proxyservers", NULL, STRING }
-+/* A list of users and groups that are allowed to proxy for other
-+ users, seperated by spaces. Any user listed in this will be
-+ allowed to login for any other user: use with caution. */
-+
-+{ "ptloader_sock", NULL, STRING }
-+/* Unix domain socket that ptloader listens on.
-+ (defaults to configdir/ptclient/ptsock) */
-+
-+{ "ptscache_db", "berkeley", STRINGLIST("berkeley", "skiplist")}
-+/* The cyrusdb backend to use for the pts cache. */
-+
-+{ "ptscache_timeout", 10800, INT }
-+/* The timeout (in seconds) for the PTS cache database when using the
-+ auth_krb_pts authorization method (default: 3 hours). */
-+
-+{ "ptskrb5_convert524", 1, SWITCH }
-+/* When using the AFSKRB ptloader module with Kerberos 5 canonicalization,
-+ do the final 524 conversion to get a n AFS style name (using '.' instead
-+ of '/', and using short names */
-+
-+{ "ptskrb5_strip_default_realm", 1, SWITCH }
-+/* When using the AFSKRB ptloader module with Kerberos 5 canonicalization,
-+ strip the default realm from the userid (this does not affect the stripping
-+ of realms specified by the afspts_localrealms option) */
-+
-+{ "quota_db", "quotalegacy", STRINGLIST("flat", "berkeley", "skiplist", "quotalegacy")}
-+/* The cyrusdb backend to use for quotas. */
-+
-+{ "quotawarn", 90, INT }
-+/* The percent of quota utilization over which the server generates
-+ warnings. */
-+
-+{ "quotawarnkb", 0, INT }
-+/* The maximum amount of free space (in kB) in which to give a quota
-+ warning (if this value is 0, or if the quota is smaller than this
-+ amount, than warnings are always given). */
-+
-+{ "reject8bit", 0, SWITCH }
-+/* If enabled, lmtpd rejects messages with 8-bit characters in the
-+ headers. Also see munge8bit, which is only applied if reject8bit is
-+ not activated. (A proper soultion to non-ASCII characters in headers
-+ is offered by RFC 2047 and its predecessors.) */
-+
-+{ "rfc2046_strict", 0, SWITCH }
-+/* If enabled, imapd will be strict (per RFC 2046) when matching MIME
-+ boundary strings. This means that boundaries containing other
-+ boundaries as substrings will be treated as identical. Since
-+ enabling this option will break some messages created by Eudora 5.1
-+ (and earlier), it is recommended that it be left disabled unless
-+ there is good reason to do otherwise. */
-+
-+{ "rfc3028_strict", 1, SWITCH }
-+/* If enabled, Sieve will be strict (per RFC 3028) with regards to
-+ which headers are allowed to be used in address and envelope tests.
-+ This means that only those headers which are defined to contain addresses
-+ will be allowed in address tests and only "to" and "from" will be
-+ allowed in envelope tests. When disabled, ANY grammatically correct header
-+ will be allowed. */
-+
-+# Commented out - used by libsasl
-+# { "sasl_auto_transition", 0, SWITCH }
-+/* If enabled, the SASL library will automatically create authentication
-+ secrets when given a plaintext password. See the SASL documentation. */
-+
-+{ "sasl_maximum_layer", 256, INT }
-+/* Maximum SSF (security strength factor) that the server will allow a
-+ client to negotiate. */
-+
-+{ "sasl_minimum_layer", 0, INT }
-+/* The minimum SSF that the server will allow a client to negotiate.
-+ A value of 1 requires integrity protection; any higher value
-+ requires some amount of encryption. */
-+
-+# Commented out - used by libsasl
-+# { "sasl_option", 0, STRING }
-+/* Any SASL option can be set by preceeding it with "sasl_". This
-+ file overrides the SASL configuration file. */
-+
-+# Commented out - used by libsasl
-+# { "sasl_pwcheck_method", NULL, STRING }
-+/* The mechanism used by the server to verify plaintext passwords.
-+ Possible values include "auxprop", "saslauthd", and "pwcheck". */
-+
-+{ "seenstate_db", "skiplist", STRINGLIST("flat", "berkeley", "skiplist")}
-+/* The cyrusdb backend to use for the seen state. */
-+
-+{ "sendmail", "/usr/lib/sendmail", STRING }
-+/* The pathname of the sendmail executable. Sieve invokes sendmail
-+ for sending rejections, redirects and vacation responses. */
-+
-+{ "servername", NULL, STRING }
-+/* This is the hostname visible in the greeting messages of the POP,
-+ IMAP and LMTP daemons. If it is unset, then the result returned
-+ from gethostname(2) is used. */
-+
-+{ "sharedprefix", "Shared Folders", STRING }
-+/* If using the alternate IMAP namespace, the prefix for the shared
-+ namespace. The hierarchy delimiter will be automatically appended. */
-+
-+{ "sieve_maxscriptsize", 32, INT }
-+/* Maximum size (in kilobytes) any sieve script can be, enforced at
-+ submission by timsieved(8). */
-+
-+{ "sieve_maxscripts", 5, INT }
-+/* Maximum number of sieve scripts any user may have, enforced at
-+ submission by timsieved(8). */
-+
-+{ "sievedir", "/usr/sieve", STRING }
-+/* If sieveusehomedir is false, this directory is searched for Sieve
-+ scripts. */
-+
-+{ "sievenotifier", NULL, STRING }
-+/* Notifyd(8) method to use for "SIEVE" notifications. If not set, "SIEVE"
-+ notifications are disabled.
-+.PP
-+ This method is only used when no method is specified in the script. */
-+
-+{ "sieveusehomedir", 0, SWITCH }
-+/* If enabled, lmtpd will look for Sieve scripts in user's home
-+ directories: ~user/.sieve. */
-+
-+{ "singleinstancestore", 1, SWITCH }
-+/* If enabled, lmtpd and nntpd attempt to only write one copy of a message per
-+ partition and create hard links, resulting in a potentially large
-+ disk savings. */
-+
-+{ "skiplist_unsafe", 0, SWITCH }
-+/* If enabled, this option forces the skiplist cyrusdb backend to
-+ not sync writes to the disk. Enabling this option is NOT RECOMMENDED. */
-+
-+{ "soft_noauth", 1, SWITCH }
-+/* If enabled, lmtpd returns temporary failures if the client does not
-+ successfully authenticate. Otherwise lmtpd returns permanant failures
-+ (causing the mail to bounce immediately). */
-+
-+{ "srvtab", "", STRING }
-+/* The pathname of \fIsrvtab\fR file containing the server's private
-+ key. This option is passed to the SASL library and overrides its
-+ default setting. */
-+
-+{ "subscription_db", "flat", STRINGLIST("flat", "berkeley", "skiplist")}
-+/* The cyrusdb backend to use for the subscriptions list. */
-+
-+{ "syslog_prefix", NULL, STRING }
-+/* String to be appended to the process name in syslog entries. */
-+
-+{ "temp_path", "/tmp", STRING }
-+/* The pathname to store temporary files in */
-+
-+{ "timeout", 30, INT }
-+/* The length of the IMAP server's inactivity autologout timer,
-+ in minutes. The minimum value is 30, the default. */
-+
-+{ "tls_ca_file", NULL, STRING }
-+/* File containing one or more Certificate Authority (CA) certificates. */
-+
-+{ "tls_ca_path", NULL, STRING }
-+/* Path to directory with certificates of CAs. This directory must
-+ have filenames with the hashed value of the certificate (see
-+ openssl(XXX)). */
-+
-+{ "tlscache_db", "berkeley-nosync", STRINGLIST("berkeley", "berkeley-nosync", "skiplist")}
-+/* The cyrusdb backend to use for the TLS cache. */
-+
-+{ "tls_cert_file", NULL, STRING }
-+/* File containing the certificate presented for server authentication
-+ during STARTTLS. A value of "disabled" will disable SSL/TLS. */
-+
-+{ "tls_cipher_list", "DEFAULT", STRING }
-+/* The list of SSL/TLS ciphers to allow. The format of the string is
-+ described in ciphers(1). */
-+
-+{ "tls_key_file", NULL, STRING }
-+/* File containing the private key belonging to the server
-+ certificate. A value of "disabled" will disable SSL/TLS. */
-+
-+{ "tls_require_cert", 0, SWITCH }
-+/* Require a client certificate for ALL services (imap, pop3, lmtp, sieve). */
-+
-+{ "tls_session_timeout", 1440, INT }
-+/* The length of time (in minutes) that a TLS session will be cached
-+ for later reuse. The maximum value is 1440 (24 hours), the
-+ default. A value of 0 will disable session caching. */
-+
-+{ "umask", "077", STRING }
-+/* The umask value used by various Cyrus IMAP programs. */
-+
-+{ "username_tolower", 1, SWITCH }
-+/* Convert usernames to all lowercase before login/authenticate. This
-+ is useful with authentication backends which ignore case during
-+ username lookups (such as LDAP). */
-+
-+{ "userprefix", "Other Users", STRING }
-+/* If using the alternate IMAP namespace, the prefix for the other users
-+ namespace. The hierarchy delimiter will be automatically appended. */
-+
-+# xxx badly worded
-+{ "unix_group_enable", 1, SWITCH }
-+/* Should we look up groups when using auth_unix (disable this if you are
-+ not using groups in ACLs for your IMAP server, and you are using auth_unix
-+ with a backend (such as LDAP) that can make getgrent() calls very
-+ slow) */
-+
-+{ "unixhierarchysep", 0, SWITCH }
-+/* Use the UNIX separator character '/' for delimiting levels of
-+ mailbox hierarchy. The default is to use the netnews separator
-+ character '.'. */
-+
-+{ "virtdomains", "off", ENUM("off", "userid", "on") }
-+/* Enable virtual domain support. If enabled, the user's domain will
-+ be determined by splitting a fully qualified userid at the last '@'
-+ or '%' symbol. If the userid is unqualified, and the virtdomains
-+ option is set to "on", then the domain will be determined by doing
-+ a reverse lookup on the IP address of the incoming network
-+ interface, otherwise the user is assumed to be in the default
-+ domain (if set). */
-+
-+/*
-+.SH SEE ALSO
-+.PP
-+\fBimapd(8)\fR, \fBpop3d(8)\fR, \fBnntpd(8)\fR, \fBlmtpd(8)\fR,
-+\fBtimsieved(8)\fR, \fBidled(8)\fR, \fBnotifyd(8)\fR,
-+\fBdeliver(8)\fR, \fBmaster(8)\fR, \fBciphers(1)\fR
-+*/
More information about the Pkg-Cyrus-imapd-Debian-devel
mailing list