[Pkg-Cyrus-imapd-Debian-devel] [SVN] r144 - in
trunk/cyrus-imapd-2.2.12: . debian debian/patches imap lib tools
debian at incase.de
debian at incase.de
Tue Aug 30 15:17:59 UTC 2005
Author: sven
Date: 2005-05-25 00:07:42 +0200 (Wed, 25 May 2005)
New Revision: 144
Added:
trunk/cyrus-imapd-2.2.12/debian/dpatch-run
trunk/cyrus-imapd-2.2.12/debian/patches/
trunk/cyrus-imapd-2.2.12/debian/patches/00list
trunk/cyrus-imapd-2.2.12/debian/patches/20_drac_auth.dpatch
trunk/cyrus-imapd-2.2.12/debian/patches/25_update_install-sh.dpatch
trunk/cyrus-imapd-2.2.12/debian/patches/30_update_perlcalling.sh.dpatch
trunk/cyrus-imapd-2.2.12/debian/patches/35_masssievec_remove_unused_variable.dpatch
trunk/cyrus-imapd-2.2.12/debian/patches/40_rehash_fix_pathes.dpatch
Modified:
trunk/cyrus-imapd-2.2.12/configure.in
trunk/cyrus-imapd-2.2.12/debian/
trunk/cyrus-imapd-2.2.12/debian/changelog
trunk/cyrus-imapd-2.2.12/debian/rules
trunk/cyrus-imapd-2.2.12/imap/Makefile.in
trunk/cyrus-imapd-2.2.12/imap/imapd.c
trunk/cyrus-imapd-2.2.12/imap/pop3d.c
trunk/cyrus-imapd-2.2.12/imap/version.c
trunk/cyrus-imapd-2.2.12/install-sh
trunk/cyrus-imapd-2.2.12/lib/imapoptions
trunk/cyrus-imapd-2.2.12/tools/rehash
Log:
Move serveral patches from patching upstream source directly in diff.gz to patching through dpatch, including DRAC authentication and fixing of perl interpreter calls
Modified: trunk/cyrus-imapd-2.2.12/configure.in
===================================================================
--- trunk/cyrus-imapd-2.2.12/configure.in 2005-05-19 22:30:07 UTC (rev 143)
+++ trunk/cyrus-imapd-2.2.12/configure.in 2005-05-24 22:07:42 UTC (rev 144)
@@ -988,19 +988,6 @@
SNMP_SUBDIRS=""
AC_SUBST(SNMP_SUBDIRS)
-dnl
-dnl Test for DRAC
-dnl
-DRACLIBS=
-AC_ARG_WITH(drac, [ --with-drac=DIR use DRAC library in <DIR> [no] ],
- if test -d "$withval"; then
- LDFLAGS="$LDFLAGS -L${withval}"
- AC_CHECK_LIB(drac, dracauth,
- AC_DEFINE(DRAC_AUTH,[],[Build DRAC support?])
- DRACLIBS="-ldrac")
- fi)
-AC_SUBST(DRACLIBS)
-
CMU_LIBWRAP
CMU_UCDSNMP
Property changes on: trunk/cyrus-imapd-2.2.12/debian
___________________________________________________________________
Name: svn:ignore
+ patched
Modified: trunk/cyrus-imapd-2.2.12/debian/changelog
===================================================================
--- trunk/cyrus-imapd-2.2.12/debian/changelog 2005-05-19 22:30:07 UTC (rev 143)
+++ trunk/cyrus-imapd-2.2.12/debian/changelog 2005-05-24 22:07:42 UTC (rev 144)
@@ -7,8 +7,10 @@
* Eliminate an unused variable from tools/masssievec to get rid of perl
warning.
* Update Recommends and Suggests for cyrus22-common as suggested by HMH
+ * Move several patches from patching the source directly to patching through
+ the use of dpatch
- -- Sven Mueller <debian at incase.de> Sun, 1 May 2005 05:53:15 +0200
+ -- Sven Mueller <debian at incase.de> Tue, 24 May 2005 23:13:18 +0200
cyrus22-imapd (2.2.12-0.4) unstable; urgency=low
Added: trunk/cyrus-imapd-2.2.12/debian/dpatch-run
===================================================================
--- trunk/cyrus-imapd-2.2.12/debian/dpatch-run 2005-05-19 22:30:07 UTC (rev 143)
+++ trunk/cyrus-imapd-2.2.12/debian/dpatch-run 2005-05-24 22:07:42 UTC (rev 144)
@@ -0,0 +1,56 @@
+#!/bin/bash
+
+# derived from dpatch.lib.sh from the dpatch package
+
+set -e
+
+dpatch_lib_patch ()
+{
+ if test "x${DPATCH_LIB_NO_DEFAULT}" = "x"; then
+ patch -p1 --dry-run $* && patch -p1 $*
+ return
+ fi
+ dpatch_patch $*
+}
+
+dpatch_lib_unpatch ()
+{
+ if test "x${DPATCH_LIB_NO_DEFAULT}" = "x"; then
+ patch -p1 --dry-run $* && patch -p1 -R $*
+ return
+ fi
+ dpatch_unpatch $*
+}
+
+
+case $0 in
+ */dpatch-run)
+ patch=$1
+ action=$2
+ workdir=$3
+ ;;
+ *)
+ patch=$0
+ action=$1
+ workdir=$2
+ ;;
+esac
+
+if test "x$action" = "x"; then
+ echo "$(basename ${patch}): script expects -patch|-unpatch as argument" >&2
+ exit 1
+fi
+
+[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts
+patch_opts="${patch_opts:--g0 -f --no-backup-if-mismatch} ${workdir:+-d ${workdir}}"
+
+case "${action}" in
+ -patch) dpatch_lib_patch ${patch_opts} < ${patch};;
+ -unpatch) dpatch_lib_unpatch ${patch_opts} < ${patch};;
+ *)
+ echo "$(basename ${patch}): script expects -patch|-unpatch as argument" >&2
+ exit 1;;
+esac
+
+exit 0
+
Property changes on: trunk/cyrus-imapd-2.2.12/debian/dpatch-run
___________________________________________________________________
Name: svn:executable
+ *
Added: trunk/cyrus-imapd-2.2.12/debian/patches/00list
===================================================================
--- trunk/cyrus-imapd-2.2.12/debian/patches/00list 2005-05-19 22:30:07 UTC (rev 143)
+++ trunk/cyrus-imapd-2.2.12/debian/patches/00list 2005-05-24 22:07:42 UTC (rev 144)
@@ -0,0 +1,5 @@
+20_drac_auth.dpatch
+25_update_install-sh.dpatch
+30_update_perlcalling.sh.dpatch
+35_masssievec_remove_unused_variable
+40_rehash_fix_pathes.dpatch
Added: 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-19 22:30:07 UTC (rev 143)
+++ trunk/cyrus-imapd-2.2.12/debian/patches/20_drac_auth.dpatch 2005-05-24 22:07:42 UTC (rev 144)
@@ -0,0 +1,12228 @@
+#! /bin/sh debian/dpatch-run
+## 20_drac_auth.dpatch by Sven Mueller <debian at incase.de>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Enable DRAC (pop-before-smtp) authentication
+
+ at 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
+@@ -988,6 +988,19 @@
+ SNMP_SUBDIRS=""
+ AC_SUBST(SNMP_SUBDIRS)
+
++dnl
++dnl Test for DRAC
++dnl
++DRACLIBS=
++AC_ARG_WITH(drac, [ --with-drac=DIR use DRAC library in <DIR> [no] ],
++ if test -d "$withval"; then
++ LDFLAGS="$LDFLAGS -L${withval}"
++ AC_CHECK_LIB(drac, dracauth,
++ AC_DEFINE(DRAC_AUTH,[],[Build DRAC support?])
++ DRACLIBS="-ldrac")
++ fi)
++AC_SUBST(DRACLIBS)
++
+ 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
+@@ -69,6 +69,7 @@
+ SIEVE_LIBS = @SIEVE_LIBS@
+ IMAP_COM_ERR_LIBS = @IMAP_COM_ERR_LIBS@
+ LIB_WRAP = @LIB_WRAP@
++DRAC_LIBS = @DRACLIBS@
+ LIBS = $(IMAP_LIBS) $(IMAP_COM_ERR_LIBS)
+ DEPLIBS = ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
+
+@@ -217,17 +218,17 @@
+ 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)
++ libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP) $(DRAC_LIBS)
+
+ 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)
++ $(DEPLIBS) $(LIBS) $(LIB_WRAP) $(DRAC_LIBS)
+
+ 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)
++ $(DEPLIBS) $(LIBS) $(LIB_WRAP) $(DRAC_LIBS) $(DRAC_LIBS)
+
+ proxyd: $(PROXYDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
+ $(CC) $(LDFLAGS) -o proxyd \
+@@ -254,7 +255,7 @@
+
+ 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)
++ mutex_fake.o libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP) $(DRAC_LIBS)
+
+ 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
+@@ -137,6 +137,18 @@
+ 1, 1, &imapd_authstate, &imapd_userisadmin, &imapd_userisproxyadmin
+ };
+
++#ifdef DRAC_AUTH
++static struct {
++ int interval; /* dracd "ping" interval; 0 = disabled */
++ unsigned long clientaddr;
++ struct prot_waitevent *event;
++} drac;
++
++extern int dracconn(char *server, char **errmsg);
++extern int dracsend(unsigned long userip, char **errmsg);
++extern int dracdisc(char **errmsg);
++#endif /* DRAC_AUTH */
++
+ /* current sub-user state */
+ static struct mailbox mboxstruct;
+ static struct mailbox *imapd_mailbox;
+@@ -558,6 +570,23 @@
+ /* setup for sending IMAP IDLE notifications */
+ idle_enabled();
+
++#ifdef DRAC_AUTH
++ /* setup for sending DRAC "pings" */
++ drac.event = NULL;
++ drac.interval = config_getint(IMAPOPT_DRACINTERVAL);
++ if (drac.interval < 0) drac.interval = 0;
++ if (drac.interval) {
++ char *err;
++
++ if (dracconn((char*) config_getstring(IMAPOPT_DRACHOST), &err) != 0) {
++ /* disable DRAC */
++ drac.interval = 0;
++ syslog(LOG_ERR, "dracconn: %s", err);
++ syslog(LOG_ERR, "DRAC notifications disabled");
++ }
++ }
++#endif /* DRAC_AUTH */
++
+ /* create connection to the SNMP listener, if available. */
+ snmp_connect(); /* ignore return code */
+ snmp_set_str(SERVER_NAME_VERSION,CYRUS_VERSION);
+@@ -651,6 +680,15 @@
+ imapd_haveaddr = 1;
+ }
+ }
++
++#ifdef DRAC_AUTH
++ if (((struct sockaddr *)&imapd_remoteaddr)->sa_family == AF_INET)
++ drac.clientaddr = ((struct sockaddr_in *)&imapd_remoteaddr)->sin_addr.s_addr;
++ else
++ drac.clientaddr = 0;
++ } else {
++ drac.clientaddr = 0;
++#endif /* DRAC_AUTH */
+ }
+
+ /* create the SASL connection */
+@@ -693,6 +731,11 @@
+ prot_flush(imapd_out);
+ snmp_increment(ACTIVE_CONNECTIONS, -1);
+
++#ifdef DRAC_AUTH
++ if (drac.event) prot_removewaitevent(imapd_in, drac.event);
++ drac.event = NULL;
++#endif /* DRAC_AUTH */
++
+ /* cleanup */
+ imapd_reset();
+
+@@ -773,6 +816,10 @@
+
+ cyrus_done();
+
++#ifdef DRAC_AUTH
++ if (drac.interval) (void) dracdisc((char **)NULL);
++#endif /* DRAC_AUTH */
++
+ exit(code);
+ }
+
+@@ -810,6 +857,35 @@
+ shut_down(code);
+ }
+
++#ifdef DRAC_AUTH
++/*
++ * Ping dracd every 'drac.interval' minutes
++ * to let it know that we are still connected
++ */
++struct prot_waitevent *drac_ping(struct protstream *s,
++ struct prot_waitevent *ev, void *rock)
++{
++ char *err;
++ static int nfailure = 0;
++
++ if (dracsend(drac.clientaddr, &err) != 0) {
++ syslog(LOG_ERR, "dracsend: %s", err);
++ if (++nfailure >= 3) {
++ /* can't contact dracd for 3 consecutive tries - disable DRAC */
++ prot_removewaitevent(s, ev);
++ drac.event = NULL;
++ syslog(LOG_ERR, "DRAC notifications disabled");
++ return NULL;
++ }
++ }
++ else
++ nfailure = 0;
++
++ ev->mark = time(NULL) + (drac.interval * 60);
++ return ev;
++}
++#endif /* DRAC_AUTH */
++
+ /*
+ * Top-level command loop parsing
+ */
+@@ -1837,6 +1913,11 @@
+
+ prot_printf(imapd_out, "%s OK %s\r\n", tag, reply);
+
++#ifdef DRAC_AUTH
++ if (drac.interval && drac.clientaddr)
++ drac.event = prot_addwaitevent(imapd_in, 0 /* now */, drac_ping, NULL);
++#endif /* DRAC_AUTH */
++
+ /* Create telemetry log */
+ imapd_logfd = telemetry_log(imapd_userid, imapd_in, imapd_out, 0);
+
+@@ -1983,6 +2064,11 @@
+ prot_setsasl(imapd_in, imapd_saslconn);
+ prot_setsasl(imapd_out, imapd_saslconn);
+
++#ifdef DRAC_AUTH
++ if (drac.interval && drac.clientaddr)
++ drac.event = prot_addwaitevent(imapd_in, 0 /* now */, drac_ping, NULL);
++#endif /* DRAC_AUTH */
++
+ /* 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
+@@ -44,6 +44,10 @@
+ */
+ #include <config.h>
+
++#ifdef DRAC_AUTH
++static int drac_enabled;
++extern int dracauth(char *server, unsigned long userip, char **errmsg);
++#endif /* DRAC_AUTH */
+
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+@@ -406,6 +410,10 @@
+ prot_settimeout(popd_in, timeout*60);
+ prot_setflushonread(popd_in, popd_out);
+
++#ifdef DRAC_AUTH
++ drac_enabled = (config_getint(IMAPOPT_DRACINTERVAL) > 0);
++#endif /* DRAC_AUTH */
++
+ if (kflag) kpop();
+
+ /* we were connected on pop3s port so we should do
+@@ -1437,6 +1445,21 @@
+ popd_mailbox = &mboxstruct;
+ proc_register("pop3d", popd_clienthost, popd_userid,
+ popd_mailbox->name);
++
++#ifdef DRAC_AUTH
++ if (drac_enabled &&
++ ((struct sockaddr *)&popd_remoteaddr)->sa_family == AF_INET) {
++ char *err;
++
++ if (dracauth((char*) config_getstring(IMAPOPT_DRACHOST),
++ ((struct sockaddr_in *)&popd_remoteaddr)->sin_addr.s_addr, &err) != 0) {
++ /* disable DRAC */
++ drac_enabled = 0;
++ syslog(LOG_ERR, "dracauth: %s", err);
++ syslog(LOG_ERR, "DRAC notifications disabled");
++ }
++ }
++#endif /* DRAC_AUTH */
+ }
+
+ /* 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
+@@ -151,6 +151,10 @@
+ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
+ "; %s", SIEVE_VERSION);
+ #endif
++#ifdef DRAC_AUTH
++ snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
++ "; DRAC");
++#endif
+ #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
+@@ -196,6 +196,14 @@
+ { "deleteright", "c", STRING }
+ /* The right that a user needs to delete a mailbox. */
+
++{ "dracinterval", 5, INT }
++/* If nonzero, enables the use of DRAC (Dynamic Relay Authorization
++ Control) by the pop3d and imapd daemons. Also sets the interval
++ (in minutes) between re-authorization requests made by imapd. */
++
++{ "drachost", "localhost", STRING }
++/* Hostname of the RPC dracd server. */
++
+ { "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
++*/
Property changes on: trunk/cyrus-imapd-2.2.12/debian/patches/20_drac_auth.dpatch
___________________________________________________________________
Name: svn:executable
+ *
Added: trunk/cyrus-imapd-2.2.12/debian/patches/25_update_install-sh.dpatch
===================================================================
--- trunk/cyrus-imapd-2.2.12/debian/patches/25_update_install-sh.dpatch 2005-05-19 22:30:07 UTC (rev 143)
+++ trunk/cyrus-imapd-2.2.12/debian/patches/25_update_install-sh.dpatch 2005-05-24 22:07:42 UTC (rev 144)
@@ -0,0 +1,501 @@
+#! /bin/sh debian/dpatch-run
+## 25_update_install.sh.dpatch by Sven Mueller <debian at incase.de>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: No description.
+
+ at DPATCH@
+diff -urNad cyrus22-imapd-2.2.12/install-sh /tmp/dpep.WTYlqp/cyrus22-imapd-2.2.12/install-sh
+--- cyrus22-imapd-2.2.12/install-sh 1995-02-10 20:26:06.000000000 +0100
++++ /tmp/dpep.WTYlqp/cyrus22-imapd-2.2.12/install-sh 2005-05-24 21:52:09.605901372 +0200
+@@ -1,23 +1,52 @@
+ #!/bin/sh
+-#
+ # install - install a program, script, or datafile
+-# This comes from X11R5.
++
++scriptversion=2005-02-02.21
++
++# This originates from X11R5 (mit/util/scripts/install.sh), which was
++# later released in X11R6 (xc/config/util/install.sh) with the
++# following copyright and license.
++#
++# Copyright (C) 1994 X Consortium
++#
++# Permission is hereby granted, free of charge, to any person obtaining a copy
++# of this software and associated documentation files (the "Software"), to
++# deal in the Software without restriction, including without limitation the
++# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++# sell copies of the Software, and to permit persons to whom the Software is
++# furnished to do so, subject to the following conditions:
++#
++# The above copyright notice and this permission notice shall be included in
++# all copies or substantial portions of the Software.
++#
++# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
++# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
++# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++#
++# Except as contained in this notice, the name of the X Consortium shall not
++# be used in advertising or otherwise to promote the sale, use or other deal-
++# ings in this Software without prior written authorization from the X Consor-
++# tium.
++#
++#
++# FSF changes to this file are in the public domain.
+ #
+ # Calling this script install-sh is preferred over install.sh, to prevent
+ # `make' implicit rules from creating a file called install from it
+ # when there is no Makefile.
+ #
+ # This script is compatible with the BSD install script, but was written
+-# from scratch.
+-#
+-
++# from scratch. It can only install one file at a time, a restriction
++# shared with many OS's install programs.
+
+ # set DOITPROG to echo to test this script
+
+ # Don't use :- since 4.3BSD and earlier shells don't like it.
+ doit="${DOITPROG-}"
+
+-
+ # put in absolute paths if you don't have them in your path; or use env. vars.
+
+ mvprog="${MVPROG-mv}"
+@@ -29,210 +58,266 @@
+ rmprog="${RMPROG-rm}"
+ mkdirprog="${MKDIRPROG-mkdir}"
+
+-tranformbasename=""
+-transform_arg=""
+-instcmd="$mvprog"
+ chmodcmd="$chmodprog 0755"
+-chowncmd=""
+-chgrpcmd=""
+-stripcmd=""
++chowncmd=
++chgrpcmd=
++stripcmd=
+ rmcmd="$rmprog -f"
+ mvcmd="$mvprog"
+-src=""
+-dst=""
+-dir_arg=""
+-
+-while [ x"$1" != x ]; do
+- case $1 in
+- -c) instcmd="$cpprog"
+- shift
+- continue;;
+-
+- -d) dir_arg=true
+- shift
+- continue;;
+-
+- -m) chmodcmd="$chmodprog $2"
+- shift
+- shift
+- continue;;
++src=
++dst=
++dir_arg=
++dstarg=
++no_target_directory=
+
+- -o) chowncmd="$chownprog $2"
+- shift
+- shift
+- continue;;
++usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
++ or: $0 [OPTION]... SRCFILES... DIRECTORY
++ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
++ or: $0 [OPTION]... -d DIRECTORIES...
+
+- -g) chgrpcmd="$chgrpprog $2"
+- shift
+- shift
+- continue;;
++In the 1st form, copy SRCFILE to DSTFILE.
++In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
++In the 4th, create DIRECTORIES.
+
+- -s) stripcmd="$stripprog"
+- shift
+- continue;;
++Options:
++-c (ignored)
++-d create directories instead of installing files.
++-g GROUP $chgrpprog installed files to GROUP.
++-m MODE $chmodprog installed files to MODE.
++-o USER $chownprog installed files to USER.
++-s $stripprog installed files.
++-t DIRECTORY install into DIRECTORY.
++-T report an error if DSTFILE is a directory.
++--help display this help and exit.
++--version display version info and exit.
+
+- -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+- shift
+- continue;;
++Environment variables override the default commands:
++ CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
++"
+
+- -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+- shift
+- continue;;
++while test -n "$1"; do
++ case $1 in
++ -c) shift
++ continue;;
+
+- *) if [ x"$src" = x ]
+- then
+- src=$1
+- else
+- # this colon is to work around a 386BSD /bin/sh bug
+- :
+- dst=$1
+- fi
+- shift
+- continue;;
+- esac
+-done
++ -d) dir_arg=true
++ shift
++ continue;;
+
+-if [ x"$src" = x ]
+-then
+- echo "install: no input file specified"
+- exit 1
+-else
+- true
+-fi
++ -g) chgrpcmd="$chgrpprog $2"
++ shift
++ shift
++ continue;;
+
+-if [ x"$dir_arg" != x ]; then
+- dst=$src
+- src=""
+-
+- if [ -d $dst ]; then
+- instcmd=:
+- else
+- instcmd=mkdir
+- fi
+-else
++ --help) echo "$usage"; exit $?;;
+
+-# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+-# might cause directories to be created, which would be especially bad
+-# if $src (and thus $dsttmp) contains '*'.
++ -m) chmodcmd="$chmodprog $2"
++ shift
++ shift
++ continue;;
+
+- if [ -f $src -o -d $src ]
+- then
+- true
+- else
+- echo "install: $src does not exist"
+- exit 1
+- fi
+-
+- if [ x"$dst" = x ]
+- then
+- echo "install: no destination specified"
+- exit 1
+- else
+- true
+- fi
++ -o) chowncmd="$chownprog $2"
++ shift
++ shift
++ continue;;
+
+-# If destination is a directory, append the input filename; if your system
+-# does not like double slashes in filenames, you may need to add some logic
++ -s) stripcmd=$stripprog
++ shift
++ continue;;
+
+- if [ -d $dst ]
+- then
+- dst="$dst"/`basename $src`
+- else
+- true
+- fi
+-fi
++ -t) dstarg=$2
++ shift
++ shift
++ continue;;
+
+-## this sed command emulates the dirname command
+-dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
++ -T) no_target_directory=true
++ shift
++ continue;;
+
+-# Make sure that the destination directory exists.
+-# this part is taken from Noah Friedman's mkinstalldirs script
++ --version) echo "$0 $scriptversion"; exit $?;;
+
+-# Skip lots of stat calls in the usual case.
+-if [ ! -d "$dstdir" ]; then
+-defaultIFS='
+-'
+-IFS="${IFS-${defaultIFS}}"
++ *) # When -d is used, all remaining arguments are directories to create.
++ # When -t is used, the destination is already specified.
++ test -n "$dir_arg$dstarg" && break
++ # Otherwise, the last argument is the destination. Remove it from $@.
++ for arg
++ do
++ if test -n "$dstarg"; then
++ # $@ is not empty: it contains at least $arg.
++ set fnord "$@" "$dstarg"
++ shift # fnord
++ fi
++ shift # arg
++ dstarg=$arg
++ done
++ break;;
++ esac
++done
+
+-oIFS="${IFS}"
+-# Some sh's can't handle IFS=/ for some reason.
+-IFS='%'
+-set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+-IFS="${oIFS}"
++if test -z "$1"; then
++ if test -z "$dir_arg"; then
++ echo "$0: no input file specified." >&2
++ exit 1
++ fi
++ # It's OK to call `install-sh -d' without argument.
++ # This can happen when creating conditional directories.
++ exit 0
++fi
+
+-pathcomp=''
++for src
++do
++ # Protect names starting with `-'.
++ case $src in
++ -*) src=./$src ;;
++ esac
+
+-while [ $# -ne 0 ] ; do
+- pathcomp="${pathcomp}${1}"
+- shift
++ if test -n "$dir_arg"; then
++ dst=$src
++ src=
+
+- if [ ! -d "${pathcomp}" ] ;
+- then
+- $mkdirprog "${pathcomp}"
+- else
+- true
+- fi
++ if test -d "$dst"; then
++ mkdircmd=:
++ chmodcmd=
++ else
++ mkdircmd=$mkdirprog
++ fi
++ else
++ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
++ # might cause directories to be created, which would be especially bad
++ # if $src (and thus $dsttmp) contains '*'.
++ if test ! -f "$src" && test ! -d "$src"; then
++ echo "$0: $src does not exist." >&2
++ exit 1
++ fi
+
+- pathcomp="${pathcomp}/"
+-done
+-fi
++ if test -z "$dstarg"; then
++ echo "$0: no destination specified." >&2
++ exit 1
++ fi
+
+-if [ x"$dir_arg" != x ]
+-then
+- $doit $instcmd $dst &&
++ dst=$dstarg
++ # Protect names starting with `-'.
++ case $dst in
++ -*) dst=./$dst ;;
++ esac
+
+- if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+- if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+- if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+- if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+-else
++ # If destination is a directory, append the input filename; won't work
++ # if double slashes aren't ignored.
++ if test -d "$dst"; then
++ if test -n "$no_target_directory"; then
++ echo "$0: $dstarg: Is a directory" >&2
++ exit 1
++ fi
++ dst=$dst/`basename "$src"`
++ fi
++ fi
+
+-# If we're going to rename the final executable, determine the name now.
++ # This sed command emulates the dirname command.
++ dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'`
+
+- if [ x"$transformarg" = x ]
+- then
+- dstfile=`basename $dst`
+- else
+- dstfile=`basename $dst $transformbasename |
+- sed $transformarg`$transformbasename
+- fi
++ # Make sure that the destination directory exists.
+
+-# don't allow the sed command to completely eliminate the filename
++ # Skip lots of stat calls in the usual case.
++ if test ! -d "$dstdir"; then
++ defaultIFS='
++ '
++ IFS="${IFS-$defaultIFS}"
+
+- if [ x"$dstfile" = x ]
+- then
+- dstfile=`basename $dst`
+- else
+- true
+- fi
++ oIFS=$IFS
++ # Some sh's can't handle IFS=/ for some reason.
++ IFS='%'
++ set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
++ shift
++ IFS=$oIFS
+
+-# Make a temp file name in the proper directory.
++ pathcomp=
+
+- dsttmp=$dstdir/#inst.$$#
++ while test $# -ne 0 ; do
++ pathcomp=$pathcomp$1
++ shift
++ if test ! -d "$pathcomp"; then
++ $mkdirprog "$pathcomp"
++ # mkdir can fail with a `File exist' error in case several
++ # install-sh are creating the directory concurrently. This
++ # is OK.
++ test -d "$pathcomp" || exit
++ fi
++ pathcomp=$pathcomp/
++ done
++ fi
+
+-# Move or copy the file name to the temp name
++ if test -n "$dir_arg"; then
++ $doit $mkdircmd "$dst" \
++ && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
++ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
++ && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
++ && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
+
+- $doit $instcmd $src $dsttmp &&
++ else
++ dstfile=`basename "$dst"`
+
+- trap "rm -f ${dsttmp}" 0 &&
++ # Make a couple of temp file names in the proper directory.
++ dsttmp=$dstdir/_inst.$$_
++ rmtmp=$dstdir/_rm.$$_
+
+-# and set any options; do chmod last to preserve setuid bits
++ # Trap to clean up those temp files at exit.
++ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
++ trap '(exit $?); exit' 1 2 13 15
+
+-# If any of these fail, we abort the whole thing. If we want to
+-# ignore errors from any of these, just make sure not to ignore
+-# errors from the above "$doit $instcmd $src $dsttmp" command.
++ # Copy the file name to the temp name.
++ $doit $cpprog "$src" "$dsttmp" &&
+
+- if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+- if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+- if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+- if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
++ # and set any options; do chmod last to preserve setuid bits.
++ #
++ # If any of these fail, we abort the whole thing. If we want to
++ # ignore errors from any of these, just make sure not to ignore
++ # errors from the above "$doit $cpprog $src $dsttmp" command.
++ #
++ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
++ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
++ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
++ && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
+
+-# Now rename the file to the real destination.
++ # Now rename the file to the real destination.
++ { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \
++ || {
++ # The rename failed, perhaps because mv can't rename something else
++ # to itself, or perhaps because mv is so ancient that it does not
++ # support -f.
+
+- $doit $rmcmd -f $dstdir/$dstfile &&
+- $doit $mvcmd $dsttmp $dstdir/$dstfile
++ # Now remove or move aside any old file at destination location.
++ # We try this two ways since rm can't unlink itself on some
++ # systems and the destination file might be busy for other
++ # reasons. In this case, the final cleanup might fail but the new
++ # file should still install successfully.
++ {
++ if test -f "$dstdir/$dstfile"; then
++ $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
++ || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
++ || {
++ echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
++ (exit 1); exit 1
++ }
++ else
++ :
++ fi
++ } &&
+
+-fi &&
++ # Now rename the file to the real destination.
++ $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
++ }
++ }
++ fi || { (exit 1); exit 1; }
++done
+
++# The final little trick to "correctly" pass the exit status to the exit trap.
++{
++ (exit 0); exit 0
++}
+
+-exit 0
++# Local variables:
++# eval: (add-hook 'write-file-hooks 'time-stamp)
++# time-stamp-start: "scriptversion="
++# time-stamp-format: "%:y-%02m-%02d.%02H"
++# time-stamp-end: "$"
++# End:
Property changes on: trunk/cyrus-imapd-2.2.12/debian/patches/25_update_install-sh.dpatch
___________________________________________________________________
Name: svn:executable
+ *
Added: trunk/cyrus-imapd-2.2.12/debian/patches/30_update_perlcalling.sh.dpatch
===================================================================
--- trunk/cyrus-imapd-2.2.12/debian/patches/30_update_perlcalling.sh.dpatch 2005-05-19 22:30:07 UTC (rev 143)
+++ trunk/cyrus-imapd-2.2.12/debian/patches/30_update_perlcalling.sh.dpatch 2005-05-24 22:07:42 UTC (rev 144)
@@ -0,0 +1,494 @@
+#! /bin/sh debian/dpatch-run
+## 30_update_perlcalling.sh.dpatch by Sven Mueller <debian at incase.de>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: updates calling of the perl interpreter to what we expect in Debian.
+## DP: More precisely: Call /usr/bin/perl directly instead of using some
+## DP: shell magic to locate perl and run it.
+## DP: NOTE: only some script use the "-w" or even the "-T" flag for perl.
+## DP: This should be the default actually.
+
+ at DPATCH@
+diff -urNad cyrus-imapd-2.2.12/contrib/cyrus-graphtools.1.0/cgi-bin/cyrus_master.pl /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/contrib/cyrus-graphtools.1.0/cgi-bin/cyrus_master.pl
+--- cyrus-imapd-2.2.12/contrib/cyrus-graphtools.1.0/cgi-bin/cyrus_master.pl 2005-05-24 22:13:04.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/contrib/cyrus-graphtools.1.0/cgi-bin/cyrus_master.pl 2005-05-24 22:44:39.039570899 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl5
++#!/usr/bin/perl
+
+ #
+ # Created by Alison Greenwald <alison at andrew.cmu.edu> 21 Sep 2000
+diff -urNad cyrus-imapd-2.2.12/contrib/cyrus-graphtools.1.0/cgi-bin/graph_cyrus_db-sum.pl /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/contrib/cyrus-graphtools.1.0/cgi-bin/graph_cyrus_db-sum.pl
+--- cyrus-imapd-2.2.12/contrib/cyrus-graphtools.1.0/cgi-bin/graph_cyrus_db-sum.pl 2005-05-24 22:13:04.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/contrib/cyrus-graphtools.1.0/cgi-bin/graph_cyrus_db-sum.pl 2005-05-24 22:44:39.038570809 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl5
++#!/usr/bin/perl
+
+ #
+ # Created by Alison Greenwald 21 Sep 2000
+diff -urNad cyrus-imapd-2.2.12/contrib/cyrus-graphtools.1.0/cgi-bin/graph_cyrus_db.pl /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/contrib/cyrus-graphtools.1.0/cgi-bin/graph_cyrus_db.pl
+--- cyrus-imapd-2.2.12/contrib/cyrus-graphtools.1.0/cgi-bin/graph_cyrus_db.pl 2005-05-24 22:13:04.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/contrib/cyrus-graphtools.1.0/cgi-bin/graph_cyrus_db.pl 2005-05-24 22:44:39.038570809 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl5
++#!/usr/bin/perl
+
+ #
+ # Created by Alison Greenwald <alison at andrew.cmu.edu> 21 Sep 2000
+diff -urNad cyrus-imapd-2.2.12/contrib/mupdate-test.pl /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/contrib/mupdate-test.pl
+--- cyrus-imapd-2.2.12/contrib/mupdate-test.pl 2005-05-24 22:13:04.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/contrib/mupdate-test.pl 2005-05-24 22:44:39.048571710 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ # Create a workload against a murder frontend
+ # that will give the MUPDATE server a workout.
+diff -urNad cyrus-imapd-2.2.12/perl/imap/examples/auditmbox.pl /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/perl/imap/examples/auditmbox.pl
+--- cyrus-imapd-2.2.12/perl/imap/examples/auditmbox.pl 2005-05-24 22:13:05.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/perl/imap/examples/auditmbox.pl 2005-05-24 22:44:39.058572611 +0200
+@@ -1,4 +1,4 @@
+-#! /usr/bin/perl -w
++#!/usr/bin/perl -w
+ #
+ # Copyright (c) 2000 Carnegie Mellon University. All rights reserved.
+ #
+diff -urNad cyrus-imapd-2.2.12/perl/imap/examples/imapcollate.pl /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/perl/imap/examples/imapcollate.pl
+--- cyrus-imapd-2.2.12/perl/imap/examples/imapcollate.pl 2005-05-24 22:13:05.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/perl/imap/examples/imapcollate.pl 2005-05-24 22:44:39.057572521 +0200
+@@ -1,4 +1,4 @@
+-#! /usr/bin/perl -w
++#!/usr/bin/perl -w
+ #
+ # Copyright (c) 2000 Carnegie Mellon University. All rights reserved.
+ #
+diff -urNad cyrus-imapd-2.2.12/perl/imap/examples/imapdu.pl /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/perl/imap/examples/imapdu.pl
+--- cyrus-imapd-2.2.12/perl/imap/examples/imapdu.pl 2005-05-24 22:13:05.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/perl/imap/examples/imapdu.pl 2005-05-24 22:44:39.059572701 +0200
+@@ -1,4 +1,4 @@
+-#! /usr/local/bin/perl -w
++#!/usr/bin/perl -w
+ #
+ # $Id: imapdu.pl,v 1.8 2001/11/30 19:30:45 leg Exp $
+ #
+diff -urNad cyrus-imapd-2.2.12/perl/imap/examples/test-imsp.pl /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/perl/imap/examples/test-imsp.pl
+--- cyrus-imapd-2.2.12/perl/imap/examples/test-imsp.pl 2005-05-24 22:13:05.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/perl/imap/examples/test-imsp.pl 2005-05-24 22:44:39.057572521 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl -w
++#!/usr/bin/perl -w
+
+ # test-imsp.pl
+ #
+diff -urNad cyrus-imapd-2.2.12/perl/sieve/scripts/installsieve.pl /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/perl/sieve/scripts/installsieve.pl
+--- cyrus-imapd-2.2.12/perl/sieve/scripts/installsieve.pl 2005-05-24 22:13:05.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/perl/sieve/scripts/installsieve.pl 2005-05-24 22:44:39.061572881 +0200
+@@ -1,6 +1,4 @@
+-#! /bin/sh
+-exec perl -x -S $0 ${1+"$@"} # -*-perl-*-
+-#!perl -w
++#!/usr/bin/perl -w
+ #
+ # Copyright (c) 2000 Carnegie Mellon University. All rights reserved.
+ #
+diff -urNad cyrus-imapd-2.2.12/perl/sieve/scripts/sieveshell.pl /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/perl/sieve/scripts/sieveshell.pl
+--- cyrus-imapd-2.2.12/perl/sieve/scripts/sieveshell.pl 2005-05-24 22:13:05.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/perl/sieve/scripts/sieveshell.pl 2005-05-24 22:44:39.062572971 +0200
+@@ -1,6 +1,4 @@
+-#! /bin/sh
+-exec perl -x -S $0 ${1+"$@"} # -*-perl-*-
+-#!perl -w
++#!/usr/bin/perl -w
+ #
+ # Copyright (c) 2000 Carnegie Mellon University. All rights reserved.
+ #
+diff -urNad cyrus-imapd-2.2.12/snmp/snmpgen /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/snmp/snmpgen
+--- cyrus-imapd-2.2.12/snmp/snmpgen 2005-05-24 22:13:05.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/snmp/snmpgen 2005-05-24 22:44:39.073573962 +0200
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!/usr/bin/perl -w
+ #
+ # Copyright (c) 2000 Carnegie Mellon University. All rights reserved.
+ #
+@@ -38,25 +38,8 @@
+ # AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ # OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ #
+-exec perl -x -S $0 ${1+"$@"} # -*-perl-*-
+-#!perl -w
+ # $Id: snmpgen,v 1.17 2004/11/19 17:05:48 shadow Exp $
+
+-if ($] !~ /^5\..*/) {
+- # uh-oh. this isn't perl 5.
+- foreach (split(/:/, $ENV{PATH})) { # try to find "perl5".
+- exec("$_/perl5", "-w", "-x", "-S", $0, @ARGV) if (-x "$_/perl5");
+- }
+- # we failed. bail.
+- die "Your perl is too old; I need perl 5.\n";
+-}
+-
+-# load the real script. this is isolated in an 'eval' so perl4 won't
+-# choke on the perl5-isms.
+-eval join("\n", <DATA>);
+-if ($@) { die "$@"; }
+-
+-__END__
+ require 5;
+
+ #Tim Martin
+diff -urNad cyrus-imapd-2.2.12/tools/arbitronsort.pl /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/arbitronsort.pl
+--- cyrus-imapd-2.2.12/tools/arbitronsort.pl 2005-05-24 22:13:04.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/arbitronsort.pl 2005-05-24 22:44:39.018569008 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ #
+ # This script takes the output of arbitron (run without the -o option)
+diff -urNad cyrus-imapd-2.2.12/tools/config2header /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/config2header
+--- cyrus-imapd-2.2.12/tools/config2header 2005-05-24 22:13:04.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/config2header 2005-05-24 22:44:39.017568918 +0200
+@@ -1,4 +1,5 @@
+-#!/bin/sh
++#!/usr/bin/perl -w
++#
+ # $Id: config2header,v 1.9 2004/06/22 19:02:31 rjs3 Exp $
+ #
+ # Copyright (c) 2001 Carnegie Mellon University. All rights reserved.
+@@ -39,24 +40,6 @@
+ # AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ # OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ #
+-exec perl -x -S $0 ${1+"$@"} # -*-perl-*-
+-#!perl -w
+-
+-if ($] !~ /^5\..*/) {
+- # uh-oh. this isn't perl 5.
+- foreach (split(/:/, $ENV{PATH})) { # try to find "perl5".
+- exec("$_/perl5", "-x", "-S", $0, @ARGV) if (-x "$_/perl5");
+- }
+- # we failed. bail.
+- die "Your perl is too old; I need perl 5.\n";
+-}
+-
+-# load the real script. this is isolated in an 'eval' so perl4 won't
+-# choke on the perl5-isms.
+-eval join("\n", <DATA>);
+-if ($@) { die "$@"; }
+-
+-__END__
+ require 5;
+
+ use strict;
+diff -urNad cyrus-imapd-2.2.12/tools/config2man /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/config2man
+--- cyrus-imapd-2.2.12/tools/config2man 2005-05-24 22:13:04.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/config2man 2005-05-24 22:44:39.020569188 +0200
+@@ -1,4 +1,5 @@
+-#!/bin/sh
++#!/usr/bin/perl -w
++#
+ # $Id: config2man,v 1.3 2003/12/09 18:33:52 ken3 Exp $
+ #
+ # Copyright (c) 2001 Carnegie Mellon University. All rights reserved.
+@@ -39,24 +40,6 @@
+ # AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ # OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ #
+-exec perl -x -S $0 ${1+"$@"} # -*-perl-*-
+-#!perl -w
+-
+-if ($] !~ /^5\..*/) {
+- # uh-oh. this isn't perl 5.
+- foreach (split(/:/, $ENV{PATH})) { # try to find "perl5".
+- exec("$_/perl5", "-x", "-S", $0, @ARGV) if (-x "$_/perl5");
+- }
+- # we failed. bail.
+- die "Your perl is too old; I need perl 5.\n";
+-}
+-
+-# load the real script. this is isolated in an 'eval' so perl4 won't
+-# choke on the perl5-isms.
+-eval join("\n", <DATA>);
+-if ($@) { die "$@"; }
+-
+-__END__
+ require 5;
+
+ use strict;
+diff -urNad cyrus-imapd-2.2.12/tools/dohash /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/dohash
+--- cyrus-imapd-2.2.12/tools/dohash 2005-05-24 22:13:04.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/dohash 2005-05-24 22:44:39.023569458 +0200
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!/usr/bin/perl -w
+ #
+ # Copyright (c) 2000 Carnegie Mellon University. All rights reserved.
+ #
+@@ -38,27 +38,11 @@
+ # AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ # OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ #
+-exec perl -x -S $0 ${1+"$@"} # -*-perl-*-
+-#!perl -w
+ # script to upgrade from versions of imapd previous to 1.6.2
+ # make sure you run it as the cyrus user
+ # $Id: dohash,v 1.10 2001/02/23 04:43:01 leg Exp $
++#
+
+-if ($] !~ /^5\..*/) {
+- # uh-oh. this isn't perl 5.
+- foreach (split(/:/, $ENV{PATH})) { # try to find "perl5".
+- exec("$_/perl5", "-x", "-S", $0, @ARGV) if (-x "$_/perl5");
+- }
+- # we failed. bail.
+- die "Your perl is too old; I need perl 5.\n";
+-}
+-
+-# load the real script. this is isolated in an 'eval' so perl4 won't
+-# choke on the perl5-isms.
+-eval join("\n", <DATA>);
+-if ($@) { die "$@"; }
+-
+-__END__
+ require 5;
+
+ $| = 1;
+diff -urNad cyrus-imapd-2.2.12/tools/masssievec /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/masssievec
+--- cyrus-imapd-2.2.12/tools/masssievec 2005-05-24 22:13:04.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/masssievec 2005-05-24 22:44:39.019569098 +0200
+@@ -1,4 +1,6 @@
+-#!/bin/sh
++#!/usr/bin/perl -w
++#
++# Script for mass compilation of sieve scripts.
+ #
+ # Copyright (c) 2000 Carnegie Mellon University. All rights reserved.
+ #
+@@ -38,28 +40,6 @@
+ # AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ # OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ #
+-exec perl -x -S $0 ${1+"$@"} # -*-perl-*-
+-#!perl -w
+-#
+-# Script for mass compilation of sieve scripts.
+-#
+-# $Id: masssievec,v 1.4 2004/06/21 18:44:11 rjs3 Exp $
+-
+-if ($] !~ /^5\..*/) {
+- # uh-oh. this isn't perl 5.
+- foreach (split(/:/, $ENV{PATH})) { # try to find "perl5".
+- exec("$_/perl5", "-x", "-S", $0, @ARGV) if (-x "$_/perl5");
+- }
+- # we failed. bail.
+- die "Your perl is too old; I need perl 5.\n";
+-}
+-
+-# load the real script. this is isolated in an 'eval' so perl4 won't
+-# choke on the perl5-isms.
+-eval join("\n", <DATA>);
+-if ($@) { die "$@"; }
+-
+-__END__
+ require 5;
+
+ $| = 1;
+diff -urNad cyrus-imapd-2.2.12/tools/mkimap /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/mkimap
+--- cyrus-imapd-2.2.12/tools/mkimap 2005-05-24 22:13:04.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/mkimap 2005-05-24 22:44:39.030570089 +0200
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!/usr/bin/perl
+ #
+ # Copyright (c) 2000 Carnegie Mellon University. All rights reserved.
+ #
+@@ -38,25 +38,8 @@
+ # AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ # OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ #
+-exec perl -x -S $0 ${1+"$@"} # -*-perl-*-
+-#!perl -w
+ # $Id: mkimap,v 1.16 2004/06/29 18:16:54 rjs3 Exp $
+
+-if ($] !~ /^5\..*/) {
+- # uh-oh. this isn't perl 5.
+- foreach (split(/:/, $ENV{PATH})) { # try to find "perl5".
+- exec("$_/perl5", "-x", "-S", $0, @ARGV) if (-x "$_/perl5");
+- }
+- # we failed. bail.
+- die "Your perl is too old; I need perl 5.\n";
+-}
+-
+-# load the real script. this is isolated in an 'eval' so perl4 won't
+-# choke on the perl5-isms.
+-eval join("\n", <DATA>);
+-if ($@) { die "$@"; }
+-
+-__END__
+ require 5;
+
+ $imapdconf = shift || "/etc/imapd.conf";
+diff -urNad cyrus-imapd-2.2.12/tools/mknewsgroups /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/mknewsgroups
+--- cyrus-imapd-2.2.12/tools/mknewsgroups 2005-05-24 22:13:04.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/mknewsgroups 2005-05-24 22:44:39.022569368 +0200
+@@ -1,5 +1,8 @@
+-#!/bin/sh
++#!/usr/bin/perl -w
+ #
++# Create newsgroups on imap server
++# Based on the make_fromactive.pl script by Tim Martin
++#
+ # Copyright (c) 2003 Carnegie Mellon University. All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without
+@@ -38,29 +41,6 @@
+ # AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ # OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ #
+-exec perl -x -S $0 ${1+"$@"} # -*-perl-*-
+-#!perl -w
+-#
+-# Create newsgroups on imap server
+-# Based on the make_fromactive.pl script by Tim Martin
+-#
+-# $Id: mknewsgroups,v 1.2 2003/10/22 18:03:47 rjs3 Exp $
+-
+-if ($] !~ /^5\..*/) {
+- # uh-oh. this isn't perl 5.
+- foreach (split(/:/, $ENV{PATH})) { # try to find "perl5".
+- exec("$_/perl5", "-x", "-S", $0, @ARGV) if (-x "$_/perl5");
+- }
+- # we failed. bail.
+- die "Your perl is too old; I need perl 5.\n";
+-}
+-
+-# load the real script. this is isolated in an 'eval' so perl4 won't
+-# choke on the perl5-isms.
+-eval join("\n", <DATA>);
+-if ($@) { die "$@"; }
+-
+-__END__
+ require 5;
+
+ use Getopt::Long;
+diff -urNad cyrus-imapd-2.2.12/tools/rehash /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/rehash
+--- cyrus-imapd-2.2.12/tools/rehash 2005-05-24 22:13:04.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/rehash 2005-05-24 22:44:39.029569999 +0200
+@@ -1,4 +1,8 @@
+-#!/bin/sh
++#!/usr/bin/perl
++# script to upgrade from simple hashing scheme to full hashing scheme
++# make sure you run it as the cyrus user
++#
++# Written by Gary Mills <mills at cc.UManitoba.CA>
+ #
+ # Copyright (c) 2000 Carnegie Mellon University. All rights reserved.
+ #
+@@ -38,8 +42,6 @@
+ # AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ # OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ #
+-exec perl -x -S $0 ${1+"$@"} # -*-perl-*-
+-#!perl -w
+ # script to upgrade from simple hashing scheme to full hashing scheme
+ # make sure you run it as the cyrus user
+ #
+@@ -47,21 +49,6 @@
+ #
+ # $Id: rehash,v 1.7 2003/10/22 18:50:32 rjs3 Exp $
+
+-if ($] !~ /^5\..*/) {
+- # uh-oh. this isn't perl 5.
+- foreach (split(/:/, $ENV{PATH})) { # try to find "perl5".
+- exec("$_/perl5", "-x", "-S", $0, @ARGV) if (-x "$_/perl5");
+- }
+- # we failed. bail.
+- die "Your perl is too old; I need perl 5.\n";
+-}
+-
+-# load the real script. this is isolated in an 'eval' so perl4 won't
+-# choke on the perl5-isms.
+-eval join("\n", <DATA>);
+-if ($@) { die "$@"; }
+-
+-__END__
+ require 5;
+
+ $| = 1;
+diff -urNad cyrus-imapd-2.2.12/tools/translatesieve /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/translatesieve
+--- cyrus-imapd-2.2.12/tools/translatesieve 2005-05-24 22:13:04.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/translatesieve 2005-05-24 22:44:39.027569818 +0200
+@@ -1,6 +1,4 @@
+-#!/bin/sh
+-exec perl -x -S $0 ${1+"$@"} # -*-perl-*-
+-#!perl -w
++#!/usr/bin/perl
+ # script to translate sieve scripts to use unixhierarchysep and/or altnamespace
+ # make sure you run it as the cyrus user
+ #!/usr/bin/perl
+@@ -45,21 +43,6 @@
+ # OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ #
+
+-if ($] !~ /^5\..*/) {
+- # uh-oh. this isn't perl 5.
+- foreach (split(/:/, $ENV{PATH})) { # try to find "perl5".
+- exec("$_/perl5", "-x", "-S", $0, @ARGV) if (-x "$_/perl5");
+- }
+- # we failed. bail.
+- die "Your perl is too old; I need perl 5.\n";
+-}
+-
+-# load the real script. this is isolated in an 'eval' so perl4 won't
+-# choke on the perl5-isms.
+-eval join("\n", <DATA>);
+-if ($@) { die "$@"; }
+-
+-__END__
+ require 5;
+
+ $| = 1;
+diff -urNad cyrus-imapd-2.2.12/tools/undohash /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/undohash
+--- cyrus-imapd-2.2.12/tools/undohash 2005-05-24 22:13:04.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/undohash 2005-05-24 22:44:39.028569908 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/bin/perl
++#!/usr/bin/perl -w
+ # script to downgrade from cyrus imapd 1.6.2+ to earlier.
+ # do NOT run this script while imapd's are running
+ # $Id: undohash,v 1.7 2002/05/25 19:57:53 leg Exp $
+diff -urNad cyrus-imapd-2.2.12/tools/upgradesieve /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/upgradesieve
+--- cyrus-imapd-2.2.12/tools/upgradesieve 2005-05-24 22:13:04.000000000 +0200
++++ /tmp/dpep.36VuGh/cyrus-imapd-2.2.12/tools/upgradesieve 2005-05-24 22:44:39.021569278 +0200
+@@ -1,6 +1,4 @@
+-#!/bin/sh
+-exec perl -x -S $0 ${1+"$@"} # -*-perl-*-
+-#!perl -w
++#!/usr/bin/perl -w
+ # script to upgrade sievedir from imapd 1.6.13
+ # make sure you run it as the cyrus user
+ #!/usr/bin/perl
+@@ -45,21 +43,6 @@
+ # OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ #
+
+-if ($] !~ /^5\..*/) {
+- # uh-oh. this isn't perl 5.
+- foreach (split(/:/, $ENV{PATH})) { # try to find "perl5".
+- exec("$_/perl5", "-x", "-S", $0, @ARGV) if (-x "$_/perl5");
+- }
+- # we failed. bail.
+- die "Your perl is too old; I need perl 5.\n";
+-}
+-
+-# load the real script. this is isolated in an 'eval' so perl4 won't
+-# choke on the perl5-isms.
+-eval join("\n", <DATA>);
+-if ($@) { die "$@"; }
+-
+-__END__
+ require 5;
+
+ $| = 1;
Property changes on: trunk/cyrus-imapd-2.2.12/debian/patches/30_update_perlcalling.sh.dpatch
___________________________________________________________________
Name: svn:executable
+ *
Added: trunk/cyrus-imapd-2.2.12/debian/patches/35_masssievec_remove_unused_variable.dpatch
===================================================================
--- trunk/cyrus-imapd-2.2.12/debian/patches/35_masssievec_remove_unused_variable.dpatch 2005-05-19 22:30:07 UTC (rev 143)
+++ trunk/cyrus-imapd-2.2.12/debian/patches/35_masssievec_remove_unused_variable.dpatch 2005-05-24 22:07:42 UTC (rev 144)
@@ -0,0 +1,18 @@
+#! /bin/sh debian/dpatch-run
+## 35_masssievec_remove_unused_variable.dpatch by Sven Mueller <debian at incase.de>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Remove the $nosievedir variable which is set once but never used.
+
+ at DPATCH@
+diff -urNad cyrus-imapd-2.2.12/tools/masssievec /tmp/dpep.jwVgoT/cyrus-imapd-2.2.12/tools/masssievec
+--- cyrus-imapd-2.2.12/tools/masssievec 2005-05-24 22:52:49.000000000 +0200
++++ /tmp/dpep.jwVgoT/cyrus-imapd-2.2.12/tools/masssievec 2005-05-24 22:53:24.124865338 +0200
+@@ -72,7 +72,6 @@
+ open CONF, $imapdconf or die "can't open $imapdconf";
+ while (<CONF>) {
+ if (/^sieveusehomedir:\s+(1|t|yes|on)/) {
+- $nosievedir = 1;
+ print "you are storing sieve scripts in user's home directories, this script cannot deal with that\n";
+ exit;
+ }
Property changes on: trunk/cyrus-imapd-2.2.12/debian/patches/35_masssievec_remove_unused_variable.dpatch
___________________________________________________________________
Name: svn:executable
+ *
Added: trunk/cyrus-imapd-2.2.12/debian/patches/40_rehash_fix_pathes.dpatch
===================================================================
(Binary files differ)
Property changes on: trunk/cyrus-imapd-2.2.12/debian/patches/40_rehash_fix_pathes.dpatch
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Modified: trunk/cyrus-imapd-2.2.12/debian/rules
===================================================================
--- trunk/cyrus-imapd-2.2.12/debian/rules 2005-05-19 22:30:07 UTC (rev 143)
+++ trunk/cyrus-imapd-2.2.12/debian/rules 2005-05-24 22:07:42 UTC (rev 144)
@@ -19,6 +19,9 @@
export DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
export DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+# enable dpatch usage
+include /usr/share/dpatch/dpatch.make
+
# Extra version information to add to Cyrus IMAPd ID
DEBVERSION:=$(shell LCALL=C dpkg-parsechangelog | sed -ne 's/^Version: \(.*-\)/\1/p')
EXTRA_IDENT:="Debian-$(DEBVERSION)"
Modified: trunk/cyrus-imapd-2.2.12/imap/Makefile.in
===================================================================
--- trunk/cyrus-imapd-2.2.12/imap/Makefile.in 2005-05-19 22:30:07 UTC (rev 143)
+++ trunk/cyrus-imapd-2.2.12/imap/Makefile.in 2005-05-24 22:07:42 UTC (rev 144)
@@ -69,7 +69,6 @@
SIEVE_LIBS = @SIEVE_LIBS@
IMAP_COM_ERR_LIBS = @IMAP_COM_ERR_LIBS@
LIB_WRAP = @LIB_WRAP@
-DRAC_LIBS = @DRACLIBS@
LIBS = $(IMAP_LIBS) $(IMAP_COM_ERR_LIBS)
DEPLIBS = ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
@@ -218,17 +217,17 @@
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) $(DRAC_LIBS)
+ 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) $(DRAC_LIBS)
+ $(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) $(DRAC_LIBS) $(DRAC_LIBS)
+ $(DEPLIBS) $(LIBS) $(LIB_WRAP)
proxyd: $(PROXYDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
$(CC) $(LDFLAGS) -o proxyd \
@@ -255,7 +254,7 @@
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) $(DRAC_LIBS)
+ 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)
Modified: trunk/cyrus-imapd-2.2.12/imap/imapd.c
===================================================================
--- trunk/cyrus-imapd-2.2.12/imap/imapd.c 2005-05-19 22:30:07 UTC (rev 143)
+++ trunk/cyrus-imapd-2.2.12/imap/imapd.c 2005-05-24 22:07:42 UTC (rev 144)
@@ -137,18 +137,6 @@
1, 1, &imapd_authstate, &imapd_userisadmin, &imapd_userisproxyadmin
};
-#ifdef DRAC_AUTH
-static struct {
- int interval; /* dracd "ping" interval; 0 = disabled */
- unsigned long clientaddr;
- struct prot_waitevent *event;
-} drac;
-
-extern int dracconn(char *server, char **errmsg);
-extern int dracsend(unsigned long userip, char **errmsg);
-extern int dracdisc(char **errmsg);
-#endif /* DRAC_AUTH */
-
/* current sub-user state */
static struct mailbox mboxstruct;
static struct mailbox *imapd_mailbox;
@@ -570,23 +558,6 @@
/* setup for sending IMAP IDLE notifications */
idle_enabled();
-#ifdef DRAC_AUTH
- /* setup for sending DRAC "pings" */
- drac.event = NULL;
- drac.interval = config_getint(IMAPOPT_DRACINTERVAL);
- if (drac.interval < 0) drac.interval = 0;
- if (drac.interval) {
- char *err;
-
- if (dracconn((char*) config_getstring(IMAPOPT_DRACHOST), &err) != 0) {
- /* disable DRAC */
- drac.interval = 0;
- syslog(LOG_ERR, "dracconn: %s", err);
- syslog(LOG_ERR, "DRAC notifications disabled");
- }
- }
-#endif /* DRAC_AUTH */
-
/* create connection to the SNMP listener, if available. */
snmp_connect(); /* ignore return code */
snmp_set_str(SERVER_NAME_VERSION,CYRUS_VERSION);
@@ -680,15 +651,6 @@
imapd_haveaddr = 1;
}
}
-
-#ifdef DRAC_AUTH
- if (((struct sockaddr *)&imapd_remoteaddr)->sa_family == AF_INET)
- drac.clientaddr = ((struct sockaddr_in *)&imapd_remoteaddr)->sin_addr.s_addr;
- else
- drac.clientaddr = 0;
- } else {
- drac.clientaddr = 0;
-#endif /* DRAC_AUTH */
}
/* create the SASL connection */
@@ -731,11 +693,6 @@
prot_flush(imapd_out);
snmp_increment(ACTIVE_CONNECTIONS, -1);
-#ifdef DRAC_AUTH
- if (drac.event) prot_removewaitevent(imapd_in, drac.event);
- drac.event = NULL;
-#endif /* DRAC_AUTH */
-
/* cleanup */
imapd_reset();
@@ -816,10 +773,6 @@
cyrus_done();
-#ifdef DRAC_AUTH
- if (drac.interval) (void) dracdisc((char **)NULL);
-#endif /* DRAC_AUTH */
-
exit(code);
}
@@ -857,36 +810,7 @@
shut_down(code);
}
-#ifdef DRAC_AUTH
/*
- * Ping dracd every 'drac.interval' minutes
- * to let it know that we are still connected
- */
-struct prot_waitevent *drac_ping(struct protstream *s,
- struct prot_waitevent *ev, void *rock)
-{
- char *err;
- static int nfailure = 0;
-
- if (dracsend(drac.clientaddr, &err) != 0) {
- syslog(LOG_ERR, "dracsend: %s", err);
- if (++nfailure >= 3) {
- /* can't contact dracd for 3 consecutive tries - disable DRAC */
- prot_removewaitevent(s, ev);
- drac.event = NULL;
- syslog(LOG_ERR, "DRAC notifications disabled");
- return NULL;
- }
- }
- else
- nfailure = 0;
-
- ev->mark = time(NULL) + (drac.interval * 60);
- return ev;
-}
-#endif /* DRAC_AUTH */
-
-/*
* Top-level command loop parsing
*/
void cmdloop()
@@ -1913,11 +1837,6 @@
prot_printf(imapd_out, "%s OK %s\r\n", tag, reply);
-#ifdef DRAC_AUTH
- if (drac.interval && drac.clientaddr)
- drac.event = prot_addwaitevent(imapd_in, 0 /* now */, drac_ping, NULL);
-#endif /* DRAC_AUTH */
-
/* Create telemetry log */
imapd_logfd = telemetry_log(imapd_userid, imapd_in, imapd_out, 0);
@@ -2064,11 +1983,6 @@
prot_setsasl(imapd_in, imapd_saslconn);
prot_setsasl(imapd_out, imapd_saslconn);
-#ifdef DRAC_AUTH
- if (drac.interval && drac.clientaddr)
- drac.event = prot_addwaitevent(imapd_in, 0 /* now */, drac_ping, NULL);
-#endif /* DRAC_AUTH */
-
/* Create telemetry log */
imapd_logfd = telemetry_log(imapd_userid, imapd_in, imapd_out, 0);
Modified: trunk/cyrus-imapd-2.2.12/imap/pop3d.c
===================================================================
--- trunk/cyrus-imapd-2.2.12/imap/pop3d.c 2005-05-19 22:30:07 UTC (rev 143)
+++ trunk/cyrus-imapd-2.2.12/imap/pop3d.c 2005-05-24 22:07:42 UTC (rev 144)
@@ -44,10 +44,6 @@
*/
#include <config.h>
-#ifdef DRAC_AUTH
-static int drac_enabled;
-extern int dracauth(char *server, unsigned long userip, char **errmsg);
-#endif /* DRAC_AUTH */
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@@ -410,10 +406,6 @@
prot_settimeout(popd_in, timeout*60);
prot_setflushonread(popd_in, popd_out);
-#ifdef DRAC_AUTH
- drac_enabled = (config_getint(IMAPOPT_DRACINTERVAL) > 0);
-#endif /* DRAC_AUTH */
-
if (kflag) kpop();
/* we were connected on pop3s port so we should do
@@ -1445,21 +1437,6 @@
popd_mailbox = &mboxstruct;
proc_register("pop3d", popd_clienthost, popd_userid,
popd_mailbox->name);
-
-#ifdef DRAC_AUTH
- if (drac_enabled &&
- ((struct sockaddr *)&popd_remoteaddr)->sa_family == AF_INET) {
- char *err;
-
- if (dracauth((char*) config_getstring(IMAPOPT_DRACHOST),
- ((struct sockaddr_in *)&popd_remoteaddr)->sin_addr.s_addr, &err) != 0) {
- /* disable DRAC */
- drac_enabled = 0;
- syslog(LOG_ERR, "dracauth: %s", err);
- syslog(LOG_ERR, "DRAC notifications disabled");
- }
- }
-#endif /* DRAC_AUTH */
}
/* Create telemetry log */
Modified: trunk/cyrus-imapd-2.2.12/imap/version.c
===================================================================
--- trunk/cyrus-imapd-2.2.12/imap/version.c 2005-05-19 22:30:07 UTC (rev 143)
+++ trunk/cyrus-imapd-2.2.12/imap/version.c 2005-05-24 22:07:42 UTC (rev 144)
@@ -151,10 +151,6 @@
snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
"; %s", SIEVE_VERSION);
#endif
-#ifdef DRAC_AUTH
- snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
- "; DRAC");
-#endif
#ifdef HAVE_LIBWRAP
snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
"; TCP Wrappers");
Modified: trunk/cyrus-imapd-2.2.12/install-sh
===================================================================
--- trunk/cyrus-imapd-2.2.12/install-sh 2005-05-19 22:30:07 UTC (rev 143)
+++ trunk/cyrus-imapd-2.2.12/install-sh 2005-05-24 22:07:42 UTC (rev 144)
@@ -1,52 +1,23 @@
#!/bin/sh
+#
# install - install a program, script, or datafile
-
-scriptversion=2005-02-02.21
-
-# This originates from X11R5 (mit/util/scripts/install.sh), which was
-# later released in X11R6 (xc/config/util/install.sh) with the
-# following copyright and license.
+# This comes from X11R5.
#
-# Copyright (C) 1994 X Consortium
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to
-# deal in the Software without restriction, including without limitation the
-# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-# sell copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
-# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-# Except as contained in this notice, the name of the X Consortium shall not
-# be used in advertising or otherwise to promote the sale, use or other deal-
-# ings in this Software without prior written authorization from the X Consor-
-# tium.
-#
-#
-# FSF changes to this file are in the public domain.
-#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
-# from scratch. It can only install one file at a time, a restriction
-# shared with many OS's install programs.
+# from scratch.
+#
+
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
+
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
@@ -58,266 +29,210 @@
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
+tranformbasename=""
+transform_arg=""
+instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
-chowncmd=
-chgrpcmd=
-stripcmd=
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
-src=
-dst=
-dir_arg=
-dstarg=
-no_target_directory=
+src=""
+dst=""
+dir_arg=""
-usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
- or: $0 [OPTION]... SRCFILES... DIRECTORY
- or: $0 [OPTION]... -t DIRECTORY SRCFILES...
- or: $0 [OPTION]... -d DIRECTORIES...
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
-In the 1st form, copy SRCFILE to DSTFILE.
-In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
-In the 4th, create DIRECTORIES.
+ -d) dir_arg=true
+ shift
+ continue;;
-Options:
--c (ignored)
--d create directories instead of installing files.
--g GROUP $chgrpprog installed files to GROUP.
--m MODE $chmodprog installed files to MODE.
--o USER $chownprog installed files to USER.
--s $stripprog installed files.
--t DIRECTORY install into DIRECTORY.
--T report an error if DSTFILE is a directory.
---help display this help and exit.
---version display version info and exit.
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
-Environment variables override the default commands:
- CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
-"
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
-while test -n "$1"; do
- case $1 in
- -c) shift
- continue;;
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
- -d) dir_arg=true
- shift
- continue;;
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
- -g) chgrpcmd="$chgrpprog $2"
- shift
- shift
- continue;;
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
- --help) echo "$usage"; exit $?;;
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
- -m) chmodcmd="$chmodprog $2"
- shift
- shift
- continue;;
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
- -o) chowncmd="$chownprog $2"
- shift
- shift
- continue;;
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
- -s) stripcmd=$stripprog
- shift
- continue;;
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
- -t) dstarg=$2
- shift
- shift
- continue;;
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
- -T) no_target_directory=true
- shift
- continue;;
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
- --version) echo "$0 $scriptversion"; exit $?;;
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
- *) # When -d is used, all remaining arguments are directories to create.
- # When -t is used, the destination is already specified.
- test -n "$dir_arg$dstarg" && break
- # Otherwise, the last argument is the destination. Remove it from $@.
- for arg
- do
- if test -n "$dstarg"; then
- # $@ is not empty: it contains at least $arg.
- set fnord "$@" "$dstarg"
- shift # fnord
- fi
- shift # arg
- dstarg=$arg
- done
- break;;
- esac
-done
-
-if test -z "$1"; then
- if test -z "$dir_arg"; then
- echo "$0: no input file specified." >&2
- exit 1
- fi
- # It's OK to call `install-sh -d' without argument.
- # This can happen when creating conditional directories.
- exit 0
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
fi
-for src
-do
- # Protect names starting with `-'.
- case $src in
- -*) src=./$src ;;
- esac
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
- if test -n "$dir_arg"; then
- dst=$src
- src=
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
- if test -d "$dst"; then
- mkdircmd=:
- chmodcmd=
- else
- mkdircmd=$mkdirprog
- fi
- else
- # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
- # might cause directories to be created, which would be especially bad
- # if $src (and thus $dsttmp) contains '*'.
- if test ! -f "$src" && test ! -d "$src"; then
- echo "$0: $src does not exist." >&2
- exit 1
- fi
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
- if test -z "$dstarg"; then
- echo "$0: no destination specified." >&2
- exit 1
- fi
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
- dst=$dstarg
- # Protect names starting with `-'.
- case $dst in
- -*) dst=./$dst ;;
- esac
+pathcomp=''
- # If destination is a directory, append the input filename; won't work
- # if double slashes aren't ignored.
- if test -d "$dst"; then
- if test -n "$no_target_directory"; then
- echo "$0: $dstarg: Is a directory" >&2
- exit 1
- fi
- dst=$dst/`basename "$src"`
- fi
- fi
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
- # This sed command emulates the dirname command.
- dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'`
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
- # Make sure that the destination directory exists.
+ pathcomp="${pathcomp}/"
+done
+fi
- # Skip lots of stat calls in the usual case.
- if test ! -d "$dstdir"; then
- defaultIFS='
- '
- IFS="${IFS-$defaultIFS}"
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
- oIFS=$IFS
- # Some sh's can't handle IFS=/ for some reason.
- IFS='%'
- set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
- shift
- IFS=$oIFS
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
- pathcomp=
+# If we're going to rename the final executable, determine the name now.
- while test $# -ne 0 ; do
- pathcomp=$pathcomp$1
- shift
- if test ! -d "$pathcomp"; then
- $mkdirprog "$pathcomp"
- # mkdir can fail with a `File exist' error in case several
- # install-sh are creating the directory concurrently. This
- # is OK.
- test -d "$pathcomp" || exit
- fi
- pathcomp=$pathcomp/
- done
- fi
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
- if test -n "$dir_arg"; then
- $doit $mkdircmd "$dst" \
- && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
- && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
- && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
- && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
+# don't allow the sed command to completely eliminate the filename
- else
- dstfile=`basename "$dst"`
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
- # Make a couple of temp file names in the proper directory.
- dsttmp=$dstdir/_inst.$$_
- rmtmp=$dstdir/_rm.$$_
+# Make a temp file name in the proper directory.
- # Trap to clean up those temp files at exit.
- trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
- trap '(exit $?); exit' 1 2 13 15
+ dsttmp=$dstdir/#inst.$$#
- # Copy the file name to the temp name.
- $doit $cpprog "$src" "$dsttmp" &&
+# Move or copy the file name to the temp name
- # and set any options; do chmod last to preserve setuid bits.
- #
- # If any of these fail, we abort the whole thing. If we want to
- # ignore errors from any of these, just make sure not to ignore
- # errors from the above "$doit $cpprog $src $dsttmp" command.
- #
- { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
- && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
- && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
- && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
+ $doit $instcmd $src $dsttmp &&
- # Now rename the file to the real destination.
- { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \
- || {
- # The rename failed, perhaps because mv can't rename something else
- # to itself, or perhaps because mv is so ancient that it does not
- # support -f.
+ trap "rm -f ${dsttmp}" 0 &&
- # Now remove or move aside any old file at destination location.
- # We try this two ways since rm can't unlink itself on some
- # systems and the destination file might be busy for other
- # reasons. In this case, the final cleanup might fail but the new
- # file should still install successfully.
- {
- if test -f "$dstdir/$dstfile"; then
- $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
- || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
- || {
- echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
- (exit 1); exit 1
- }
- else
- :
- fi
- } &&
+# and set any options; do chmod last to preserve setuid bits
- # Now rename the file to the real destination.
- $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
- }
- }
- fi || { (exit 1); exit 1; }
-done
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
-# The final little trick to "correctly" pass the exit status to the exit trap.
-{
- (exit 0); exit 0
-}
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-end: "$"
-# End:
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
Modified: trunk/cyrus-imapd-2.2.12/lib/imapoptions
===================================================================
--- trunk/cyrus-imapd-2.2.12/lib/imapoptions 2005-05-19 22:30:07 UTC (rev 143)
+++ trunk/cyrus-imapd-2.2.12/lib/imapoptions 2005-05-24 22:07:42 UTC (rev 144)
@@ -196,14 +196,6 @@
{ "deleteright", "c", STRING }
/* The right that a user needs to delete a mailbox. */
-{ "dracinterval", 5, INT }
-/* If nonzero, enables the use of DRAC (Dynamic Relay Authorization
- Control) by the pop3d and imapd daemons. Also sets the interval
- (in minutes) between re-authorization requests made by imapd. */
-
-{ "drachost", "localhost", STRING }
-/* Hostname of the RPC dracd server. */
-
{ "duplicate_db", "berkeley-nosync", STRINGLIST("berkeley", "berkeley-nosync", "skiplist")}
/* The cyrusdb backend to use for the duplicate delivery suppression
and sieve. */
Modified: trunk/cyrus-imapd-2.2.12/tools/rehash
===================================================================
--- trunk/cyrus-imapd-2.2.12/tools/rehash 2005-05-19 22:30:07 UTC (rev 143)
+++ trunk/cyrus-imapd-2.2.12/tools/rehash 2005-05-24 22:07:42 UTC (rev 144)
@@ -130,7 +130,7 @@
$imapdconf = shift || "/etc/imapd.conf";
$yn = "y";
-$sievedir = "/var/spool/sieve";
+$sievedir = "/usr/sieve";
$nosievedir = 0;
$hashispool = 0;
$virtdomains = 0;
@@ -165,7 +165,7 @@
}
close CONF;
-if (! $conf) { $conf = "/var/lib/cyrus"; }
+if (! $conf) { $conf = "/var/imap"; }
if ($interactive) {
print "upgrade $conf? ";
@@ -539,7 +539,6 @@
or die "couldn't rename .$i/$s/$t to $s/$t";
}
closedir MV;
- rmdir ".$i/$s" or die "could not remove .$i/$s"
}
closedir SUB;
rmdir ".$i" or die "could not remove .$i";
More information about the Pkg-Cyrus-imapd-Debian-devel
mailing list