~ubuntu-branches/ubuntu/karmic/cyrus-imapd-2.2/karmic

« back to all changes in this revision

Viewing changes to debian/patches/20-drac_auth.dpatch

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2006-07-11 18:51:39 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20060711185139-gl3oe4tppp7g3euf
Tags: 2.2.13-4ubuntu1
Synchronize with Debian unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
## DP: Enable DRAC (pop-before-smtp) authentication
6
6
 
7
7
@DPATCH@
8
 
diff -urNad cyrus-imapd-2.2.12/configure.in /tmp/dpep.FoExSn/cyrus-imapd-2.2.12/configure.in
9
 
--- cyrus-imapd-2.2.12/configure.in     2006-02-14 17:13:36.000000000 +0100
10
 
+++ /tmp/dpep.FoExSn/cyrus-imapd-2.2.12/configure.in    2006-02-14 17:13:44.656438535 +0100
11
 
@@ -988,6 +988,19 @@
 
8
diff -urNad cyrus-imapd-2.2.13/configure.in /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/configure.in
 
9
--- cyrus-imapd-2.2.13/configure.in     2006-04-18 20:39:34.000000000 +0200
 
10
+++ /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/configure.in    2006-04-18 20:39:35.682096917 +0200
 
11
@@ -974,6 +974,19 @@
12
12
 SNMP_SUBDIRS=""
13
13
 AC_SUBST(SNMP_SUBDIRS)
14
14
 
28
28
 CMU_LIBWRAP
29
29
 CMU_UCDSNMP
30
30
 
31
 
diff -urNad cyrus-imapd-2.2.12/imap/Makefile.in /tmp/dpep.FoExSn/cyrus-imapd-2.2.12/imap/Makefile.in
32
 
--- cyrus-imapd-2.2.12/imap/Makefile.in 2006-02-14 17:13:36.000000000 +0100
33
 
+++ /tmp/dpep.FoExSn/cyrus-imapd-2.2.12/imap/Makefile.in        2006-02-14 17:13:44.657438437 +0100
 
31
diff -urNad cyrus-imapd-2.2.13/configure.in.orig /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/configure.in.orig
 
32
--- cyrus-imapd-2.2.13/configure.in.orig        1970-01-01 01:00:00.000000000 +0100
 
33
+++ /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/configure.in.orig       2006-04-18 20:39:35.684096723 +0200
 
34
@@ -0,0 +1,1223 @@
 
35
+dnl Process this file with autoconf to produce a configure script.
 
36
+
 
37
+dnl
 
38
+dnl Copyright (c) 1998-2005 Carnegie Mellon University.  All rights reserved.
 
39
+dnl
 
40
+dnl Redistribution and use in source and binary forms, with or without
 
41
+dnl modification, are permitted provided that the following conditions
 
42
+dnl are met:
 
43
+dnl
 
44
+dnl 1. Redistributions of source code must retain the above copyright
 
45
+dnl    notice, this list of conditions and the following disclaimer. 
 
46
+dnl
 
47
+dnl 2. Redistributions in binary form must reproduce the above copyright
 
48
+dnl    notice, this list of conditions and the following disclaimer in
 
49
+dnl    the documentation and/or other materials provided with the
 
50
+dnl    distribution.
 
51
+dnl
 
52
+dnl 3. The name "Carnegie Mellon University" must not be used to
 
53
+dnl    endorse or promote products derived from this software without
 
54
+dnl    prior written permission. For permission or any other legal
 
55
+dnl    details, please contact  
 
56
+dnl      Office of Technology Transfer
 
57
+dnl      Carnegie Mellon University
 
58
+dnl      5000 Forbes Avenue
 
59
+dnl      Pittsburgh, PA  15213-3890
 
60
+dnl      (412) 268-4387, fax: (412) 268-7395
 
61
+dnl      tech-transfer@andrew.cmu.edu
 
62
+dnl
 
63
+dnl 4. Redistributions of any form whatsoever must retain the following
 
64
+dnl    acknowledgment:
 
65
+dnl    \"This product includes software developed by Computing Services
 
66
+dnl     at Carnegie Mellon University (http://www.cmu.edu/computing/).\"
 
67
+dnl
 
68
+dnl CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
69
+dnl THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 
70
+dnl AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
 
71
+dnl FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
72
+dnl WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 
73
+dnl AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 
74
+dnl OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
75
+dnl
 
76
+
 
77
+dnl
 
78
+dnl configure.in for the Cyrus imapd
 
79
+dnl $Id: configure.in,v 1.296 2005/10/13 19:56:14 jeaton Exp $
 
80
+dnl
 
81
+
 
82
+
 
83
+AC_INIT(imap/imapd.c)
 
84
+AC_PREREQ([2.54])
 
85
+AC_CONFIG_HEADER(config.h)
 
86
+AC_CANONICAL_HOST
 
87
+
 
88
+dnl Useful for maintainer mode stuff
 
89
+WARNERROR=-W
 
90
+AC_ARG_ENABLE(warnings-are-errors,[  --enable-warnings-are-errors   add -Werror to most gcc calls], [ if test "$enableval" != "no" ; then WARNERROR=-Werror ; fi ])
 
91
+AC_SUBST(WARNERROR)
 
92
+
 
93
+dnl Useful hook for distributions
 
94
+AC_ARG_WITH(extraident,[  --with-extraident=STRING   use STRING as extra version information],
 
95
+       [AC_DEFINE_UNQUOTED(EXTRA_IDENT,"$withval", [Extra version information for imap/version.h])])
 
96
+
 
97
+AC_CHECK_PROG(MAKEDEPEND,makedepend,makedepend,[`cd ${srcdir};pwd`/tools/not-mkdep])
 
98
+if test "$MAKEDEPEND" != "makedepend"; then
 
99
+        AC_MSG_WARN([Makedepend is not installed on this system.  You should compile and install the version from the makedepend subdirectory.])
 
100
+fi
 
101
+
 
102
+AC_ARG_WITH(login,,AC_ERROR([--with-login is no longer supported.
 
103
+Configure SASL appropriately instead.]))
 
104
+
 
105
+AC_ARG_WITH(cyrus-prefix,[  --with-cyrus-prefix=DIR    use DIR as cyrus server install directory],
 
106
+       cyrus_prefix="$withval",cyrus_prefix="/usr/cyrus")
 
107
+AC_SUBST(cyrus_prefix)
 
108
+AC_DEFINE_UNQUOTED(CYRUS_PATH,"$cyrus_prefix",[Where will we be installed?])
 
109
+AC_ARG_WITH(service-path,[  --with-service-path=DIR    use DIR as service install directory],
 
110
+       service_path="$withval",service_path="$cyrus_prefix/bin")
 
111
+AC_SUBST(service_path)
 
112
+AC_DEFINE_UNQUOTED(SERVICE_PATH,"$service_path",[Directiory to use for service binaries])
 
113
+AC_ARG_WITH(cyrus-user,[  --with-cyrus-user=USERID   use USERID cyrus userid],
 
114
+       cyrus_user="$withval",cyrus_user="cyrus")
 
115
+AC_SUBST(cyrus_user)
 
116
+AC_DEFINE_UNQUOTED(CYRUS_USER, "$cyrus_user",[What user will we run as?])
 
117
+AC_ARG_WITH(cyrus-group,[  --with-cyrus-group=GROUPID use GROUPID cyrus group],
 
118
+       cyrus_group="$withval",cyrus_group="mail")
 
119
+AC_SUBST(cyrus_group)
 
120
+
 
121
+dnl allow users to override $sysconfdir, but retain old default (/etc)
 
122
+dnl if not specified
 
123
+if test $sysconfdir = '${prefix}/etc'; then
 
124
+  sysconfdir="/etc"
 
125
+fi
 
126
+AC_DEFINE_UNQUOTED(SYSCONFDIR,"$sysconfdir",[Config File Location])
 
127
+
 
128
+AC_PROG_CC
 
129
+AC_PROG_RANLIB
 
130
+AC_PROG_MAKE_SET
 
131
+AC_PROG_INSTALL
 
132
+AC_AIX
 
133
+AC_ISC_POSIX
 
134
+AC_PROG_AWK
 
135
+AC_C_CONST
 
136
+dnl fakeroot sometimes fails this test
 
137
+dnl and Debian always supports long filenames anyway
 
138
+dnl AC_SYS_LONG_FILE_NAMES
 
139
+dnl if test $ac_cv_sys_long_file_names = no; then
 
140
+dnl    AC_MSG_ERROR(The Cyrus IMAPD requires support for long file names)
 
141
+dnl fi
 
142
+AC_C_INLINE
 
143
+
 
144
+CMU_C___ATTRIBUTE__
 
145
+CMU_C_FPIC
 
146
+
 
147
+AC_CHECK_SIZEOF(long)
 
148
+
 
149
+dnl check for -R, etc. switch
 
150
+CMU_GUESS_RUNPATH_SWITCH
 
151
+
 
152
+AC_CHECK_HEADERS(unistd.h sys/select.h sys/param.h stdarg.h)
 
153
+AC_REPLACE_FUNCS(memmove strcasecmp ftruncate strerror)
 
154
+AC_CHECK_FUNCS(strlcat strlcpy)
 
155
+AC_HEADER_DIRENT
 
156
+
 
157
+dnl do this before Berkeley DB/IPv6 detection
 
158
+CMU_SOCKETS
 
159
+LIBS="$LIBS ${LIB_SOCKET}"
 
160
+
 
161
+dnl check for IPv6 functions (fall back to sasl's if we don't have them)
 
162
+cyrus_cv_getaddrinfo=yes
 
163
+IPv6_CHECK_FUNC(getaddrinfo, [IPv6_CHECK_FUNC(gai_strerror,
 
164
+       AC_DEFINE(HAVE_GETADDRINFO,[],[Do we have a getaddrinfo?]),
 
165
+       cyrus_cv_getaddrinfo=no)], cyrus_cv_getaddrinfo=no)
 
166
+
 
167
+if test $cyrus_cv_getaddrinfo = no; then
 
168
+       IPV6_OBJS="getaddrinfo.o"
 
169
+fi
 
170
+
 
171
+cyrus_cv_getnameinfo=yes
 
172
+IPv6_CHECK_FUNC(getnameinfo,
 
173
+       AC_DEFINE(HAVE_GETNAMEINFO,[],[Do we have a getnameinfo?]),
 
174
+       cyrus_cv_getnameinfo=no)
 
175
+
 
176
+if test $cyrus_cv_getnameinfo = no; then
 
177
+       IPV6_OBJS="$IPV6_OBJS getnameinfo.o"
 
178
+fi
 
179
+
 
180
+IPv6_CHECK_SS_FAMILY()
 
181
+IPv6_CHECK_SA_LEN()
 
182
+
 
183
+AC_SUBST(IPV6_OBJS)
 
184
+
 
185
+dnl this is to check for time things
 
186
+AC_CHECK_HEADERS(sys/time.h)
 
187
+AC_HEADER_TIME
 
188
+AC_STRUCT_TM
 
189
+AC_STRUCT_TIMEZONE
 
190
+
 
191
+AC_SUBST(CPPFLAGS)
 
192
+AC_SUBST(PRE_SUBDIRS)
 
193
+AC_SUBST(EXTRA_SUBDIRS)
 
194
+AC_SUBST(DEPLIBS)
 
195
+AC_SUBST(LOCALDEFS)
 
196
+AC_FUNC_VPRINTF
 
197
+
 
198
+dnl function for doing each of the database backends
 
199
+dnl parameters: backend name, variable to set, withval
 
200
+
 
201
+CYRUSDB_OBJS="cyrusdb_flat.o cyrusdb_skiplist.o cyrusdb_quotalegacy.o"
 
202
+
 
203
+dnl Berkeley DB Detection
 
204
+
 
205
+AC_ARG_WITH(bdb, [  --with-bdb=DIR          use Berkeley DB (in DIR) [[yes]] ],
 
206
+       with_bdb=$withval, with_bdb="yes")
 
207
+
 
208
+dnl support old-style
 
209
+AC_ARG_WITH(dbdir,, with_bdb=$withval)
 
210
+
 
211
+case "$with_bdb" in
 
212
+  no)
 
213
+       use_berkeley="no"
 
214
+       ;;
 
215
+  yes)
 
216
+       use_berkeley="yes"
 
217
+       with_bdb_lib=none
 
218
+       with_bdb_inc=none
 
219
+       ;;
 
220
+  
 
221
+  *)
 
222
+       use_berkeley="yes"
 
223
+       with_bdb_lib="$with_bdb/lib"
 
224
+       with_bdb_inc="$with_bdb/include"
 
225
+       ;;
 
226
+esac
 
227
+
 
228
+if test "$use_berkeley" != "no"; then
 
229
+  CYRUS_BERKELEY_DB_CHK()
 
230
+
 
231
+  if test "$dblib" = "no"; then
 
232
+    AC_ERROR([Berkeley DB 3.x or later was not found.  You may need to 
 
233
+    supply the --with-bdb-libdir or --with-bdb-incdir configure options.])
 
234
+  fi
 
235
+
 
236
+  if test "$with_bdb_lib" != "none"; then
 
237
+    CMU_ADD_LIBPATH($with_bdb_lib)
 
238
+  fi
 
239
+
 
240
+  BDB_INC=${BDB_INCADD}
 
241
+  BDB_LIB=${BDB_LIBADD}
 
242
+  AC_SUBST(BDB_INC)
 
243
+  AC_SUBST(BDB_LIB)
 
244
+
 
245
+  LIBS="${LIBS} ${BDB_LIBADD}"
 
246
+  CPPFLAGS="${BDB_INCADD} ${CPPFLAGS}"
 
247
+
 
248
+  CYRUSDB_OBJS="$CYRUSDB_OBJS cyrusdb_berkeley.o"
 
249
+  AC_DEFINE(HAVE_BDB,[],[Build in Berkeley DB support?])
 
250
+fi
 
251
+
 
252
+dnl End Berkeley DB Detection
 
253
+
 
254
+AC_SUBST(CYRUSDB_OBJS)
 
255
+
 
256
+SIEVE_SUBDIRS=""
 
257
+sievedir="sieve"
 
258
+AC_ARG_ENABLE(sieve,
 
259
+        [  --disable-sieve         disable Sieve support],
 
260
+       if test "$enableval" = no; then
 
261
+               sievedir="no"
 
262
+       fi)
 
263
+
 
264
+if test "$sievedir" != "no"; then
 
265
+       SIEVE_OBJS="lmtp_sieve.o smtpclient.o"
 
266
+       AC_SUBST(SIEVE_OBJS)
 
267
+       SIEVE_LIBS="../${sievedir}/libsieve.a"
 
268
+       AC_SUBST(SIEVE_LIBS)
 
269
+       SIEVE_CPPFLAGS="-I\$(srcdir)/../$sievedir"
 
270
+       AC_SUBST(SIEVE_CPPFLAGS)
 
271
+       AC_DEFINE(USE_SIEVE,[],[Build in Sieve support?])
 
272
+
 
273
+       dnl Sieve configure stuff
 
274
+       AC_PROG_YACC
 
275
+       AC_PROG_LEX
 
276
+       AC_CHECK_LIB(fl,main)
 
277
+
 
278
+       AC_SEARCH_LIBS(regcomp, rx regex, [
 
279
+                       AC_DEFINE(ENABLE_REGEX,[],[Do we have a decent regex library?])
 
280
+                       AC_CHECK_HEADER(rxposix.h, AC_DEFINE(HAVE_RX,[],[Do we have rxposix.h?]))])
 
281
+               
 
282
+
 
283
+       SIEVE_SUBDIRS="${SIEVE_SUBDIRS} $sievedir"
 
284
+       EXTRA_OUTPUT="${EXTRA_OUTPUT} $sievedir/Makefile"
 
285
+fi
 
286
+
 
287
+AC_SUBST(SIEVE_SUBDIRS)
 
288
+
 
289
+dnl for et routines
 
290
+AC_FUNC_CHECK(strerror,AC_DEFINE(HAS_STRERROR,[],[Do we have strerror()?]),
 
291
+              AC_DEFINE(NEED_SYS_ERRLIST,[],[Do we have a sys_errlist?]))
 
292
+
 
293
+dnl for master fd limits
 
294
+AC_CHECK_HEADERS(sys/resource.h)
 
295
+AC_CHECK_FUNCS(setrlimit)
 
296
+AC_CHECK_FUNCS(getrlimit)
 
297
+
 
298
+dnl for detaching terminal
 
299
+AC_CHECK_FUNCS(daemon setsid)
 
300
+
 
301
+dnl for turning off sockets
 
302
+AC_CHECK_FUNCS(shutdown)
 
303
+
 
304
+AC_EGREP_HEADER(socklen_t, sys/socket.h, AC_DEFINE(HAVE_SOCKLEN_T,[],[Do we have a socklen_t?]))
 
305
+AC_EGREP_HEADER(sockaddr_storage, sys/socket.h,
 
306
+               AC_DEFINE(HAVE_STRUCT_SOCKADDR_STORAGE,[],[Do we have a sockaddr_storage?]))
 
307
+AC_EGREP_HEADER(rlim_t, sys/resource.h, AC_DEFINE(HAVE_RLIM_T,[],[Do we have an rlim_t?]))
 
308
+
 
309
+dnl Bunch of setproctitle stuff
 
310
+spt_type=""
 
311
+AC_CHECK_FUNC(setproctitle,spt_type=SPT_BUILTIN)
 
312
+if test "$spt_type" = ""; then
 
313
+       dnl BSD/OS and FreeBSD put it in -lutil
 
314
+       AC_CHECK_LIB(util,setproctitle,spt_type=SPT_BUILTIN
 
315
+                       LIBS="${LIBS} -lutil")
 
316
+fi
 
317
+if test "$spt_type" = ""; then
 
318
+       AC_CHECK_HEADER(sys/pstat.h,spt_type=SPT_PSTAT)
 
319
+fi
 
320
+if test "$spt_type" = ""; then
 
321
+       AC_CHECK_HEADER(sys/sysnews.h,spt_type=SPT_SYSMIPS)
 
322
+fi
 
323
+if test "$spt_type" = ""; then
 
324
+       AC_MSG_CHECKING(for PS_STRINGS)
 
325
+       AC_CACHE_VAL(cyrus_cv_sys_psstrings, AC_TRY_CPP([
 
326
+#include <machine/vmparam.h>
 
327
+#include <sys/exec.h>
 
328
+#ifndef PS_STRINGS
 
329
+#include </nonexistent>
 
330
+#endif],cyrus_cv_sys_psstrings=yes,cyrus_cv_sys_psstrings=no))
 
331
+       if test $cyrus_cv_sys_psstrings = yes; then
 
332
+               spt_type=SPT_PSSTRINGS
 
333
+       fi
 
334
+       AC_MSG_RESULT($cyrus_cv_sys_psstrings)
 
335
+fi
 
336
+if test "$spt_type" = ""; then
 
337
+       AC_MSG_CHECKING(for SCO)
 
338
+       AC_CACHE_VAL(cyrus_cv_sys_sco, AC_TRY_CPP([
 
339
+#ifndef _SCO_unix_
 
340
+#include </nonexistent>
 
341
+#endif],cyrus_cv_sys_sco=yes,cyrus_cv_sys_sco=no))
 
342
+       if test $cyrus_cv_sys_sco = yes; then
 
343
+               spt_type=SPT_SCO
 
344
+       fi
 
345
+       AC_MSG_RESULT($cyrus_cv_sys_sco)
 
346
+fi
 
347
+if test "$spt_type" = ""; then
 
348
+       AC_MSG_CHECKING(for setproctitle usability)
 
349
+       AC_CACHE_VAL(cyrus_cv_sys_setproctitle, AC_TRY_CPP([
 
350
+#if defined(DGUX) || defined(_SEQUENT_) || defined(apollo)
 
351
+#include </nonexistent>
 
352
+#endif],cyrus_cv_sys_setproctitle=yes,cyrus_cv_sys_setproctitle=no))
 
353
+       if test $cyrus_cv_sys_setproctitle = no; then
 
354
+               spt_type=SPT_NONE
 
355
+       fi
 
356
+       AC_MSG_RESULT($cyrus_cv_sys_setproctitle)
 
357
+fi
 
358
+if test "$spt_type" != ""; then
 
359
+       AC_DEFINE_UNQUOTED(SPT_TYPE,$spt_type,[Do we already have setproctitle?])
 
360
+fi
 
361
+
 
362
+AC_MSG_CHECKING(nonblocking method)
 
363
+AC_CACHE_VAL(cyrus_cv_sys_nonblock,AC_TRY_LINK([#include <sys/types.h>
 
364
+#include <sys/file.h>
 
365
+#include <fcntl.h>
 
366
+#ifndef        FNDELAY
 
367
+#define FNDELAY                O_NDELAY
 
368
+#endif],[fcntl(0, F_GETFL, 0)&FNDELAY],
 
369
+cyrus_cv_sys_nonblock=fcntl,cyrus_cv_sys_nonblock=ioctl))
 
370
+WITH_NONBLOCK=$cyrus_cv_sys_nonblock
 
371
+AC_SUBST(WITH_NONBLOCK)
 
372
+AC_MSG_RESULT($WITH_NONBLOCK)
 
373
+
 
374
+AC_MSG_CHECKING(timezone GMT offset method)
 
375
+AC_CACHE_VAL(cyrus_cv_struct_sys_gmtoff,AC_TRY_COMPILE([
 
376
+#include <time.h>],[struct tm tm;
 
377
+tm.tm_gmtoff = 0;
 
378
+],cyrus_cv_struct_sys_gmtoff=tm,cyrus_cv_struct_sys_gmtoff=gmtime))
 
379
+WITH_GMTOFF=$cyrus_cv_struct_sys_gmtoff
 
380
+AC_SUBST(WITH_GMTOFF)
 
381
+AC_MSG_RESULT($WITH_GMTOFF)
 
382
+AC_MSG_CHECKING(for shared mmap)
 
383
+AC_CACHE_VAL(cyrus_cv_func_mmap_shared,AC_TRY_RUN([
 
384
+#include <sys/types.h>
 
385
+#include <sys/mman.h>
 
386
+#include <fcntl.h>
 
387
+main() {
 
388
+char *base;
 
389
+int fd = open("conftestmmap", O_RDWR|O_CREAT|O_TRUNC, 0666);
 
390
+if (fd == -1) exit(1);
 
391
+if (write(fd, "test", 4) != 4) exit(1);
 
392
+fsync(fd);
 
393
+base = mmap((caddr_t)0, 100, PROT_READ, MAP_SHARED
 
394
+#ifdef MAP_FILE
 
395
+| MAP_FILE
 
396
+#endif
 
397
+#ifdef MAP_VARIABLE
 
398
+| MAP_VARIABLE
 
399
+#endif
 
400
+, fd, 0L);
 
401
+if (base == (caddr_t)-1) exit(1);
 
402
+if (strncmp(base, "test", 4) != 0) exit(1);
 
403
+if (write(fd, "test", 4) != 4) exit(1);
 
404
+fsync(fd);
 
405
+if (strncmp(base+4, "test", 4) != 0) exit(1);
 
406
+exit(0);}
 
407
+],cyrus_cv_func_mmap_shared=yes,cyrus_cv_func_mmap_shared=no,
 
408
+cyrus_cv_func_mmap_shared=no))
 
409
+AC_MSG_RESULT($cyrus_cv_func_mmap_shared)
 
410
+if test $cyrus_cv_func_mmap_shared = yes; then
 
411
+       WITH_MAP="shared"
 
412
+else
 
413
+AC_MSG_CHECKING(for stupid shared mmap)
 
414
+AC_CACHE_VAL(cyrus_cv_func_mmap_stupidshared,AC_TRY_RUN([
 
415
+#include <sys/types.h>
 
416
+#include <sys/mman.h>
 
417
+#include <fcntl.h>
 
418
+main() {
 
419
+char *base;
 
420
+int fd = open("conftestmmap", O_RDWR|O_CREAT|O_TRUNC, 0666);
 
421
+if (fd == -1) exit(1);
 
422
+if (write(fd, "test", 4) != 4) exit(1);
 
423
+fsync(fd);
 
424
+base = mmap((caddr_t)0, 4, PROT_READ, MAP_SHARED
 
425
+#ifdef MAP_FILE
 
426
+| MAP_FILE
 
427
+#endif
 
428
+#ifdef MAP_VARIABLE
 
429
+| MAP_VARIABLE
 
430
+#endif
 
431
+, fd, 0L);
 
432
+if (base == (caddr_t)-1) exit(1);
 
433
+if (strncmp(base, "test", 4) != 0) exit(1);
 
434
+lseek(fd, 0L, 0);      
 
435
+if (write(fd, "xyzz", 4) != 4) exit(1);
 
436
+fsync(fd);
 
437
+if (strncmp(base, "xyzz", 4) != 0) exit(1);
 
438
+exit(0);}
 
439
+],cyrus_cv_func_mmap_stupidshared=yes,cyrus_cv_func_mmap_stupidshared=no,
 
440
+cyrus_cv_func_mmap_stupidshared=no))
 
441
+AC_MSG_RESULT($cyrus_cv_func_mmap_stupidshared)
 
442
+if test $cyrus_cv_func_mmap_stupidshared = yes; then
 
443
+       WITH_MAP="stupidshared"
 
444
+else
 
445
+       AC_MSG_WARN([*** This system does not have a working mmap()])
 
446
+       AC_MSG_WARN(*** Expect a considerable performance penalty)
 
447
+       WITH_MAP=nommap
 
448
+fi
 
449
+fi
 
450
+
 
451
+AC_SUBST(WITH_MAP)
 
452
+AC_ARG_WITH(lock,
 
453
+  [  --with-lock=METHOD      force use of METHOD for locking (flock or fcntl)],
 
454
+  WITH_LOCK="$withval", [
 
455
+  AC_CHECK_FUNC(fcntl,WITH_LOCK="fcntl",[
 
456
+               AC_CHECK_FUNC(flock,WITH_LOCK="flock",[
 
457
+                               AC_ERROR(unable to detect locking method)
 
458
+                             ])
 
459
+               ])
 
460
+  ])
 
461
+
 
462
+AC_SUBST(WITH_LOCK)
 
463
+
 
464
+dnl check for fdatasync (used by cyrusdb_skiplist)
 
465
+LIB_RT=""
 
466
+AC_CHECK_FUNC(fdatasync, AC_DEFINE(HAVE_FDATASYNC,[],[Do we have fdatasync()?]), [
 
467
+  AC_CHECK_LIB(rt, fdatasync, [
 
468
+       LIB_RT="-lrt"
 
469
+       AC_DEFINE(HAVE_FDATASYNC,[],[Do we have fdatasync()?])
 
470
+  ])
 
471
+])
 
472
+
 
473
+dnl for makedepend and AFS.
 
474
+cant_find_sigvec=no
 
475
+AC_CACHE_VAL(cyrus_sigveclib,[
 
476
+ dnl bsd classic flavor
 
477
+ AC_CHECK_FUNC(sigvec, [
 
478
+       cyrus_sigveclib=""
 
479
+  ], [
 
480
+  dnl hp flavor
 
481
+  AC_CHECK_LIB(BSD, sigvec, cyrus_sigveclib="-lBSD", [
 
482
+    dnl not hp flavor
 
483
+    SAVE_LDFLAGS="$LDFLAGS"
 
484
+    dnl solaris flavor
 
485
+    LDFLAGS="-L/usr/ucblib -R/usr/ucblib $LDFLAGS"
 
486
+    AC_CHECK_LIB(ucb, sigvec, [
 
487
+      dnl more solaris flavor
 
488
+      cyrus_sigveclib="-lc -L/usr/ucblib -R/usr/ucblib -lucb"],
 
489
+      [ cant_find_sigvec=yes ])
 
490
+    LDFLAGS="$SAVE_LDFLAGS"])
 
491
+  ])
 
492
+])
 
493
+AC_SUBST(cyrus_sigveclib)
 
494
+
 
495
+# ok, we still look for this stuff because of checking groups, but
 
496
+# all authentication goes through SASL
 
497
+
 
498
+AC_ARG_WITH(afs,[  --with-afs=PATH         use AFS libraries from PATH],
 
499
+       with_afs="${withval}", with_afs="no")
 
500
+
 
501
+AC_ARG_WITH(ldap, [  --with-ldap=DIR         use LDAP (in DIR) (experimental) [/usr/local] ],
 
502
+       with_ldap="${withval}", with_ldap="no")
 
503
+
 
504
+dnl select mode of afspts
 
505
+AC_ARG_ENABLE(krb5afspts,[  --enable-krb5afspts     compile afskrb PTS module with krb5 support],
 
506
+       [SASL_SET_GSSAPI_LIBS
 
507
+         AC_DEFINE(AFSPTS_USE_KRB5,[],[Should the AFS PTS plugin use krb5?])])
 
508
+
 
509
+if test "x$with_afs" != "xno"; then
 
510
+    if test ! -d $with_afs; then
 
511
+        $with_afs=/usr/local
 
512
+    fi
 
513
+    CFLAGS="${CFLAGS} -I${with_afs}/include"
 
514
+    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"
 
515
+    if test -f ${with_afs}/lib/afs/libaudit.a; then
 
516
+    AFS_LIBS="$AFS_LIBS ${with_afs}/lib/afs/libaudit.a"
 
517
+    fi
 
518
+    if test -f /usr/ucblib/libucb.a; then
 
519
+    CMU_ADD_LIBPATH_TO(/usr/ucblib, AFS_LDFLAGS)
 
520
+    AFS_LIBS="$AFS_LIBS -lc -lucb"
 
521
+    fi
 
522
+
 
523
+    AC_CACHE_VAL(cyrus_afs_sigvec,[
 
524
+        SAVE_LIBS="$LIBS"
 
525
+        LIBS="${with_afs}/lib/liblwp.a"
 
526
+        AC_MSG_CHECKING(if AFS libraries need sigvec)
 
527
+        dnl Does AFS need sigvec?  We have to link against lwp and see
 
528
+        dnl if IOMGR_Initialize wants it
 
529
+        AC_TRY_LINK([IOMGR_Initialize();],
 
530
+                [IOMGR_Initialize()],
 
531
+                [
 
532
+                        dnl it linked; don't need it
 
533
+                        AC_MSG_RESULT(no)
 
534
+                        cyrus_afs_sigvec="no"
 
535
+                ], [
 
536
+                        dnl didn't link; pick up sigvec
 
537
+                        AC_MSG_RESULT(yes)
 
538
+                        cyrus_afs_sigvec="yes"
 
539
+                ])
 
540
+        ])
 
541
+    if test "$cyrus_afs_sigvec" = yes; then
 
542
+      if test "$cant_find_sigvec" = yes; then
 
543
+        AC_MSG_WARN([Can't find a sigvec for AFS libraries which seem to need one.])
 
544
+      else
 
545
+        AFS_LIBS="${AFS_LIBS} $cyrus_sigveclib"
 
546
+        AC_SUBST(AFS_LIBS)
 
547
+        AC_SUBST(AFS_LDFLAGS)
 
548
+        AC_DEFINE(HAVE_AFSKRB,[],[Should we build afskrb pts module?])
 
549
+      fi
 
550
+    else
 
551
+      AFS_LIBS="${AFS_LIBS}"
 
552
+      AC_SUBST(AFS_LIBS)
 
553
+      AC_SUBST(AFS_LDFLAGS)
 
554
+      AC_DEFINE(HAVE_AFSKRB,[],[Should we build afskrb pts module?])
 
555
+    fi
 
556
+    LIBS="$SAVE_LIBS"
 
557
+fi
 
558
+
 
559
+LDAP_CPPFLAGS=""
 
560
+LDAP_LDFLAGS=""
 
561
+LDAP_LIBS=""
 
562
+
 
563
+if test "x$with_ldap" != "xno"; then
 
564
+    if test ! -d $with_ldap; then
 
565
+        $with_ldap=/usr/local
 
566
+    fi
 
567
+
 
568
+    LDAP_CPPFLAGS="$CPPFLAGS -I${with_ldap}/include"
 
569
+    LDAP_LDFLAGS="$LDFLAGS -L${with_ldap}/lib"
 
570
+    LDAP_LIBS=""
 
571
+
 
572
+    save_CPPFLAGS=$CPPFLAGS
 
573
+    save_LDFLAGS=$LDFLAGS
 
574
+    CPPFLAGS=$LDAP_CPPFLAGS
 
575
+    LDFLAGS=$LDAP_LDFLAGS
 
576
+
 
577
+    AC_CHECK_LIB(ldap, ldap_initialize, 
 
578
+        [ AC_DEFINE(HAVE_LDAP,[],[Should we build ldap pts module?])
 
579
+          AC_SUBST(LDAP_CPPFLAGS)
 
580
+          AC_SUBST(LDAP_LDFLAGS)
 
581
+          AC_SUBST(LDAP_LIBS)  
 
582
+          LDAP_LIBS="-lldap -llber" ],,-llber)
 
583
+
 
584
+    CPPFLAGS=$save_CPPFLAGS
 
585
+    LDFLAGS=$save_LDFLAGS
 
586
+fi
 
587
+
 
588
+if test "x$with_afs" != "xno" -o "x$with_ldap" != "xno"; then
 
589
+       EXTRA_SUBDIRS="${EXTRA_SUBDIRS} ptclient"
 
590
+       EXTRA_OUTPUT="${EXTRA_OUTPUT} ptclient/Makefile"
 
591
+       AC_DEFINE(WITH_PTS,[],[Build in PTS support?])
 
592
+fi
 
593
+
 
594
+SERVER_SUBDIRS="master imap"
 
595
+AC_ARG_ENABLE(server,
 
596
+       [  --disable-server        disable compiling servers],
 
597
+       if test "$enableval" = no; then
 
598
+               SERVER_SUBDIRS=""
 
599
+       fi)
 
600
+AC_SUBST(SERVER_SUBDIRS)
 
601
+# We always output a server makefile (just because we can)
 
602
+
 
603
+dnl this is the new simple check for kerberos; since the person had to
 
604
+dnl compile SASL, we might as well use the same checks.
 
605
+AC_ARG_WITH(krb,[  --with-krb=PATH         use Kerberos from PATH],
 
606
+       with_krb="$withval", with_krb="no")
 
607
+
 
608
+AC_ARG_WITH(krbimpl,[  --with-krbimpl=\[kth|mit\]         assume Kerberos 4 from KTH or MIT],
 
609
+       with_krbimpl="$withval", with_krbimpl="kth")
 
610
+
 
611
+AC_ARG_ENABLE(statickrb,
 
612
+               [  --enable-statickrb      link Kerberos statically],
 
613
+       with_statickrb="yes", with_statickrb="no")
 
614
+
 
615
+dnl In order to compile kerberos4, we need libkrb and libdes.
 
616
+
 
617
+dnl we might need -lresolv for kerberos
 
618
+AC_CHECK_LIB(resolv,res_search)
 
619
+
 
620
+if test "$with_statickrb" = "yes" -a ! -d "$with_krb"; then
 
621
+      AC_MSG_ERROR([--enable-statickrb specified but --with-krb did not specify a valid directory])
 
622
+fi 
 
623
+
 
624
+if test "$with_krb" != "no"; then
 
625
+dnl Do we need DES for kerberos?
 
626
+AC_ARG_WITH(krbdes,[  --with-krbdes           use Kerberos DES implementation [[yes]]],
 
627
+      with_krbdes="$withval", with_krbdes="yes")
 
628
+if test "$with_krbdes" = "yes"; then
 
629
+  AC_CHECK_LIB(des,des_ecb_encrypt,
 
630
+      if test "$with_statickrb" = "yes"; then
 
631
+          KRB_LIBS="$with_krb/lib/libdes.a"
 
632
+      else
 
633
+          KRB_LIBS="-ldes"
 
634
+      fi,
 
635
+  AC_MSG_ERROR([The Kerberos DES library is required for Kerberos support.  You might want --with-auth=unix.]))
 
636
+fi
 
637
+fi
 
638
+
 
639
+dnl if we were ambitious, we'd look more aggressively for the
 
640
+dnl krb4 install
 
641
+if test -d ${with_krb}; then
 
642
+   AC_CACHE_CHECK(for Kerberos includes, cyrus_krbinclude, [
 
643
+     for krbhloc in include/kerberosIV include
 
644
+     do
 
645
+       if test -f ${with_krb}/${krbhloc}/krb.h ; then
 
646
+         cyrus_krbinclude=${with_krb}/${krbhloc}
 
647
+         break
 
648
+       fi
 
649
+     done
 
650
+     ])
 
651
+
 
652
+   if test -n "${cyrus_krbinclude}"; then
 
653
+     CPPFLAGS="$CPPFLAGS -I${cyrus_krbinclude}"
 
654
+   fi
 
655
+   CMU_ADD_LIBPATH(${with_krb}/lib)
 
656
+fi
 
657
+
 
658
+if test "$with_krbimpl" != "kth"; then
 
659
+  KRBLIB="krb4"
 
660
+else
 
661
+  KRBLIB="krb"
 
662
+fi
 
663
+
 
664
+if test "$with_des" != no; then
 
665
+  AC_CHECK_HEADER(krb.h,
 
666
+    AC_CHECK_LIB(${KRBLIB}, krb_mk_priv,
 
667
+      if test "$with_statickrb" = "yes"; then
 
668
+          KRB_LIBS="$KRB_LIBS $with_krb/lib/lib${KRBLIB}.a"
 
669
+      else
 
670
+          KRB_LIBS="$KRB_LIBS -l${KRBLIB}"
 
671
+      fi,
 
672
+                 AC_WARN(No Kerberos V4 found); krb4=no,
 
673
+          $KRB_LIBS),
 
674
+    AC_WARN(No Kerberos V4 found); krb4=no)
 
675
+else
 
676
+  AC_WARN(No DES library found for Kerberos V4 support)
 
677
+  krb4=no
 
678
+fi
 
679
+
 
680
+if test "${krb4}" != no; then
 
681
+  AC_DEFINE(HAVE_KRB,[],[Support for Kerberos?])
 
682
+fi
 
683
+
 
684
+LIBS="$KRB_LIBS $LIBS"
 
685
+
 
686
+SASL_SET_GSSAPI_LIBS
 
687
+
 
688
+dnl
 
689
+dnl Test for OpenSSL
 
690
+dnl
 
691
+IMAP_PROGS=""
 
692
+AC_ARG_WITH(openssl,[  --with-openssl=PATH     use OpenSSL from PATH],
 
693
+       with_openssl="${withval}")
 
694
+
 
695
+OPENSSL_INC=
 
696
+OPENSSL_LIB=
 
697
+case "$with_openssl" in
 
698
+       no) with_openssl="no";;
 
699
+       ""|yes) 
 
700
+         dnl if openssl has been compiled with the rsaref2 libraries,
 
701
+         dnl we need to include the rsaref libraries in the crypto check
 
702
+                LIB_RSAREF=""
 
703
+               AC_CHECK_LIB(rsaref, RSAPublicEncrypt,
 
704
+                      LIB_RSAREF="-lRSAglue -lrsaref"; cmu_have_rsaref=yes,
 
705
+                      cmu_have_rsaref=no)
 
706
+
 
707
+               with_openssl="yes"
 
708
+               AC_CHECK_LIB(crypto,BIO_accept,
 
709
+                                    LIBS="-lcrypto $LIB_RSAREF ${LIBS}",
 
710
+                                   with_openssl="no", $LIB_RSAREF)
 
711
+               AC_CHECK_LIB(ssl, SSL_CTX_new, LIBS="-lssl ${LIBS}",
 
712
+                            with_openssl="no", -lcrypto $LIB_RSAREF)
 
713
+               
 
714
+               ;;
 
715
+       *)  OPENSSL_INC="-I${with_openssl}/include"
 
716
+           OPENSSL_LIBPATH="${with_openssl}/lib"
 
717
+           OPENSSL_LIB="-L${OPENSSL_LIBPATH}"
 
718
+           CPPFLAGS="${CPPFLAGS} ${OPENSSL_INC}"
 
719
+           CMU_ADD_LIBPATH(${OPENSSL_LIBPATH})
 
720
+           CMU_ADD_LIBPATH_TO(${OPENSSL_LIBPATH}, OPENSSL_LIB)
 
721
+           LIBS="${LIBS} -lssl -lcrypto";;
 
722
+esac
 
723
+
 
724
+AC_MSG_CHECKING(for openssl)
 
725
+AC_MSG_RESULT($with_openssl)
 
726
+
 
727
+if test "$with_openssl" != "no"; then
 
728
+       AC_DEFINE(HAVE_SSL,[],[Build with SSL support?])
 
729
+       IMAP_PROGS="$IMAP_PROGS tls_prune"
 
730
+        if test "${krb4}" != no; then
 
731
+           AC_DEFINE(OPENSSL_ENABLE_OLD_DES_SUPPORT,[],[Configure OpenSSL to provide legacy des apis])
 
732
+           AC_DEFINE(OPENSSL_DES_LIBDES_COMPATIBILITY,[],[Configure OpenSSL to provide krb4-compatible legacy des apis])
 
733
+        fi
 
734
+fi
 
735
+AC_SUBST(OPENSSL_INC)
 
736
+AC_SUBST(OPENSSL_LIB)
 
737
+
 
738
+dnl
 
739
+dnl Allow for setting EGD socket file on systems without /dev/*random.
 
740
+dnl
 
741
+AC_ARG_WITH(egd-socket,
 
742
+      [  --with-egd-socket=FILE  Entropy Gathering Daemon socket pathname
 
743
+                          for systems without /dev/urandom],
 
744
+              [ EGD_SOCKET="$withval" ]
 
745
+      )
 
746
+if test -n "$EGD_SOCKET" ; then
 
747
+      AC_DEFINE_UNQUOTED(EGD_SOCKET, "$EGD_SOCKET", [Alternative to /dev/urandom?])
 
748
+fi
 
749
+
 
750
+dnl
 
751
+dnl Test for Zephyr
 
752
+dnl
 
753
+AC_ARG_WITH(zephyr,[  --with-zephyr[=PATH]    enable Zephyr notification (installed on PATH)],
 
754
+       with_zephyr="${withval}")
 
755
+if test -z "$with_zephyr"; then
 
756
+     if test -f /usr/local/lib/libzephyr.a; then
 
757
+       with_zephyr="/usr/local"
 
758
+     elif test -f /usr/lib/libzephyr.a; then
 
759
+        with_zephyr="/usr"
 
760
+     fi
 
761
+fi
 
762
+ZEPHYR_LIBS=""
 
763
+ZEPHYR_CPPFLAGS=""
 
764
+case "$with_zephyr" in
 
765
+       no) true;;
 
766
+       ""|yes) AC_CHECK_LIB(zephyr,ZInitialize,ZEPHYR_LIBS="-lzephyr",
 
767
+               with_zephyr="no",);;
 
768
+       *)  if test -d ${with_zephyr}/include/zephyr; then
 
769
+               ZEPHYR_CPPFLAGS="-I${with_zephyr}/include/zephyr"
 
770
+           else
 
771
+               ZEPHYR_CPPFLAGS="-I${with_zephyr}/include"
 
772
+           fi
 
773
+           ZEPHYR_LIBS="-lzephyr";;
 
774
+esac
 
775
+AC_SUBST(ZEPHYR_LIBS)
 
776
+AC_SUBST(ZEPHYR_CPPFLAGS)
 
777
+if test "$with_zephyr" != "no"; then
 
778
+       AC_DEFINE(HAVE_ZEPHYR,[],[Build with Zephyr support?])
 
779
+fi
 
780
+
 
781
+dnl
 
782
+dnl Set pidfile location
 
783
+dnl
 
784
+AC_ARG_WITH(pidfile,[  --with-pidfile[=PATH]   pidfile in PATH (/var/run/cyrus-master.pid)],
 
785
+       [MASTERPIDFILE="$withval"],
 
786
+       [MASTERPIDFILE="/var/run/cyrus-master.pid"])
 
787
+MASTERPIDFILE="\"$MASTERPIDFILE\""
 
788
+AC_DEFINE_UNQUOTED(MASTER_PIDFILE, $MASTERPIDFILE,[Name of the pidfile for master])
 
789
+
 
790
+dnl
 
791
+dnl Select a method for IMAP IDLE
 
792
+dnl
 
793
+AC_ARG_WITH(idle,[  --with-idle=METHOD      use METHOD for IMAP IDLE
 
794
+                          METHOD is [poll], idled or no],
 
795
+       WITH_IDLE="${withval}",WITH_IDLE="poll")
 
796
+AC_SUBST(WITH_IDLE)
 
797
+if test "$WITH_IDLE" = "idled"; then
 
798
+  IMAP_PROGS="$IMAP_PROGS idled"
 
799
+fi
 
800
+
 
801
+dnl
 
802
+dnl see if we're compiling with NNTP support
 
803
+dnl
 
804
+ENABLE_NNTP=no
 
805
+AC_ARG_ENABLE(nntp,
 
806
+        [  --enable-nntp           enable NNTP support (experimental)],
 
807
+       ENABLE_NNTP=$enableval
 
808
+        if test "$ENABLE_NNTP" != no; then
 
809
+         IMAP_PROGS="$IMAP_PROGS nntpd fetchnews"
 
810
+        fi) 
 
811
+
 
812
+dnl
 
813
+dnl see if we're compiling the Murder support programs
 
814
+dnl
 
815
+AC_ARG_ENABLE(murder,
 
816
+        [  --enable-murder         enable IMAP Murder support],
 
817
+        if test "$enableval" != no; then
 
818
+         IMAP_PROGS="$IMAP_PROGS proxyd lmtpproxyd mupdate"
 
819
+        fi) 
 
820
+
 
821
+AC_SUBST(IMAP_PROGS)
 
822
+
 
823
+dnl
 
824
+dnl Try and find a system version of com_err.
 
825
+dnl If we see something that looks a little wacky, ignore it (there are many
 
826
+dnl deficient installs of com_err, unfortunately, which leave out compile_et)
 
827
+dnl
 
828
+AC_ARG_WITH(com_err,
 
829
+[  --with-com_err=PATH     use com_err from path -- includes in PATH/include,
 
830
+                          libs in PATH/lib, and compile_et in PATH/bin])
 
831
+if test -z "$with_com_err"; then
 
832
+       # no value supplied
 
833
+       AC_CHECK_LIB(com_err, com_err, [
 
834
+               # com_err is already in library path
 
835
+               # guess we're okay
 
836
+               # can use system com_err
 
837
+               with_com_err=""
 
838
+               AC_CHECK_HEADER(et/com_err.h,
 
839
+                 [AC_DEFINE(HAVE_ET_COM_ERR_H,[],[We need et/com_err.h])],
 
840
+                 [AC_CHECK_HEADER(com_err.h,[],[AC_ERROR([cannot locate com_err.h])])])
 
841
+               AC_PATH_PROG(COMPILE_ET, compile_et, [no compile et])
 
842
+       ], [
 
843
+       if test -f /usr/local/include/com_err.h -o -f /usr/local/include/et/com_err.h; then
 
844
+               with_com_err="/usr/local"
 
845
+               AC_PATH_PROG(COMPILE_ET, /usr/local/bin/compile_et, [no compile et])
 
846
+       elif test -f /usr/include/com_err.h -o -f /usr/include/et/com_err.h; then
 
847
+               with_com_err="/usr"
 
848
+               AC_PATH_PROG(COMPILE_ET, /usr/bin/compile_et, [no compile et])
 
849
+       else
 
850
+               # use ours
 
851
+               with_com_err=yes
 
852
+       fi
 
853
+       ])
 
854
+
 
855
+       if test "${with_com_err}" = "no"; then
 
856
+         AC_MSG_WARN([com_err is required; included version will be used.])
 
857
+         with_com_err="yes"
 
858
+       fi
 
859
+       if test "${COMPILE_ET}" = "no compile et" -o "${COMPILE_ET}" = ""; then
 
860
+         AC_MSG_WARN([Parts of com_err distribuion were found, but not compile_et.])
 
861
+         AC_MSG_WARN([Will build com_err from included sources.])
 
862
+         with_com_err="yes" # build it ourselves
 
863
+       fi
 
864
+fi
 
865
+
 
866
+case "$with_com_err" in
 
867
+  # built-in et
 
868
+  yes) # use the com_err we're gonna build
 
869
+         COM_ERR_LIBS="../et/libcom_err.a"
 
870
+         COMPILE_ET="../et/compile_et"
 
871
+         COM_ERR_LDFLAGS=""
 
872
+         COM_ERR_CPPFLAGS="-I\${top_srcdir}/et"
 
873
+         PRE_SUBDIRS="et ${PRE_SUBDIRS}"
 
874
+         EXTRA_OUTPUT="${EXTRA_OUTPUT} et/Makefile"
 
875
+         ;;
 
876
+  "")   # no problem, we already have it in the paths
 
877
+       # we do nothing to pick it up
 
878
+       COM_ERR_LIBS="-lcom_err" # hope it's not shared
 
879
+       # we already set COMPILE_ET, or we didn't get here
 
880
+       COM_ERR_LDFLAGS=""
 
881
+       COM_ERR_CPPFLAGS=""
 
882
+      ;;
 
883
+  *) # use whatever they told us, or whatever we found
 
884
+     COMPILE_ET="${with_com_err}/bin/compile_et"
 
885
+     COM_ERR_LIBS="${with_com_err}/lib/libcom_err.a"
 
886
+     COM_ERR_CPPFLAGS="-I${with_com_err}/include"
 
887
+     # Ever get the feeling people hide this stuff on purpose?
 
888
+     if test -d "${with_com_err}/include/et" ; then
 
889
+       COM_ERR_CPPFLAGS="-I${with_com_err}/include/et"
 
890
+     fi
 
891
+dnl     CMU_ADD_LIBPATH_TO(${with_com_err}/lib, COM_ERR_LDFLAGS)
 
892
+     COMPILE_ET="${with_com_err}/bin/compile_et"
 
893
+esac
 
894
+AC_SUBST(COMPILE_ET)
 
895
+AC_SUBST(COM_ERR_LIBS)
 
896
+AC_SUBST(COM_ERR_LDFLAGS)
 
897
+AC_SUBST(COM_ERR_CPPFLAGS)
 
898
+
 
899
+AC_MSG_CHECKING(for modern syslog)
 
900
+AC_CACHE_VAL(cyrus_cv_lib_syslog, AC_TRY_CPP([#include <syslog.h>
 
901
+#ifndef LOG_LOCAL6
 
902
+#include </nonexistent>
 
903
+#endif],cyrus_cv_lib_syslog=yes,cyrus_cv_lib_syslog=no))
 
904
+if test $cyrus_cv_lib_syslog = no; then
 
905
+       PRE_SUBDIRS="${PRE_SUBDIRS} syslog"
 
906
+       EXTRA_OUTPUT="${EXTRA_OUTPUT} syslog/Makefile"
 
907
+       DEPLIBS="${DEPLIBS} ../syslog/libsyslog.a"
 
908
+       CPPFLAGS="$CPPFLAGS -I\$(srcdir)/../syslog"
 
909
+fi
 
910
+AC_MSG_RESULT($cyrus_cv_lib_syslog)
 
911
+
 
912
+AC_MSG_CHECKING(which syslog facility to use)
 
913
+SYSLOG_FACILITY=LOG_LOCAL6
 
914
+AC_ARG_WITH(syslogfacility,[  --with-syslogfacility=FACILITY set the syslog facility to use (default LOCAL6)],
 
915
+               [ if test "$withval" != "yes" -a "$withval" != "no" ; then
 
916
+                       SYSLOG_FACILITY=LOG_$withval
 
917
+               fi; ])
 
918
+AC_DEFINE_UNQUOTED(SYSLOG_FACILITY, $SYSLOG_FACILITY, [Syslog facility to use.])
 
919
+AC_MSG_RESULT($SYSLOG_FACILITY)
 
920
+
 
921
+dnl Have to check getdtabalesize after adding ossup, as some ossups define it
 
922
+AC_REPLACE_FUNCS(getdtablesize)
 
923
+AC_ARG_ENABLE(cmulocal,
 
924
+       [  --enable-cmulocal       enable CMU-specific local support],
 
925
+       if test "$enableval" = yes; then
 
926
+               EXTRA_SUBDIRS="${EXTRA_SUBDIRS} netnews depot"
 
927
+               EXTRA_OUTPUT="${EXTRA_OUTPUT} depot/Makefile"
 
928
+       fi)
 
929
+
 
930
+AC_MSG_CHECKING(to use old sieve service name)
 
931
+AC_ARG_ENABLE(oldsievename,
 
932
+       [  --enable-oldsievename   enable the use of 'imap' as the sieve service name],
 
933
+       if test "$enableval" = yes; then
 
934
+               AC_MSG_RESULT(yes)
 
935
+               AC_DEFINE(OLD_SIEVE_SERVICE_NAME,[],[Use "imap" as sieve service name?])
 
936
+       else
 
937
+               AC_MSG_RESULT(no)
 
938
+       fi,
 
939
+       AC_MSG_RESULT(no))
 
940
+
 
941
+AC_ARG_ENABLE(listext,
 
942
+       [  --enable-listext        enable IMAP List extensions],
 
943
+       if test "$enableval" = yes; then
 
944
+               AC_DEFINE(ENABLE_LISTEXT,[],[Enable the LISTEXT extension?])
 
945
+       fi)
 
946
+
 
947
+AC_ARG_ENABLE(netscapehack,
 
948
+       [  --enable-netscapehack   enable Netscape hack for the menu option
 
949
+                          in Communicator to Administrate Mail],
 
950
+       if test "$enableval" = yes; then
 
951
+               AC_DEFINE(ENABLE_X_NETSCAPE_HACK,[],[Enable Netscape Menu Option Hack?])
 
952
+       fi)
 
953
+
 
954
+AC_CHECK_FUNC(dlopen,,[AC_CHECK_LIB(dl, dlopen)])
 
955
+CMU_SASL2_REQUIRE_VER(2,1,7)
 
956
+CMU_SASL2_CHECKAPOP_REQUIRED
 
957
+
 
958
+AC_ARG_WITH(perl,       [  --with-perl=PERL        use PERL for perl],
 
959
+       with_perl="$withval", with_perl="perl")
 
960
+
 
961
+if test "${with_perl}" = yes; then
 
962
+    with_perl="perl"
 
963
+fi
 
964
+if test "${with_perl}" != no; then
 
965
+    if test ${using_static_sasl} = "staticonly"; then
 
966
+       AC_MSG_WARN([Cannot compile perl utilities using static libsasl])
 
967
+       with_perl="no"
 
968
+    else 
 
969
+       AC_CHECK_PROGS(PERL, ${with_perl} perl, with_perl=notfound)
 
970
+    fi
 
971
+fi
 
972
+if test "$with_perl" = "notfound"; then
 
973
+    AC_MSG_WARN(Perl not found: Administrative tools won't be available)
 
974
+elif test "${with_perl}" != "no"; then
 
975
+dnl compile perl stuff
 
976
+    EXTRA_SUBDIRS="${EXTRA_SUBDIRS} perl"
 
977
+dnl and compile perl/cyradm
 
978
+    PERL_SUBDIRS="imap"
 
979
+    PERL="${with_perl}"
 
980
+dnl add perl cccdlflags when building libraries -- this ensures that the
 
981
+dnl libraries will be compiled as PIC if perl requires PIC objects
 
982
+dnl -- this is needed on NetBSD, but seems to cause problems on atleast Solaris --
 
983
+dnl    eval `${PERL} -V:cccdlflags`
 
984
+    PERL_CCCDLFLAGS="$cccdlflags"
 
985
+    AC_SUBST(PERL_CCCDLFLAGS)
 
986
+fi
 
987
+
 
988
+dnl for timsieved
 
989
+if test "$sievedir" != "no"; then
 
990
+       EXTRA_SUBDIRS="${EXTRA_SUBDIRS} timsieved notifyd"
 
991
+       EXTRA_OUTPUT="${EXTRA_OUTPUT} timsieved/Makefile notifyd/Makefile"
 
992
+
 
993
+       PERL_SUBDIRS="${PERL_SUBDIRS} sieve"
 
994
+       PERL_DEPSUBDIRS="sieve"
 
995
+       EXTRA_OUTPUT="${EXTRA_OUTPUT} perl/sieve/Makefile perl/sieve/lib/Makefile"
 
996
+else
 
997
+       PERL_DEPSUBDIRS="none"
 
998
+fi
 
999
+
 
1000
+dnl Check for MD5 functions
 
1001
+AC_FUNC_CHECK(MD5Init,,
 
1002
+       AC_CHECK_LIB(md, MD5Init, LIBS="${LIBS} -lmd",
 
1003
+                    MD5OBJ="md5.o"))
 
1004
+AC_SUBST(MD5OBJ)
 
1005
+
 
1006
+dnl snmp
 
1007
+dnl (agentx was depricated, but SNMP_SUBDIRS is conveinent as a placeholder)
 
1008
+SNMP_SUBDIRS=""
 
1009
+AC_SUBST(SNMP_SUBDIRS)
 
1010
+
 
1011
+CMU_LIBWRAP
 
1012
+CMU_UCDSNMP
 
1013
+
 
1014
+# Figure out what directories we're linking against.
 
1015
+# Lots of fun for the whole family.
 
1016
+# This probably chokes on anything with spaces in it.
 
1017
+# All we want is the list of -L directories, and -L may or may not be
 
1018
+# followed by a space.
 
1019
+isdir=no
 
1020
+libpath=""
 
1021
+#echo "debug ldflags: << ${ldflags} >>"
 
1022
+#echo "debug default_ldflags: << ${default_ldflags} >>"
 
1023
+for flag in ${ldflags} ${default_ldflags}; do
 
1024
+  case $flag in
 
1025
+    -L)
 
1026
+      # it's a split -L option, we'll mark the next option as a dir.
 
1027
+      isdir=yes
 
1028
+      ;;
 
1029
+
 
1030
+    -L*) 
 
1031
+      # attached -L option: split off the directory
 
1032
+      larg=`echo $flag | sed -e 's:-L\(..*\):\1:'`
 
1033
+      libpath="${libpath} ${larg}"
 
1034
+      ;;
 
1035
+
 
1036
+    *)
 
1037
+      if test $isdir = yes ; then
 
1038
+       libpath="${libpath} ${flag}"
 
1039
+       isdir=no
 
1040
+      fi
 
1041
+  esac
 
1042
+done
 
1043
+
 
1044
+IMAP_COM_ERR_LIBS="${COM_ERR_LIBS}"
 
1045
+IMAP_LIBS="${LIB_SASL} ${LIBS}"
 
1046
+
 
1047
+AC_SUBST(LIB_RT)
 
1048
+AC_SUBST(IMAP_COM_ERR_LIBS)
 
1049
+AC_SUBST(IMAP_LIBS)
 
1050
+
 
1051
+dnl AC_OUTPUT_COMMANDS([
 
1052
+dnl   if test "$with_perl" != "no"; then
 
1053
+dnl     (cd perl/sieve/managesieve; $perl Makefile.PL PREFIX=$prefix)
 
1054
+dnl     (cd perl/imap; $perl Makefile.PL PREFIX=$prefix)
 
1055
+dnl   fi
 
1056
+dnl ], perl=$PERL; with_perl=$with_perl; prefix=$prefix; SASL_LIB="$LIB_SASL"; SASL_INC="$SASLFLAGS"; export SASL_LIB SASL_INC)
 
1057
+AC_SUBST(PERL_SUBDIRS)
 
1058
+AC_SUBST(PERL_DEPSUBDIRS)
 
1059
+AC_SUBST(PERL)
 
1060
+
 
1061
+AH_TOP([
 
1062
+/* $Id: configure.in,v 1.296 2005/10/13 19:56:14 jeaton Exp $ */
 
1063
+/* 
 
1064
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
 
1065
+ *
 
1066
+ * Redistribution and use in source and binary forms, with or without
 
1067
+ * modification, are permitted provided that the following conditions
 
1068
+ * are met:
 
1069
+ *
 
1070
+ * 1. Redistributions of source code must retain the above copyright
 
1071
+ *    notice, this list of conditions and the following disclaimer. 
 
1072
+ *
 
1073
+ * 2. Redistributions in binary form must reproduce the above copyright
 
1074
+ *    notice, this list of conditions and the following disclaimer in
 
1075
+ *    the documentation and/or other materials provided with the
 
1076
+ *    distribution.
 
1077
+ *
 
1078
+ * 3. The name "Carnegie Mellon University" must not be used to
 
1079
+ *    endorse or promote products derived from this software without
 
1080
+ *    prior written permission. For permission or any other legal
 
1081
+ *    details, please contact  
 
1082
+ *      Office of Technology Transfer
 
1083
+ *      Carnegie Mellon University
 
1084
+ *      5000 Forbes Avenue
 
1085
+ *      Pittsburgh, PA  15213-3890
 
1086
+ *      (412) 268-4387, fax: (412) 268-7395
 
1087
+ *      tech-transfer@andrew.cmu.edu
 
1088
+ *
 
1089
+ * 4. Redistributions of any form whatsoever must retain the following
 
1090
+ *    acknowledgment:
 
1091
+ *    "This product includes software developed by Computing Services
 
1092
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
 
1093
+ *
 
1094
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
1095
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 
1096
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
 
1097
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
1098
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 
1099
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 
1100
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
1101
+ */
 
1102
+
 
1103
+#ifndef _CYRUS_IMAPD_CONFIG_H_
 
1104
+#define _CYRUS_IMAPD_CONFIG_H_
 
1105
+])
 
1106
+
 
1107
+AH_BOTTOM([
 
1108
+/* time.h */
 
1109
+#if TIME_WITH_SYS_TIME
 
1110
+# include <sys/time.h>
 
1111
+# include <time.h>
 
1112
+#else
 
1113
+# if HAVE_SYS_TIME_H
 
1114
+#  include <sys/time.h>
 
1115
+# else
 
1116
+#  include <time.h>
 
1117
+# endif
 
1118
+#endif
 
1119
+
 
1120
+/* com_err.h, as needed */
 
1121
+#ifndef IN_COM_ERR
 
1122
+#ifdef HAVE_ET_COM_ERR_H
 
1123
+#include <et/com_err.h>
 
1124
+#else
 
1125
+#include <com_err.h>
 
1126
+#endif /* HAVE_ET_COM_ERR_H */
 
1127
+#endif /* IN_COM_ERR */
 
1128
+
 
1129
+/* This allows us to work even when we don't have an fdatasync */
 
1130
+#ifndef HAVE_FDATASYNC
 
1131
+#define fdatasync(fd) fsync(fd)
 
1132
+#endif
 
1133
+
 
1134
+/* A similar setup for not having O_DSYNC */
 
1135
+#include <fcntl.h>
 
1136
+
 
1137
+#ifndef O_DSYNC
 
1138
+#  ifdef O_SYNC
 
1139
+#    define O_DSYNC     O_SYNC          /* POSIX */
 
1140
+#  else
 
1141
+#    define O_DSYNC     O_FSYNC         /* BSD */
 
1142
+#  endif
 
1143
+#endif
 
1144
+
 
1145
+#ifndef HAVE___ATTRIBUTE__
 
1146
+/* Can't use attributes... */
 
1147
+#define __attribute__(foo)
 
1148
+#endif
 
1149
+
 
1150
+#ifndef HAVE_SOCKLEN_T
 
1151
+typedef unsigned int socklen_t;
 
1152
+#endif
 
1153
+
 
1154
+#ifndef HAVE_RLIM_T
 
1155
+typedef int rlim_t;
 
1156
+#endif
 
1157
+
 
1158
+/* some potentially memory saving tradeoffs, 
 
1159
+   preconfigured in memory-saving mode */
 
1160
+
 
1161
+/* save the cmdlines for the ID command */
 
1162
+#undef ID_SAVE_CMDLINE
 
1163
+
 
1164
+/* IPv6 things */
 
1165
+#include <netdb.h>
 
1166
+#include <sys/types.h>
 
1167
+#include <sys/socket.h>
 
1168
+#include <netinet/in.h>
 
1169
+
 
1170
+#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
 
1171
+#define        _SS_MAXSIZE     128     /* Implementation specific max size */
 
1172
+#define        _SS_PADSIZE     (_SS_MAXSIZE - sizeof (struct sockaddr))
 
1173
+
 
1174
+struct sockaddr_storage {
 
1175
+       struct  sockaddr ss_sa;
 
1176
+       char            __ss_pad2[_SS_PADSIZE];
 
1177
+};
 
1178
+# define ss_family ss_sa.sa_family
 
1179
+# define HAVE_SS_FAMILY
 
1180
+#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */
 
1181
+
 
1182
+#ifndef HAVE_SS_FAMILY
 
1183
+#define ss_family      __ss_family
 
1184
+#endif
 
1185
+
 
1186
+#ifndef AF_INET6
 
1187
+/* Define it to something that should never appear */
 
1188
+#define        AF_INET6        AF_MAX
 
1189
+#endif
 
1190
+
 
1191
+#if !defined(HAVE_GETADDRINFO) || !defined(HAVE_GETNAMEINFO)
 
1192
+#include "gai.h"
 
1193
+#endif
 
1194
+
 
1195
+/* End IPv6 things */
 
1196
+
 
1197
+#ifdef OLD_SIEVE_SERVICE_NAME
 
1198
+#define SIEVE_SERVICE_NAME "imap"
 
1199
+#else
 
1200
+#define SIEVE_SERVICE_NAME "sieve"
 
1201
+#endif
 
1202
+
 
1203
+/* filenames */
 
1204
+#define FNAME_DBDIR "/db"
 
1205
+#define FNAME_USERDIR "/user/"
 
1206
+#define FNAME_DOMAINDIR "/domain/"
 
1207
+#define FNAME_LOGDIR "/log/"
 
1208
+#define FNAME_PTSDB "/ptclient/ptscache.db"
 
1209
+#define CONFIG_FILENAME (SYSCONFDIR "/imapd.conf")
 
1210
+#define DEFAULT_MASTER_CONFIG_FILENAME (SYSCONFDIR "/cyrus.conf")
 
1211
+
 
1212
+#ifndef HAVE_SHUTDOWN
 
1213
+#define shutdown(fd, mode) 0
 
1214
+#endif
 
1215
+
 
1216
+/* compile time options; think carefully before modifying */
 
1217
+enum {
 
1218
+    /* should we send an UNAVAILABLE message to master when
 
1219
+     * a service is exiting (master is already going to be 
 
1220
+     * informed of the exit by the SIGCHLD signal anyway) ? */
 
1221
+    MESSAGE_MASTER_ON_EXIT = 0,
 
1222
+
 
1223
+    /* should a hierarchical rename stop on error? */
 
1224
+    RENAME_STOP_ON_ERROR = 1,
 
1225
+
 
1226
+    /* should we call fsync() to maybe help with softupdates? (it should) */
 
1227
+    APPEND_ULTRA_PARANOID = 1,
 
1228
+
 
1229
+    /* should we log extra information at the DEBUG level for DB stuff? 
 
1230
+     * 0 -> nothing; 1 -> some; higher -> even more */
 
1231
+    CONFIG_DB_VERBOSE = 1,
 
1232
+
 
1233
+    /* log timing information to LOG_DEBUG */
 
1234
+    CONFIG_TIMING_VERBOSE = 0,
 
1235
+
 
1236
+    /* should we be pedantic about namespace or sleezy? */
 
1237
+    SLEEZY_NAMESPACE = 1,
 
1238
+
 
1239
+    /* should we do a fast TLS session shutdown? */
 
1240
+    TLS_FAST_SHUTDOWN = 1,
 
1241
+
 
1242
+    /* should we use the SQUAT engine to accelerate SEARCH? */
 
1243
+    SQUAT_ENGINE = 1,
 
1244
+
 
1245
+    /* should we have long LMTP error messages? */
 
1246
+    LMTP_LONG_ERROR_MSGS = 1,
 
1247
+
 
1248
+    /* default time to wait, in seconds, before giving up
 
1249
+     * trying to lock something */
 
1250
+    LOCK_GIVEUP_TIMER_DEFAULT = 100
 
1251
+};
 
1252
+
 
1253
+#endif /* _CYRUS_IMAPD_CONFIG_H_ */
 
1254
+])
 
1255
+
 
1256
+dnl make sure that Makefile is the last thing output
 
1257
+AC_OUTPUT(man/Makefile master/Makefile lib/Makefile imap/Makefile imtest/Makefile netnews/Makefile perl/Makefile $EXTRA_OUTPUT Makefile)
 
1258
diff -urNad cyrus-imapd-2.2.13/imap/Makefile.in /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/imap/Makefile.in
 
1259
--- cyrus-imapd-2.2.13/imap/Makefile.in 2006-04-18 20:39:34.000000000 +0200
 
1260
+++ /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/imap/Makefile.in        2006-04-18 20:39:35.685096625 +0200
34
1261
@@ -69,6 +69,7 @@
35
1262
 SIEVE_LIBS = @SIEVE_LIBS@
36
1263
 IMAP_COM_ERR_LIBS = @IMAP_COM_ERR_LIBS@
56
1283
        $(QUANTIFY) $(QUANTOPT) $(CC) $(LDFLAGS) -o imapd.quant \
57
1284
         $(SERVICE) $(IMAPDOBJS) mutex_fake.o libimap.a \
58
1285
-       $(DEPLIBS) $(LIBS) $(LIB_WRAP)
59
 
+       $(DEPLIBS) $(LIBS) $(LIB_WRAP) $(DRAC_LIBS)
 
1286
+       $(DEPLIBS) $(LIBS) $(LIB_WRAP) $(DRAC_LIBS) $(DRAC_LIBS)
60
1287
 
61
1288
 proxyd: $(PROXYDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
62
1289
        $(CC) $(LDFLAGS) -o proxyd \
69
1296
 
70
1297
 nntpd: nntpd.o backend.o index.o smtpclient.o spool.o tls.o \
71
1298
         mutex_fake.o nntp_err.o libimap.a $(DEPLIBS) $(SERVICE)
72
 
diff -urNad cyrus-imapd-2.2.12/imap/imapd.c /tmp/dpep.FoExSn/cyrus-imapd-2.2.12/imap/imapd.c
73
 
--- cyrus-imapd-2.2.12/imap/imapd.c     2006-02-14 17:13:36.000000000 +0100
74
 
+++ /tmp/dpep.FoExSn/cyrus-imapd-2.2.12/imap/imapd.c    2006-02-14 17:13:44.660438143 +0100
75
 
@@ -137,6 +137,18 @@
 
1299
diff -urNad cyrus-imapd-2.2.13/imap/Makefile.in.orig /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/imap/Makefile.in.orig
 
1300
--- cyrus-imapd-2.2.13/imap/Makefile.in.orig    1970-01-01 01:00:00.000000000 +0100
 
1301
+++ /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/imap/Makefile.in.orig   2006-04-18 20:39:35.686096528 +0200
 
1302
@@ -0,0 +1,354 @@
 
1303
+# Makefile for cyrus imap server and associated programs
 
1304
+# $Id: Makefile.in,v 1.184 2004/05/28 18:03:02 rjs3 Exp $
 
1305
+# 
 
1306
+# @configure_input@
 
1307
+# 
 
1308
+# Copyright (c) 1998-2000 Carnegie Mellon University.  All rights reserved.
 
1309
+#
 
1310
+# Redistribution and use in source and binary forms, with or without
 
1311
+# modification, are permitted provided that the following conditions
 
1312
+# are met:
 
1313
+#
 
1314
+# 1. Redistributions of source code must retain the above copyright
 
1315
+#    notice, this list of conditions and the following disclaimer. 
 
1316
+#
 
1317
+# 2. Redistributions in binary form must reproduce the above copyright
 
1318
+#    notice, this list of conditions and the following disclaimer in
 
1319
+#    the documentation and/or other materials provided with the
 
1320
+#    distribution.
 
1321
+#
 
1322
+# 3. The name "Carnegie Mellon University" must not be used to
 
1323
+#    endorse or promote products derived from this software without
 
1324
+#    prior written permission. For permission or any other legal
 
1325
+#    details, please contact  
 
1326
+#      Office of Technology Transfer
 
1327
+#      Carnegie Mellon University
 
1328
+#      5000 Forbes Avenue
 
1329
+#      Pittsburgh, PA  15213-3890
 
1330
+#      (412) 268-4387, fax: (412) 268-7395
 
1331
+#      tech-transfer@andrew.cmu.edu
 
1332
+#
 
1333
+# 4. Redistributions of any form whatsoever must retain the following
 
1334
+#    acknowledgment:
 
1335
+#    "This product includes software developed by Computing Services
 
1336
+#     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
 
1337
+#
 
1338
+# CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
1339
+# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 
1340
+# AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
 
1341
+# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
1342
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 
1343
+# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 
1344
+# OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
1345
+# 
 
1346
+DEFINES=-DSETPROCTITLE
 
1347
+
 
1348
+# \Seen state database.  Either 'db' (berkeley db) or 
 
1349
+# 'local' (legacy flat file).
 
1350
+SEEN=seen_db.o
 
1351
+
 
1352
+# IMAP IDLE mechanism
 
1353
+IDLE=idle_@WITH_IDLE@.o
 
1354
+
 
1355
+srcdir = @srcdir@
 
1356
+top_srcdir = @top_srcdir@
 
1357
+VPATH = @srcdir@
 
1358
+
 
1359
+CC = @CC@
 
1360
+INSTALL = @INSTALL@
 
1361
+RANLIB = @RANLIB@
 
1362
+AWK = @AWK@
 
1363
+
 
1364
+CYRUS_USER=@cyrus_user@
 
1365
+CYRUS_GROUP=@cyrus_group@
 
1366
+
 
1367
+DEFS = @DEFS@ @LOCALDEFS@
 
1368
+CPPFLAGS = -I.. -I$(srcdir)/../lib @COM_ERR_CPPFLAGS@ @SIEVE_CPPFLAGS@ @CPPFLAGS@ @SASLFLAGS@
 
1369
+IMAP_LIBS = @IMAP_LIBS@ @LIB_RT@
 
1370
+SIEVE_OBJS = @SIEVE_OBJS@
 
1371
+SIEVE_LIBS = @SIEVE_LIBS@
 
1372
+IMAP_COM_ERR_LIBS = @IMAP_COM_ERR_LIBS@
 
1373
+LIB_WRAP = @LIB_WRAP@
 
1374
+LIBS = $(IMAP_LIBS) $(IMAP_COM_ERR_LIBS)
 
1375
+DEPLIBS = ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
 
1376
+
 
1377
+CFLAGS = @CFLAGS@ @WARNERROR@
 
1378
+LDFLAGS = @LDFLAGS@ @COM_ERR_LDFLAGS@ 
 
1379
+
 
1380
+SHELL = /bin/sh
 
1381
+MAKEDEPEND = @MAKEDEPEND@
 
1382
+
 
1383
+COMPILE_ET=@COMPILE_ET@
 
1384
+
 
1385
+#
 
1386
+# Some notes on purify --
 
1387
+#     you probably want to run the make as the cyrus user as 
 
1388
+#     purify sets the cache directory based on the user. So,
 
1389
+#     if you don't, purify can't find the instrumented libraries
 
1390
+#     and so you don't get any useful information.
 
1391
+#     It may also help to run purify by hand to instrument any of
 
1392
+#     the dynamic libraries that may crop up during run time.
 
1393
+# 
 
1394
+PURIFY=/usr/local/bin/purify
 
1395
+PUREOPT= -best-effort -logfile=/tmp/pure/%v.%p.log -always_use_cache_dir -cachedir=/usr/tmp/$(USER)
 
1396
+QUANTIFY=/usr/local/bin/quantify
 
1397
+QUANTOPT=-windows=no -filename-prefix=/tmp/quant/%v.%p -write-summary-file= -logfile=/tmp/quant/%v.%p.log
 
1398
+
 
1399
+prefix = @prefix@
 
1400
+exec_prefix = @exec_prefix@
 
1401
+cyrus_prefix = @cyrus_prefix@
 
1402
+service_path = @service_path@
 
1403
+
 
1404
+LOBJS= append.o mailbox.o mboxlist.o mupdate-client.o mboxname.o message.o \
 
1405
+       global.o imap_err.o mupdate_err.o proc.o setproctitle.o \
 
1406
+       convert_code.o duplicate.o saslclient.o saslserver.o signals.o \
 
1407
+       annotate.o search_engines.o squat.o squat_internal.o mbdump.o \
 
1408
+       imapparse.o telemetry.o user.o notify.o protocol.o quota_db.o \
 
1409
+       $(SEEN) $(IDLE)
 
1410
+
 
1411
+IMAPDOBJS=pushstats.o backend.o imapd.o index.o tls.o version.o
 
1412
+
 
1413
+PROXYDOBJS=backend.o pushstats.o proxyd.o tls.o version.o 
 
1414
+
 
1415
+LMTPOBJS=lmtpstats.o lmtpengine.o spool.o tls.o
 
1416
+
 
1417
+# Your typical objects for the command line utilities
 
1418
+CLIOBJS=cli_fatal.o mutex_fake.o
 
1419
+
 
1420
+SERVICE=../master/service.o
 
1421
+SERVICETHREAD=../master/service-thread.o
 
1422
+
 
1423
+PROGS = imapd lmtpd pop3d \
 
1424
+       fud smmapd reconstruct quota mbpath ipurge \
 
1425
+       cyrdump chk_cyrus cvt_cyrusdb deliver ctl_mboxlist \
 
1426
+       ctl_deliver ctl_cyrusdb squatter mbexamine cyr_expire arbitron \
 
1427
+       @IMAP_PROGS@
 
1428
+
 
1429
+BUILTSOURCES = imap_err.c imap_err.h pushstats.c pushstats.h \
 
1430
+       lmtpstats.c lmtpstats.h xversion.h mupdate_err.c mupdate_err.h \
 
1431
+       nntp_err.c nntp_err.h
 
1432
+
 
1433
+all: $(BUILTSOURCES) $(PROGS) $(SUIDPROGS)
 
1434
+
 
1435
+pure: imapd.pure lmtpd.pure proxyd.pure mupdate.pure lmtpproxyd.pure
 
1436
+
 
1437
+
 
1438
+install:
 
1439
+       $(srcdir)/../install-sh -d ${DESTDIR}$(service_path)
 
1440
+       for file in $(PROGS); \
 
1441
+       do \
 
1442
+               $(INSTALL) -m 755 $$file $(DESTDIR)$(service_path) || exit 1; \
 
1443
+       done
 
1444
+       ln -f $(DESTDIR)$(service_path)/pop3d $(DESTDIR)$(service_path)/pop3proxyd
 
1445
+
 
1446
+.c.o:
 
1447
+       $(CC) -c $(CPPFLAGS) $(DEFS) $(CFLAGS) \
 
1448
+       $<
 
1449
+
 
1450
+### libimap
 
1451
+
 
1452
+libimap.a: $(LOBJS)
 
1453
+       rm -f libimap.a
 
1454
+       ar cr libimap.a $(LOBJS)
 
1455
+       $(RANLIB) libimap.a
 
1456
+
 
1457
+### Built Source Files
 
1458
+
 
1459
+xversion:
 
1460
+       rm -f version.o
 
1461
+       AWK=$(AWK) $(srcdir)/xversion.sh
 
1462
+
 
1463
+xversion.h: xversion
 
1464
+
 
1465
+pushstats.c: pushstats.snmp $(srcdir)/../snmp/snmpgen
 
1466
+       $(srcdir)/../snmp/snmpgen $(srcdir)/pushstats.snmp
 
1467
+
 
1468
+pushstats.h: pushstats.c
 
1469
+
 
1470
+lmtpstats.c: lmtpstats.snmp $(srcdir)/../snmp/snmpgen
 
1471
+       $(srcdir)/../snmp/snmpgen $(srcdir)/lmtpstats.snmp
 
1472
+
 
1473
+lmtpstats.h: lmtpstats.c
 
1474
+
 
1475
+imap_err.c: imap_err.et
 
1476
+       $(COMPILE_ET) $(srcdir)/imap_err.et
 
1477
+
 
1478
+imap_err.h: imap_err.c
 
1479
+
 
1480
+nntp_err.c: nntp_err.et
 
1481
+       $(COMPILE_ET) $(srcdir)/nntp_err.et
 
1482
+
 
1483
+nntp_err.h: nntp_err.c
 
1484
+
 
1485
+mupdate_err.c: mupdate_err.et
 
1486
+       $(COMPILE_ET) $(srcdir)/mupdate_err.et
 
1487
+
 
1488
+mupdate_err.h: mupdate_err.c
 
1489
+
 
1490
+### Services
 
1491
+idled: idled.o mutex_fake.o libimap.a $(DEPLIBS)
 
1492
+       $(CC) $(LDFLAGS) -o idled \
 
1493
+        idled.o mutex_fake.o libimap.a $(DEPLIBS) $(LIBS)
 
1494
+
 
1495
+lmtpd: lmtpd.o $(LMTPOBJS) $(SIEVE_OBJS) mutex_fake.o libimap.a $(SIEVE_LIBS) \
 
1496
+       $(DEPLIBS) $(SERVICE)
 
1497
+       $(CC) $(LDFLAGS) -o lmtpd \
 
1498
+        $(SERVICE) lmtpd.o $(LMTPOBJS) $(SIEVE_OBJS) mutex_fake.o \
 
1499
+        libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
 
1500
+
 
1501
+lmtpd.pure: lmtpd.o $(LMTPOBJS) $(SIEVE_OBJS) mutex_fake.o \
 
1502
+       libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
 
1503
+       $(PURIFY) $(PUREOPT) $(CC) $(LDFLAGS) -o lmtpd.pure \
 
1504
+        $(SERVICE) lmtpd.o $(LMTPOBJS) $(SIEVE_OBJS) mutex_fake.o \
 
1505
+        libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
 
1506
+
 
1507
+lmtpproxyd: lmtpproxyd.o backend.o $(LMTPOBJS) mutex_fake.o \
 
1508
+       libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
 
1509
+       $(CC) $(LDFLAGS) -o lmtpproxyd \
 
1510
+        $(SERVICE) lmtpproxyd.o backend.o $(LMTPOBJS) mutex_fake.o \
 
1511
+        libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
 
1512
+
 
1513
+lmtpproxyd.pure: lmtpproxyd.o backend.o $(LMTPOBJS) mutex_fake.o \
 
1514
+       libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
 
1515
+       $(PURIFY) $(PUREOPT) $(CC) $(LDFLAGS) -o lmtpproxyd.pure \
 
1516
+        $(SERVICE) lmtpproxyd.o backend.o $(LMTPOBJS) mutex_fake.o \
 
1517
+        libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
 
1518
+
 
1519
+imapd: xversion $(IMAPDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
 
1520
+       $(CC) $(LDFLAGS) -o imapd \
 
1521
+        $(SERVICE) $(IMAPDOBJS) mutex_fake.o \
 
1522
+       libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP)
 
1523
+
 
1524
+imapd.pure: $(IMAPDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
 
1525
+       $(PURIFY) $(PUREOPT) $(CC) $(LDFLAGS) -o imapd.pure \
 
1526
+        $(SERVICE) $(IMAPDOBJS) mutex_fake.o libimap.a \
 
1527
+       $(DEPLIBS) $(LIBS) $(LIB_WRAP)
 
1528
+
 
1529
+imapd.quant: $(IMAPDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
 
1530
+       $(QUANTIFY) $(QUANTOPT) $(CC) $(LDFLAGS) -o imapd.quant \
 
1531
+        $(SERVICE) $(IMAPDOBJS) mutex_fake.o libimap.a \
 
1532
+       $(DEPLIBS) $(LIBS) $(LIB_WRAP)
 
1533
+
 
1534
+proxyd: $(PROXYDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
 
1535
+       $(CC) $(LDFLAGS) -o proxyd \
 
1536
+        $(SERVICE) $(PROXYDOBJS) mutex_fake.o libimap.a \
 
1537
+        $(DEPLIBS) $(LIBS) $(LIB_WRAP)
 
1538
+
 
1539
+proxyd.pure: $(PROXYDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
 
1540
+       $(PURIFY) $(PUREOPT) $(CC) $(LDFLAGS) -o proxyd.pure \
 
1541
+        $(SERVICE) $(PROXYDOBJS) mutex_fake.o libimap.a \
 
1542
+        $(DEPLIBS) $(LIBS) $(LIB_WRAP)
 
1543
+
 
1544
+mupdate: mupdate.o mupdate-slave.o mupdate-client.o mutex_pthread.o tls.o \
 
1545
+       libimap.a $(DEPLIBS)
 
1546
+       $(CC) $(LDFLAGS) -o mupdate \
 
1547
+        $(SERVICETHREAD) mupdate.o mupdate-slave.o mupdate-client.o \
 
1548
+        mutex_pthread.o tls.o libimap.a \
 
1549
+        $(DEPLIBS) $(LIBS) $(LIB_WRAP) -lpthread
 
1550
+
 
1551
+mupdate.pure: mupdate.o mupdate-slave.o mupdate-client.o mutex_pthread.o \
 
1552
+       libimap.a $(DEPLIBS)
 
1553
+       $(PURIFY) $(PUREOPT) $(CC) $(LDFLAGS) -o mupdate.pure \
 
1554
+        $(SERVICETHREAD) mupdate.o mupdate-slave.o mupdate-client.o \
 
1555
+        mutex_pthread.o libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP) -lpthread
 
1556
+
 
1557
+pop3d: pop3d.o backend.o tls.o mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
 
1558
+       $(CC) $(LDFLAGS) -o pop3d pop3d.o backend.o tls.o $(SERVICE) \
 
1559
+        mutex_fake.o libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP)
 
1560
+
 
1561
+nntpd: nntpd.o backend.o index.o smtpclient.o spool.o tls.o \
 
1562
+        mutex_fake.o nntp_err.o libimap.a $(DEPLIBS) $(SERVICE)
 
1563
+       $(CC) $(LDFLAGS) -o nntpd nntpd.o backend.o index.o spool.o \
 
1564
+        smtpclient.o tls.o $(SERVICE) mutex_fake.o nntp_err.o \
 
1565
+        libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP)
 
1566
+
 
1567
+fud: fud.o libimap.a mutex_fake.o $(DEPLIBS) $(SERVICE)
 
1568
+       $(CC) $(LDFLAGS) -o fud $(SERVICE) fud.o mutex_fake.o libimap.a \
 
1569
+       $(DEPLIBS) $(LIBS) $(LIB_WRAP)
 
1570
+
 
1571
+smmapd: smmapd.o libimap.a mutex_fake.o $(DEPLIBS) $(SERVICE)
 
1572
+       $(CC) $(LDFLAGS) -o smmapd $(SERVICE) smmapd.o mutex_fake.o libimap.a \
 
1573
+       $(DEPLIBS) $(LIBS) $(LIB_WRAP)
 
1574
+
 
1575
+### Command Line Utilities
 
1576
+arbitron: arbitron.o $(CLIOBJS) libimap.a $(DEPLIBS)
 
1577
+       $(CC) $(LDFLAGS) -o arbitron arbitron.o $(CLIOBJS) \
 
1578
+       libimap.a $(DEPLIBS) $(LIBS)
 
1579
+
 
1580
+cvt_cyrusdb: cvt_cyrusdb.o mutex_fake.o libimap.a $(DEPLIBS)
 
1581
+       $(CC) $(LDFLAGS) -o cvt_cyrusdb cvt_cyrusdb.o $(CLIOBJS) \
 
1582
+       libimap.a $(DEPLIBS) $(LIBS)
 
1583
+
 
1584
+chk_cyrus: chk_cyrus.o mutex_fake.o libimap.a $(DEPLIBS)
 
1585
+       $(CC) $(LDFLAGS) -o chk_cyrus chk_cyrus.o $(CLIOBJS) \
 
1586
+       libimap.a $(DEPLIBS) $(LIBS)
 
1587
+
 
1588
+deliver: deliver.o backend.o $(LMTPOBJS) mutex_fake.o libimap.a $(DEPLIBS)
 
1589
+       $(CC) $(LDFLAGS) -o deliver deliver.o backend.o $(LMTPOBJS) \
 
1590
+       mutex_fake.o libimap.a $(DEPLIBS) $(LIBS)
 
1591
+
 
1592
+ctl_deliver: ctl_deliver.o $(CLIOBJS) libimap.a $(DEPLIBS)
 
1593
+       $(CC) $(LDFLAGS) -o \
 
1594
+        $@ ctl_deliver.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
 
1595
+
 
1596
+ctl_mboxlist: ctl_mboxlist.o mupdate-client.o $(CLIOBJS) libimap.a $(DEPLIBS)
 
1597
+       $(CC) $(LDFLAGS) -o $@ ctl_mboxlist.o mupdate-client.o $(CLIOBJS) \
 
1598
+       libimap.a $(DEPLIBS) $(LIBS)
 
1599
+
 
1600
+ctl_cyrusdb: ctl_cyrusdb.o $(CLIOBJS) libimap.a $(DEPLIBS)
 
1601
+       $(CC) $(LDFLAGS) -o \
 
1602
+        $@ ctl_cyrusdb.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
 
1603
+
 
1604
+cyr_expire: cyr_expire.o $(CLIOBJS) libimap.a $(DEPLIBS)
 
1605
+       $(CC) $(LDFLAGS) -o $@ cyr_expire.o $(CLIOBJS) \
 
1606
+       libimap.a $(DEPLIBS) $(LIBS)
 
1607
+
 
1608
+fetchnews: fetchnews.o $(CLIOBJS) libimap.a $(DEPLIBS)
 
1609
+       $(CC) $(LDFLAGS) -o \
 
1610
+        $@ fetchnews.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
 
1611
+
 
1612
+squatter: squatter.o index.o squat_build.o $(CLIOBJS) libimap.a $(DEPLIBS)
 
1613
+       $(CC) $(LDFLAGS) -o squatter squatter.o index.o squat_build.o \
 
1614
+       $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
 
1615
+
 
1616
+mbpath: mbpath.o $(CLIOBJS) libimap.a $(DEPLIBS)
 
1617
+       $(CC) $(LDFLAGS) -o mbpath mbpath.o $(CLIOBJS) libimap.a \
 
1618
+       $(DEPLIBS) $(LIBS)
 
1619
+
 
1620
+ipurge: ipurge.o $(CLIOBJS) libimap.a $(DEPLIBS)
 
1621
+       $(CC) $(LDFLAGS) -o ipurge ipurge.o $(CLIOBJS) \
 
1622
+       libimap.a $(DEPLIBS) $(LIBS)
 
1623
+
 
1624
+cyrdump: cyrdump.o index.o $(CLIOBJS) libimap.a $(DEPLIBS)
 
1625
+       $(CC) $(LDFLAGS) -o cyrdump cyrdump.o index.o $(CLIOBJS) \
 
1626
+       libimap.a $(DEPLIBS) $(LIBS)
 
1627
+
 
1628
+mbexamine: mbexamine.o $(CLIOBJS) libimap.a $(DEPLIBS)
 
1629
+       $(CC) $(LDFLAGS) -o \
 
1630
+        mbexamine mbexamine.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
 
1631
+
 
1632
+reconstruct: reconstruct.o $(CLIOBJS) libimap.a $(DEPLIBS)
 
1633
+       $(CC) $(LDFLAGS) -o \
 
1634
+        reconstruct reconstruct.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
 
1635
+
 
1636
+quota: quota.o $(CLIOBJS) libimap.a $(DEPLIBS)
 
1637
+       $(CC) $(LDFLAGS) -o quota quota.o $(CLIOBJS) \
 
1638
+       libimap.a $(DEPLIBS) $(LIBS)
 
1639
+
 
1640
+tls_prune: tls_prune.o tls.o $(CLIOBJS) libimap.a $(DEPLIBS)
 
1641
+       $(CC) $(LDFLAGS) -o \
 
1642
+        $@ tls_prune.o tls.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
 
1643
+
 
1644
+### Other Misc Targets
 
1645
+
 
1646
+clean:
 
1647
+       rm -f *.o *.a Makefile.bak makedepend.log \
 
1648
+       $(BUILTSOURCES) $(PROGS) $(SUIDPROGS)
 
1649
+
 
1650
+distclean: clean
 
1651
+       rm -f Makefile
 
1652
+
 
1653
+depend: imap_err.h
 
1654
+       ${MAKEDEPEND} $(CPPFLAGS) $(DEFS) $(CFLAGS) *.c $(srcdir)/*.c 1>makedepend.log 2>&1
 
1655
+
 
1656
+# DO NOT DELETE THIS LINE -- make depend depends on it.
 
1657
diff -urNad cyrus-imapd-2.2.13/imap/imapd.c /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/imap/imapd.c
 
1658
--- cyrus-imapd-2.2.13/imap/imapd.c     2006-04-18 20:39:34.000000000 +0200
 
1659
+++ /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/imap/imapd.c    2006-04-18 20:39:35.689096237 +0200
 
1660
@@ -138,6 +138,18 @@
76
1661
     1, 1, &imapd_authstate, &imapd_userisadmin, &imapd_userisproxyadmin
77
1662
 };
78
1663
 
91
1676
 /* current sub-user state */
92
1677
 static struct mailbox mboxstruct;
93
1678
 static struct mailbox *imapd_mailbox;
94
 
@@ -558,6 +570,23 @@
 
1679
@@ -560,6 +572,23 @@
95
1680
     /* setup for sending IMAP IDLE notifications */
96
1681
     idle_enabled();
97
1682
 
115
1700
     /* create connection to the SNMP listener, if available. */
116
1701
     snmp_connect(); /* ignore return code */
117
1702
     snmp_set_str(SERVER_NAME_VERSION,CYRUS_VERSION);
118
 
@@ -650,6 +679,15 @@
 
1703
@@ -652,6 +681,15 @@
119
1704
                imapd_haveaddr = 1;
120
1705
            }
121
1706
        }
131
1716
     }
132
1717
 
133
1718
     /* create the SASL connection */
134
 
@@ -692,6 +730,11 @@
 
1719
@@ -694,6 +732,11 @@
135
1720
     prot_flush(imapd_out);
136
1721
     snmp_increment(ACTIVE_CONNECTIONS, -1);
137
1722
 
143
1728
     /* cleanup */
144
1729
     imapd_reset();
145
1730
 
146
 
@@ -772,6 +815,10 @@
 
1731
@@ -774,6 +817,10 @@
147
1732
 
148
1733
     cyrus_done();
149
1734
 
154
1739
     exit(code);
155
1740
 }
156
1741
 
157
 
@@ -809,6 +856,35 @@
 
1742
@@ -811,6 +858,35 @@
158
1743
     shut_down(code);
159
1744
 }
160
1745
 
190
1775
 /*
191
1776
  * Top-level command loop parsing
192
1777
  */
193
 
@@ -1836,6 +1912,11 @@
 
1778
@@ -1848,6 +1924,11 @@
194
1779
 
195
1780
     prot_printf(imapd_out, "%s OK %s\r\n", tag, reply);
196
1781
 
202
1787
     /* Create telemetry log */
203
1788
     imapd_logfd = telemetry_log(imapd_userid, imapd_in, imapd_out, 0);
204
1789
 
205
 
@@ -1982,6 +2063,11 @@
 
1790
@@ -1994,6 +2075,11 @@
206
1791
     prot_setsasl(imapd_in,  imapd_saslconn);
207
1792
     prot_setsasl(imapd_out, imapd_saslconn);
208
1793
 
214
1799
     /* Create telemetry log */
215
1800
     imapd_logfd = telemetry_log(imapd_userid, imapd_in, imapd_out, 0);
216
1801
 
217
 
diff -urNad cyrus-imapd-2.2.12/imap/pop3d.c /tmp/dpep.FoExSn/cyrus-imapd-2.2.12/imap/pop3d.c
218
 
--- cyrus-imapd-2.2.12/imap/pop3d.c     2006-02-14 17:13:36.000000000 +0100
219
 
+++ /tmp/dpep.FoExSn/cyrus-imapd-2.2.12/imap/pop3d.c    2006-02-14 17:13:44.661438045 +0100
220
 
@@ -44,6 +44,10 @@
221
 
  */
222
 
 #include <config.h>
 
1802
diff -urNad cyrus-imapd-2.2.13/imap/imapd.c.orig /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/imap/imapd.c.orig
 
1803
--- cyrus-imapd-2.2.13/imap/imapd.c.orig        1970-01-01 01:00:00.000000000 +0100
 
1804
+++ /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/imap/imapd.c.orig       2006-04-18 20:39:35.700095168 +0200
 
1805
@@ -0,0 +1,7624 @@
 
1806
+/* 
 
1807
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
 
1808
+ *
 
1809
+ * Redistribution and use in source and binary forms, with or without
 
1810
+ * modification, are permitted provided that the following conditions
 
1811
+ * are met:
 
1812
+ *
 
1813
+ * 1. Redistributions of source code must retain the above copyright
 
1814
+ *    notice, this list of conditions and the following disclaimer. 
 
1815
+ *
 
1816
+ * 2. Redistributions in binary form must reproduce the above copyright
 
1817
+ *    notice, this list of conditions and the following disclaimer in
 
1818
+ *    the documentation and/or other materials provided with the
 
1819
+ *    distribution.
 
1820
+ *
 
1821
+ * 3. The name "Carnegie Mellon University" must not be used to
 
1822
+ *    endorse or promote products derived from this software without
 
1823
+ *    prior written permission. For permission or any other legal
 
1824
+ *    details, please contact  
 
1825
+ *      Office of Technology Transfer
 
1826
+ *      Carnegie Mellon University
 
1827
+ *      5000 Forbes Avenue
 
1828
+ *      Pittsburgh, PA  15213-3890
 
1829
+ *      (412) 268-4387, fax: (412) 268-7395
 
1830
+ *      tech-transfer@andrew.cmu.edu
 
1831
+ *
 
1832
+ * 4. Redistributions of any form whatsoever must retain the following
 
1833
+ *    "This product includes software developed by Computing Services
 
1834
+ *    acknowledgment:
 
1835
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
 
1836
+ *
 
1837
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
1838
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 
1839
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
 
1840
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
1841
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 
1842
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 
1843
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
1844
+ */
 
1845
+
 
1846
+/* $Id: imapd.c,v 1.498 2006/01/13 22:06:28 murch Exp $ */
 
1847
+
 
1848
+#include <config.h>
 
1849
+
 
1850
+#ifdef HAVE_UNISTD_H
 
1851
+#include <unistd.h>
 
1852
+#endif
 
1853
+#include <stdio.h>
 
1854
+#include <string.h>
 
1855
+#include <ctype.h>
 
1856
+#include <errno.h>
 
1857
+#include <signal.h>
 
1858
+#include <fcntl.h>
 
1859
+#include <sys/types.h>
 
1860
+#include <sys/param.h>
 
1861
+#include <sys/stat.h>
 
1862
+#include <syslog.h>
 
1863
+#include <netdb.h>
 
1864
+#include <sys/socket.h>
 
1865
+#include <sys/wait.h>
 
1866
+#include <netinet/in.h>
 
1867
+#include <arpa/inet.h>
 
1868
+
 
1869
+#include <sasl/sasl.h>
 
1870
+
 
1871
+#include "acl.h"
 
1872
+#include "annotate.h"
 
1873
+#include "append.h"
 
1874
+#include "auth.h"
 
1875
+#include "backend.h"
 
1876
+#include "charset.h"
 
1877
+#include "exitcodes.h"
 
1878
+#include "idle.h"
 
1879
+#include "global.h"
 
1880
+#include "imap_err.h"
 
1881
+#include "imapd.h"
 
1882
+#include "imapurl.h"
 
1883
+#include "imparse.h"
 
1884
+#include "iptostring.h"
 
1885
+#include "mailbox.h"
 
1886
+#include "message.h"
 
1887
+#include "mboxname.h"
 
1888
+#include "mboxlist.h"
 
1889
+#include "mbdump.h"
 
1890
+#include "mkgmtime.h"
 
1891
+#include "mupdate-client.h"
 
1892
+#include "quota.h"
 
1893
+#include "telemetry.h"
 
1894
+#include "tls.h"
 
1895
+#include "user.h"
 
1896
+#include "util.h"
 
1897
+#include "version.h"
 
1898
+#include "xmalloc.h"
 
1899
+
 
1900
+#include "pushstats.h"         /* SNMP interface */
 
1901
+
 
1902
+extern void seen_done(void);
 
1903
+
 
1904
+extern int optind;
 
1905
+extern char *optarg;
 
1906
+
 
1907
+/* global state */
 
1908
+const int config_need_data = CONFIG_NEED_PARTITION_DATA;
 
1909
+
 
1910
+static char shutdownfilename[1024];
 
1911
+static int imaps = 0;
 
1912
+static sasl_ssf_t extprops_ssf = 0;
 
1913
+
 
1914
+/* per-user/session state */
 
1915
+struct protstream *imapd_out = NULL;
 
1916
+struct protstream *imapd_in = NULL;
 
1917
+static char imapd_clienthost[NI_MAXHOST*2+1] = "[local]";
 
1918
+static int imapd_logfd = -1;
 
1919
+char *imapd_userid;
 
1920
+static char *imapd_magicplus = NULL;
 
1921
+struct auth_state *imapd_authstate = 0;
 
1922
+static int imapd_userisadmin = 0;
 
1923
+static int imapd_userisproxyadmin = 0;
 
1924
+static sasl_conn_t *imapd_saslconn; /* the sasl connection context */
 
1925
+static int imapd_starttls_done = 0; /* have we done a successful starttls? */
 
1926
+const char *plaintextloginalert = NULL;
 
1927
+#ifdef HAVE_SSL
 
1928
+/* our tls connection, if any */
 
1929
+static SSL *tls_conn = NULL;
 
1930
+#endif /* HAVE_SSL */
 
1931
+
 
1932
+/* stage(s) for APPEND */
 
1933
+struct appendstage {
 
1934
+    struct stagemsg *stage;
 
1935
+    char **flag;
 
1936
+    int nflags, flagalloc;
 
1937
+    time_t internaldate;
 
1938
+} **stage = NULL;
 
1939
+unsigned long numstage = 0;
 
1940
+
 
1941
+/* the sasl proxy policy context */
 
1942
+static struct proxy_context imapd_proxyctx = {
 
1943
+    1, 1, &imapd_authstate, &imapd_userisadmin, &imapd_userisproxyadmin
 
1944
+};
 
1945
+
 
1946
+/* current sub-user state */
 
1947
+static struct mailbox mboxstruct;
 
1948
+static struct mailbox *imapd_mailbox;
 
1949
+int imapd_exists = -1;
 
1950
+
 
1951
+/* current namespace */
 
1952
+static struct namespace imapd_namespace;
 
1953
+
 
1954
+static const char *monthname[] = {
 
1955
+    "jan", "feb", "mar", "apr", "may", "jun",
 
1956
+    "jul", "aug", "sep", "oct", "nov", "dec"
 
1957
+};
 
1958
+
 
1959
+static const int max_monthdays[] = {
 
1960
+    31, 29, 31, 30, 31, 30,
 
1961
+    31, 31, 30, 31, 30, 31
 
1962
+};
 
1963
+
 
1964
+void motd_file(int fd);
 
1965
+void shut_down(int code);
 
1966
+void fatal(const char *s, int code);
 
1967
+
 
1968
+void cmdloop(void);
 
1969
+void cmd_login(char *tag, char *user);
 
1970
+void cmd_authenticate(char *tag, char *authtype, char *resp);
 
1971
+void cmd_noop(char *tag, char *cmd);
 
1972
+void cmd_capability(char *tag);
 
1973
+void cmd_append(char *tag, char *name);
 
1974
+void cmd_select(char *tag, char *cmd, char *name);
 
1975
+void cmd_close(char *tag);
 
1976
+void cmd_fetch(char *tag, char *sequence, int usinguid);
 
1977
+void cmd_partial(const char *tag, const char *msgno, char *data,
 
1978
+                const char *start, const char *count);
 
1979
+void cmd_store(char *tag, char *sequence, char *operation, int usinguid);
 
1980
+void cmd_search(char *tag, int usinguid);
 
1981
+void cmd_sort(char *tag, int usinguid);
 
1982
+void cmd_thread(char *tag, int usinguid);
 
1983
+void cmd_copy(char *tag, char *sequence, char *name, int usinguid);
 
1984
+void cmd_expunge(char *tag, char *sequence);
 
1985
+void cmd_create(char *tag, char *name, char *partition, int localonly);
 
1986
+void cmd_delete(char *tag, char *name, int localonly);
 
1987
+void cmd_dump(char *tag, char *name, int uid_start);
 
1988
+void cmd_undump(char *tag, char *name);
 
1989
+void cmd_xfer(char *tag, char *name, char *toserver, char *topart);
 
1990
+void cmd_rename(const char *tag, char *oldname, 
 
1991
+               char *newname, char *partition);
 
1992
+void cmd_reconstruct(const char *tag, const char *name, int recursive);
 
1993
+void cmd_find(char *tag, char *namespace, char *pattern);
 
1994
+void cmd_list(char *tag, int subscribed, char *reference, char *pattern);
 
1995
+void cmd_changesub(char *tag, char *namespace, char *name, int add);
 
1996
+void cmd_getacl(const char *tag, const char *name);
 
1997
+void cmd_listrights(char *tag, char *name, char *identifier);
 
1998
+void cmd_myrights(const char *tag, const char *name);
 
1999
+void cmd_setacl(const char *tag, const char *name,
 
2000
+               const char *identifier, const char *rights);
 
2001
+void cmd_getquota(const char *tag, const char *name);
 
2002
+void cmd_getquotaroot(const char *tag, const char *name);
 
2003
+void cmd_setquota(const char *tag, const char *quotaroot);
 
2004
+void cmd_status(char *tag, char *name);
 
2005
+void cmd_getuids(char *tag, char *startuid);
 
2006
+void cmd_unselect(char* tag);
 
2007
+void cmd_namespace(char* tag);
 
2008
+void cmd_mupdatepush(char *tag, char *name);
 
2009
+void cmd_id(char* tag);
 
2010
+extern void id_getcmdline(int argc, char **argv);
 
2011
+extern void id_response(struct protstream *pout);
 
2012
+
 
2013
+void cmd_idle(char* tag);
 
2014
+void idle_update(idle_flags_t flags);
 
2015
+
 
2016
+void cmd_starttls(char *tag, int imaps);
 
2017
+
 
2018
+#ifdef ENABLE_X_NETSCAPE_HACK
 
2019
+void cmd_netscrape(char* tag);
 
2020
+#endif
 
2021
+
 
2022
+void cmd_getannotation(char* tag, char *mboxpat);
 
2023
+void cmd_setannotation(char* tag, char *mboxpat);
 
2024
+
 
2025
+int getannotatefetchdata(char *tag,
 
2026
+                        struct strlist **entries, struct strlist **attribs);
 
2027
+int getannotatestoredata(char *tag, struct entryattlist **entryatts);
 
2028
+
 
2029
+void annotate_response(struct entryattlist *l);
 
2030
+
 
2031
+#ifdef ENABLE_LISTEXT
 
2032
+int getlistopts(char *tag, int *listopts);
 
2033
+#endif
 
2034
+
 
2035
+int getsearchprogram(char *tag, struct searchargs *searchargs,
 
2036
+                       int *charset, int parsecharset);
 
2037
+int getsearchcriteria(char *tag, struct searchargs *searchargs,
 
2038
+                        int *charset, int parsecharset);
 
2039
+int getsearchdate(time_t *start, time_t *end);
 
2040
+int getsortcriteria(char *tag, struct sortcrit **sortcrit);
 
2041
+int getdatetime(time_t *date);
 
2042
+
 
2043
+void printstring(const char *s);
 
2044
+void printastring(const char *s);
 
2045
+
 
2046
+void appendfieldlist(struct fieldlist **l, char *section,
 
2047
+                    struct strlist *fields, char *trail,
 
2048
+                    void *d, size_t size);
 
2049
+void freefieldlist(struct fieldlist *l);
 
2050
+void freestrlist(struct strlist *l);
 
2051
+void appendsearchargs(struct searchargs *s, struct searchargs *s1,
 
2052
+                        struct searchargs *s2);
 
2053
+void freesearchargs(struct searchargs *s);
 
2054
+static void freesortcrit(struct sortcrit *s);
 
2055
+
 
2056
+static int mailboxdata(char *name, int matchlen, int maycreate, void *rock);
 
2057
+static int listdata(char *name, int matchlen, int maycreate, void *rock);
 
2058
+static void mstringdata(char *cmd, char *name, int matchlen, int maycreate,
 
2059
+                       int listopts);
 
2060
+
 
2061
+extern void setproctitle_init(int argc, char **argv, char **envp);
 
2062
+extern int proc_register(const char *progname, const char *clienthost, 
 
2063
+                        const char *userid, const char *mailbox);
 
2064
+extern void proc_cleanup(void);
 
2065
+
 
2066
+extern int saslserver(sasl_conn_t *conn, const char *mech,
 
2067
+                     const char *init_resp, const char *resp_prefix,
 
2068
+                     const char *continuation, const char *empty_resp,
 
2069
+                     struct protstream *pin, struct protstream *pout,
 
2070
+                     int *sasl_result, char **success_data);
 
2071
+
 
2072
+/* Enable the resetting of a sasl_conn_t */
 
2073
+static int reset_saslconn(sasl_conn_t **conn);
 
2074
+
 
2075
+static struct 
 
2076
+{
 
2077
+    char *ipremoteport;
 
2078
+    char *iplocalport;
 
2079
+    sasl_ssf_t ssf;
 
2080
+    char *authid;
 
2081
+} saslprops = {NULL,NULL,0,NULL};
 
2082
+
 
2083
+static int imapd_canon_user(sasl_conn_t *conn, void *context,
 
2084
+                           const char *user, unsigned ulen,
 
2085
+                           unsigned flags, const char *user_realm,
 
2086
+                           char *out, unsigned out_max, unsigned *out_ulen)
 
2087
+{
 
2088
+    char userbuf[MAX_MAILBOX_NAME+1], *p;
 
2089
+    size_t n;
 
2090
+    int r;
 
2091
+
 
2092
+    if (!ulen) ulen = strlen(user);
 
2093
+
 
2094
+    if (config_getswitch(IMAPOPT_IMAPMAGICPLUS)) {
 
2095
+       /* make a working copy of the auth[z]id */
 
2096
+       if (ulen > MAX_MAILBOX_NAME) {
 
2097
+           sasl_seterror(conn, 0, "buffer overflow while canonicalizing");
 
2098
+           return SASL_BUFOVER;
 
2099
+       }
 
2100
+       memcpy(userbuf, user, ulen);
 
2101
+       userbuf[ulen] = '\0';
 
2102
+       user = userbuf;
 
2103
+
 
2104
+       /* See if we're using the magic plus
 
2105
+          (currently we don't support anything after '+') */
 
2106
+       if ((p = strchr(userbuf, '+')) && 
 
2107
+           (n = config_virtdomains ? strcspn(p, "@") : strlen(p)) == 1) {
 
2108
+
 
2109
+           if (flags & SASL_CU_AUTHZID) {
 
2110
+               /* make a copy of the magic plus */
 
2111
+               if (imapd_magicplus) free(imapd_magicplus);
 
2112
+               imapd_magicplus = xstrndup(p, n);
 
2113
+           }
 
2114
+
 
2115
+           /* strip the magic plus from the auth[z]id */
 
2116
+           memmove(p, p+n, strlen(p+n)+1);
 
2117
+           ulen -= n;
 
2118
+       }
 
2119
+    }
 
2120
+
 
2121
+    r = mysasl_canon_user(conn, context, user, ulen, flags, user_realm,
 
2122
+                         out, out_max, out_ulen);
 
2123
+
 
2124
+    if (!r && imapd_magicplus && flags == SASL_CU_AUTHZID) {
 
2125
+       /* If we're only doing the authzid, put back the magic plus
 
2126
+          in case its used in the challenge/response calculation */
 
2127
+       n = strlen(imapd_magicplus);
 
2128
+       if (*out_ulen + n > out_max) {
 
2129
+           sasl_seterror(conn, 0, "buffer overflow while canonicalizing");
 
2130
+           r = SASL_BUFOVER;
 
2131
+       }
 
2132
+       else {
 
2133
+           p = (config_virtdomains && (p = strchr(out, '@'))) ?
 
2134
+               p : out + *out_ulen;
 
2135
+           memmove(p+n, p, strlen(p)+1);
 
2136
+           memcpy(p, imapd_magicplus, n);
 
2137
+           *out_ulen += n;
 
2138
+       }
 
2139
+    }
 
2140
+
 
2141
+    return r;
 
2142
+}
 
2143
+
 
2144
+static int imapd_proxy_policy(sasl_conn_t *conn,
 
2145
+                             void *context,
 
2146
+                             const char *requested_user, unsigned rlen,
 
2147
+                             const char *auth_identity, unsigned alen,
 
2148
+                             const char *def_realm,
 
2149
+                             unsigned urlen,
 
2150
+                             struct propctx *propctx)
 
2151
+{
 
2152
+    if (config_getswitch(IMAPOPT_IMAPMAGICPLUS)) {
 
2153
+       char userbuf[MAX_MAILBOX_NAME+1], *p;
 
2154
+       size_t n;
 
2155
+
 
2156
+       /* make a working copy of the authzid */
 
2157
+       if (!rlen) rlen = strlen(requested_user);
 
2158
+       if (rlen > MAX_MAILBOX_NAME) {
 
2159
+           sasl_seterror(conn, 0, "buffer overflow while proxying");
 
2160
+           return SASL_BUFOVER;
 
2161
+       }
 
2162
+       memcpy(userbuf, requested_user, rlen);
 
2163
+       userbuf[rlen] = '\0';
 
2164
+       requested_user = userbuf;
 
2165
+
 
2166
+       /* See if we're using the magic plus */
 
2167
+       if ((p = strchr(userbuf, '+'))) {
 
2168
+           n = config_virtdomains ? strcspn(p, "@") : strlen(p);
 
2169
+
 
2170
+           /* strip the magic plus from the authzid */
 
2171
+           memmove(p, p+n, strlen(p+n)+1);
 
2172
+           rlen -= n;
 
2173
+       }
 
2174
+    }
 
2175
+
 
2176
+    return mysasl_proxy_policy(conn, context, requested_user, rlen,
 
2177
+                              auth_identity, alen, def_realm, urlen, propctx);
 
2178
+}
 
2179
+
 
2180
+static const struct sasl_callback mysasl_cb[] = {
 
2181
+    { SASL_CB_GETOPT, &mysasl_config, NULL },
 
2182
+    { SASL_CB_PROXY_POLICY, &imapd_proxy_policy, (void*) &imapd_proxyctx },
 
2183
+    { SASL_CB_CANON_USER, &imapd_canon_user, NULL },
 
2184
+    { SASL_CB_LIST_END, NULL, NULL }
 
2185
+};
 
2186
+
 
2187
+/* imapd_refer() issues a referral to the client. */
 
2188
+static void imapd_refer(const char *tag,
 
2189
+                       const char *server,
 
2190
+                       const char *mailbox)
 
2191
+{
 
2192
+    char url[MAX_MAILBOX_PATH+1];
 
2193
+
 
2194
+    if(!strcmp(imapd_userid, "anonymous")) {
 
2195
+       imapurl_toURL(url, server, mailbox, "ANONYMOUS");
 
2196
+    } else {
 
2197
+       imapurl_toURL(url, server, mailbox, "*");
 
2198
+    }
 
2199
+    
 
2200
+    prot_printf(imapd_out, "%s NO [REFERRAL %s] Remote mailbox.\r\n", 
 
2201
+               tag, url);
 
2202
+}
 
2203
+
 
2204
+/* wrapper for mboxlist_lookup that will force a referral if we are remote
 
2205
+ * returns IMAP_SERVER_UNAVAILABLE if we don't have a place to send the client
 
2206
+ * (that'd be a bug).
 
2207
+ * returns IMAP_MAILBOX_MOVED if we referred the client */
 
2208
+/* ext_name is the external name of the mailbox */
 
2209
+/* you can avoid referring the client by setting tag or ext_name to NULL. */
 
2210
+static int mlookup(const char *tag, const char *ext_name,
 
2211
+                  const char *name, int *flags, char **pathp, char **partp,
 
2212
+                  char **aclp, struct txn **tid) 
 
2213
+{
 
2214
+    int r, mbtype;
 
2215
+    char *remote, *acl;
 
2216
+
 
2217
+    r = mboxlist_detail(name, &mbtype, pathp, &remote, &acl, tid);
 
2218
+
 
2219
+    if(partp) *partp = remote;
 
2220
+    if(aclp) *aclp = acl;
 
2221
+    if(flags) *flags = mbtype;
 
2222
+    if(r) return r;
 
2223
+
 
2224
+    if(mbtype & MBTYPE_RESERVE) return IMAP_MAILBOX_RESERVED;
 
2225
+    
 
2226
+    if(mbtype & MBTYPE_MOVING) {
 
2227
+       /* do we have rights on the mailbox? */
 
2228
+       if(!imapd_userisadmin &&
 
2229
+          (!acl || !(cyrus_acl_myrights(imapd_authstate,acl) & ACL_LOOKUP))) {
 
2230
+           r = IMAP_MAILBOX_NONEXISTENT;
 
2231
+       } else if(tag && ext_name && remote && *remote) {
 
2232
+           char *c = NULL;
 
2233
+           
 
2234
+           c = strchr(remote, '!');
 
2235
+           if(c) *c = '\0';
 
2236
+           imapd_refer(tag, remote, ext_name);
 
2237
+           r = IMAP_MAILBOX_MOVED;
 
2238
+       } else if(config_mupdate_server) {
 
2239
+           r = IMAP_SERVER_UNAVAILABLE;
 
2240
+       } else {
 
2241
+           r = IMAP_MAILBOX_NOTSUPPORTED;
 
2242
+       }
 
2243
+    }
 
2244
+    
 
2245
+    return r;
 
2246
+}
 
2247
+
 
2248
+static void imapd_reset(void)
 
2249
+{
 
2250
+    proc_cleanup();
 
2251
+
 
2252
+    if (imapd_mailbox) {
 
2253
+       index_closemailbox(imapd_mailbox);
 
2254
+       mailbox_close(imapd_mailbox);
 
2255
+       imapd_mailbox = 0;
 
2256
+    }
 
2257
+
 
2258
+    if (imapd_in) {
 
2259
+       /* Flush the incoming buffer */
 
2260
+       prot_NONBLOCK(imapd_in);
 
2261
+       prot_fill(imapd_in);
 
2262
+
 
2263
+       prot_free(imapd_in);
 
2264
+    }
 
2265
+
 
2266
+    if (imapd_out) {
 
2267
+       /* Flush the outgoing buffer */
 
2268
+       prot_flush(imapd_out);
 
2269
+
 
2270
+       prot_free(imapd_out);
 
2271
+    }
 
2272
+    
 
2273
+    imapd_in = imapd_out = NULL;
 
2274
+
 
2275
+#ifdef HAVE_SSL
 
2276
+    if (tls_conn) {
 
2277
+       if (tls_reset_servertls(&tls_conn) == -1) {
 
2278
+           fatal("tls_reset() failed", EC_TEMPFAIL);
 
2279
+       }
 
2280
+       tls_conn = NULL;
 
2281
+    }
 
2282
+#endif
 
2283
+
 
2284
+    cyrus_reset_stdio(); 
 
2285
+
 
2286
+    strcpy(imapd_clienthost, "[local]");
 
2287
+    if (imapd_logfd != -1) {
 
2288
+       close(imapd_logfd);
 
2289
+       imapd_logfd = -1;
 
2290
+    }
 
2291
+    if (imapd_userid != NULL) {
 
2292
+       free(imapd_userid);
 
2293
+       imapd_userid = NULL;
 
2294
+    }
 
2295
+    if (imapd_magicplus != NULL) {
 
2296
+       free(imapd_magicplus);
 
2297
+       imapd_magicplus = NULL;
 
2298
+    }
 
2299
+    if (imapd_authstate) {
 
2300
+       auth_freestate(imapd_authstate);
 
2301
+       imapd_authstate = NULL;
 
2302
+    }
 
2303
+    imapd_userisadmin = 0;
 
2304
+    imapd_userisproxyadmin = 0;
 
2305
+    if (imapd_saslconn) {
 
2306
+       sasl_dispose(&imapd_saslconn);
 
2307
+       imapd_saslconn = NULL;
 
2308
+    }
 
2309
+    imapd_starttls_done = 0;
 
2310
+    plaintextloginalert = NULL;
 
2311
+
 
2312
+    if(saslprops.iplocalport) {
 
2313
+       free(saslprops.iplocalport);
 
2314
+       saslprops.iplocalport = NULL;
 
2315
+    }
 
2316
+    if(saslprops.ipremoteport) {
 
2317
+       free(saslprops.ipremoteport);
 
2318
+       saslprops.ipremoteport = NULL;
 
2319
+    }
 
2320
+    if(saslprops.authid) {
 
2321
+       free(saslprops.authid);
 
2322
+       saslprops.authid = NULL;
 
2323
+    }
 
2324
+    saslprops.ssf = 0;
 
2325
+
 
2326
+    imapd_exists = -1;
 
2327
+}
 
2328
+
 
2329
+/*
 
2330
+ * run once when process is forked;
 
2331
+ * MUST NOT exit directly; must return with non-zero error code
 
2332
+ */
 
2333
+int service_init(int argc, char **argv, char **envp)
 
2334
+{
 
2335
+    int ret;
 
2336
+    int opt;
 
2337
+    
 
2338
+    if (geteuid() == 0) fatal("must run as the Cyrus user", EC_USAGE);
 
2339
+    setproctitle_init(argc, argv, envp);
 
2340
+
 
2341
+    /* set signal handlers */
 
2342
+    signals_set_shutdown(&shut_down);
 
2343
+    signal(SIGPIPE, SIG_IGN);
 
2344
+
 
2345
+    /* load the SASL plugins */
 
2346
+    global_sasl_init(1, 1, mysasl_cb);
 
2347
+
 
2348
+    ret = snprintf(shutdownfilename, sizeof(shutdownfilename),
 
2349
+                  "%s/msg/shutdown", config_dir);
 
2350
+    
 
2351
+    if(ret < 0 || ret >= sizeof(shutdownfilename)) {
 
2352
+       fatal("shutdownfilename buffer too small (configdirectory too long)",
 
2353
+            EC_CONFIG);
 
2354
+    }
 
2355
+
 
2356
+    /* open the mboxlist, we'll need it for real work */
 
2357
+    mboxlist_init(0);
 
2358
+    mboxlist_open(NULL);
 
2359
+    mailbox_initialize();
 
2360
+
 
2361
+    /* open the quota db, we'll need it for real work */
 
2362
+    quotadb_init(0);
 
2363
+    quotadb_open(NULL);
 
2364
+
 
2365
+    /* setup for sending IMAP IDLE notifications */
 
2366
+    idle_enabled();
 
2367
+
 
2368
+    /* create connection to the SNMP listener, if available. */
 
2369
+    snmp_connect(); /* ignore return code */
 
2370
+    snmp_set_str(SERVER_NAME_VERSION,CYRUS_VERSION);
 
2371
+
 
2372
+    while ((opt = getopt(argc, argv, "sp:")) != EOF) {
 
2373
+       switch (opt) {
 
2374
+       case 's': /* imaps (do starttls right away) */
 
2375
+           imaps = 1;
 
2376
+           if (!tls_enabled()) {
 
2377
+               syslog(LOG_ERR, "imaps: required OpenSSL options not present");
 
2378
+               fatal("imaps: required OpenSSL options not present",
 
2379
+                     EC_CONFIG);
 
2380
+           }
 
2381
+           break;
 
2382
+       case 'p': /* external protection */
 
2383
+           extprops_ssf = atoi(optarg);
 
2384
+           break;
 
2385
+       default:
 
2386
+           break;
 
2387
+       }
 
2388
+    }
 
2389
+
 
2390
+    /* Initialize the annotatemore extention */
 
2391
+    annotatemore_init(0, NULL, NULL);
 
2392
+    annotatemore_open(NULL);
 
2393
+
 
2394
+    return 0;
 
2395
+}
 
2396
+
 
2397
+/*
 
2398
+ * run for each accepted connection
 
2399
+ */
 
2400
+#ifdef ID_SAVE_CMDLINE
 
2401
+int service_main(int argc, char **argv, char **envp __attribute__((unused)))
 
2402
+#else
 
2403
+int service_main(int argc __attribute__((unused)),
 
2404
+                char **argv __attribute__((unused)),
 
2405
+                char **envp __attribute__((unused)))
 
2406
+#endif
 
2407
+{
 
2408
+    socklen_t salen;
 
2409
+    int timeout;
 
2410
+    sasl_security_properties_t *secprops = NULL;
 
2411
+    struct sockaddr_storage imapd_localaddr, imapd_remoteaddr;
 
2412
+    char localip[60], remoteip[60];
 
2413
+    char hbuf[NI_MAXHOST];
 
2414
+    int niflags;
 
2415
+    int imapd_haveaddr = 0;
 
2416
+
 
2417
+    signals_poll();
 
2418
+
 
2419
+#ifdef ID_SAVE_CMDLINE
 
2420
+    /* get command line args for use in ID before getopt mangles them */
 
2421
+    id_getcmdline(argc, argv);
 
2422
+#endif
 
2423
+
 
2424
+    imapd_in = prot_new(0, 0);
 
2425
+    imapd_out = prot_new(1, 1);
 
2426
+
 
2427
+    /* Find out name of client host */
 
2428
+    salen = sizeof(imapd_remoteaddr);
 
2429
+    if (getpeername(0, (struct sockaddr *)&imapd_remoteaddr, &salen) == 0 &&
 
2430
+       (imapd_remoteaddr.ss_family == AF_INET ||
 
2431
+        imapd_remoteaddr.ss_family == AF_INET6)) {
 
2432
+       if (getnameinfo((struct sockaddr *)&imapd_remoteaddr, salen,
 
2433
+                       hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD) == 0) {
 
2434
+           strncpy(imapd_clienthost, hbuf, sizeof(hbuf));
 
2435
+           strlcat(imapd_clienthost, " ", sizeof(imapd_clienthost));
 
2436
+           imapd_clienthost[sizeof(imapd_clienthost)-30] = '\0';
 
2437
+       } else {
 
2438
+           imapd_clienthost[0] = '\0';
 
2439
+       }
 
2440
+       niflags = NI_NUMERICHOST;
 
2441
+#ifdef NI_WITHSCOPEID
 
2442
+       if (((struct sockaddr *)&imapd_remoteaddr)->sa_family == AF_INET6)
 
2443
+           niflags |= NI_WITHSCOPEID;
 
2444
+#endif
 
2445
+       if (getnameinfo((struct sockaddr *)&imapd_remoteaddr, salen, hbuf,
 
2446
+                       sizeof(hbuf), NULL, 0, niflags) != 0)
 
2447
+           strlcpy(hbuf, "unknown", sizeof(hbuf));
 
2448
+       strlcat(imapd_clienthost, "[", sizeof(imapd_clienthost));
 
2449
+       strlcat(imapd_clienthost, hbuf, sizeof(imapd_clienthost));
 
2450
+       strlcat(imapd_clienthost, "]", sizeof(imapd_clienthost));
 
2451
+       salen = sizeof(imapd_localaddr);
 
2452
+       if (getsockname(0, (struct sockaddr *)&imapd_localaddr, &salen) == 0) {
 
2453
+           if(iptostring((struct sockaddr *)&imapd_remoteaddr, salen,
 
2454
+                         remoteip, sizeof(remoteip)) == 0
 
2455
+              && iptostring((struct sockaddr *)&imapd_localaddr, salen,
 
2456
+                            localip, sizeof(localip)) == 0) {
 
2457
+               imapd_haveaddr = 1;
 
2458
+           }
 
2459
+       }
 
2460
+    }
 
2461
+
 
2462
+    /* create the SASL connection */
 
2463
+    if (sasl_server_new("imap", config_servername, 
 
2464
+                       NULL, NULL, NULL, NULL, 0, 
 
2465
+                       &imapd_saslconn) != SASL_OK) {
 
2466
+       fatal("SASL failed initializing: sasl_server_new()", EC_TEMPFAIL);
 
2467
+    }
 
2468
+
 
2469
+    /* never allow plaintext, since IMAP has the LOGIN command */
 
2470
+    secprops = mysasl_secprops(SASL_SEC_NOPLAINTEXT);
 
2471
+    sasl_setprop(imapd_saslconn, SASL_SEC_PROPS, secprops);
 
2472
+    sasl_setprop(imapd_saslconn, SASL_SSF_EXTERNAL, &extprops_ssf);
 
2473
+
 
2474
+    if (imapd_haveaddr) {
 
2475
+       sasl_setprop(imapd_saslconn, SASL_IPREMOTEPORT, remoteip);
 
2476
+       saslprops.ipremoteport = xstrdup(remoteip);
 
2477
+       sasl_setprop(imapd_saslconn, SASL_IPLOCALPORT, localip);
 
2478
+       saslprops.iplocalport = xstrdup(localip);
 
2479
+    }
 
2480
+
 
2481
+    proc_register("imapd", imapd_clienthost, NULL, NULL);
 
2482
+
 
2483
+    /* Set inactivity timer */
 
2484
+    timeout = config_getint(IMAPOPT_TIMEOUT);
 
2485
+    if (timeout < 30) timeout = 30;
 
2486
+    prot_settimeout(imapd_in, timeout*60);
 
2487
+    prot_setflushonread(imapd_in, imapd_out);
 
2488
+
 
2489
+    /* we were connected on imaps port so we should do 
 
2490
+       TLS negotiation immediately */
 
2491
+    if (imaps == 1) cmd_starttls(NULL, 1);
 
2492
+
 
2493
+    snmp_increment(TOTAL_CONNECTIONS, 1);
 
2494
+    snmp_increment(ACTIVE_CONNECTIONS, 1);
 
2495
+
 
2496
+    cmdloop();
 
2497
+
 
2498
+    /* LOGOUT executed */
 
2499
+    prot_flush(imapd_out);
 
2500
+    snmp_increment(ACTIVE_CONNECTIONS, -1);
 
2501
+
 
2502
+    /* cleanup */
 
2503
+    imapd_reset();
 
2504
+
 
2505
+    return 0;
 
2506
+}
 
2507
+
 
2508
+/* Called by service API to shut down the service */
 
2509
+void service_abort(int error)
 
2510
+{
 
2511
+    shut_down(error);
 
2512
+}
 
2513
+
 
2514
+/*
 
2515
+ * found a motd file; spit out message and return
 
2516
+ */
 
2517
+void motd_file(fd)
 
2518
+int fd;
 
2519
+{
 
2520
+    struct protstream *motd_in;
 
2521
+    char buf[1024];
 
2522
+    char *p;
 
2523
+
 
2524
+    motd_in = prot_new(fd, 0);
 
2525
+
 
2526
+    prot_fgets(buf, sizeof(buf), motd_in);
 
2527
+    if ((p = strchr(buf, '\r'))!=NULL) *p = 0;
 
2528
+    if ((p = strchr(buf, '\n'))!=NULL) *p = 0;
 
2529
+
 
2530
+    for(p = buf; *p == '['; p++); /* can't have [ be first char, sigh */
 
2531
+    prot_printf(imapd_out, "* OK [ALERT] %s\r\n", p);
 
2532
+}
 
2533
+
 
2534
+/*
 
2535
+ * Cleanly shut down and exit
 
2536
+ */
 
2537
+void shut_down(int code) __attribute__((noreturn));
 
2538
+void shut_down(int code)
 
2539
+{
 
2540
+    proc_cleanup();
 
2541
+    if (imapd_mailbox) {
 
2542
+       index_closemailbox(imapd_mailbox);
 
2543
+       mailbox_close(imapd_mailbox);
 
2544
+    }
 
2545
+    seen_done();
 
2546
+    mboxlist_close();
 
2547
+    mboxlist_done();
 
2548
+
 
2549
+    quotadb_close();
 
2550
+    quotadb_done();
 
2551
+
 
2552
+    annotatemore_close();
 
2553
+    annotatemore_done();
 
2554
+
 
2555
+    if (imapd_in) {
 
2556
+       /* Flush the incoming buffer */
 
2557
+       prot_NONBLOCK(imapd_in);
 
2558
+       prot_fill(imapd_in);
 
2559
+       
 
2560
+       prot_free(imapd_in);
 
2561
+    }
 
2562
+    
 
2563
+    if (imapd_out) {
 
2564
+       /* Flush the outgoing buffer */
 
2565
+       prot_flush(imapd_out);
 
2566
+       prot_free(imapd_out);
 
2567
+       
 
2568
+       /* one less active connection */
 
2569
+       snmp_increment(ACTIVE_CONNECTIONS, -1);
 
2570
+    }
 
2571
+
 
2572
+#ifdef HAVE_SSL
 
2573
+    tls_shutdown_serverengine();
 
2574
+#endif
 
2575
+    /* shutdown socket nicely */
 
2576
+    cyrus_close_sock(0);
 
2577
+    cyrus_close_sock(1);
 
2578
+    cyrus_close_sock(2);
 
2579
+
 
2580
+    cyrus_done();
 
2581
+
 
2582
+    exit(code);
 
2583
+}
 
2584
+
 
2585
+void fatal(const char *s, int code)
 
2586
+{
 
2587
+    static int recurse_code = 0;
 
2588
+
 
2589
+    if (recurse_code) {
 
2590
+       /* We were called recursively. Just give up */
 
2591
+       proc_cleanup();
 
2592
+       snmp_increment(ACTIVE_CONNECTIONS, -1);
 
2593
+       exit(recurse_code);
 
2594
+    }
 
2595
+    recurse_code = code;
 
2596
+    if (imapd_out) {
 
2597
+       prot_printf(imapd_out, "* BYE Fatal error: %s\r\n", s);
 
2598
+       prot_flush(imapd_out);
 
2599
+    }
 
2600
+    if (stage) {
 
2601
+       /* Cleanup the stage(s) */
 
2602
+       while (numstage) {
 
2603
+           struct appendstage *curstage = stage[--numstage];
 
2604
+
 
2605
+           append_removestage(curstage->stage);
 
2606
+           while (curstage->nflags--) {
 
2607
+               free(curstage->flag[curstage->nflags]);
 
2608
+           }
 
2609
+           if (curstage->flag) free((char *) curstage->flag);
 
2610
+           free(curstage);
 
2611
+       }
 
2612
+       free(stage);
 
2613
+    }
 
2614
+
 
2615
+    syslog(LOG_ERR, "Fatal error: %s", s);
 
2616
+    shut_down(code);
 
2617
+}
 
2618
+
 
2619
+/*
 
2620
+ * Top-level command loop parsing
 
2621
+ */
 
2622
+void cmdloop()
 
2623
+{
 
2624
+    int fd;
 
2625
+    char motdfilename[1024];
 
2626
+    int c;
 
2627
+    int ret;
 
2628
+    int usinguid, havepartition, havenamespace, recursive;
 
2629
+    static struct buf tag, cmd, arg1, arg2, arg3, arg4;
 
2630
+    char *p, shut[1024];
 
2631
+    const char *err;
 
2632
+
 
2633
+    prot_printf(imapd_out,
 
2634
+               "* OK %s Cyrus IMAP4 %s server ready\r\n", config_servername,
 
2635
+               CYRUS_VERSION);
 
2636
+
 
2637
+    ret = snprintf(motdfilename, sizeof(motdfilename), "%s/msg/motd",
 
2638
+                  config_dir);
 
2639
+    
 
2640
+    if(ret < 0 || ret >= sizeof(motdfilename)) {
 
2641
+       fatal("motdfilename buffer too small (configdirectory too long)",
 
2642
+            EC_CONFIG);
 
2643
+    }
 
2644
+    
 
2645
+    if ((fd = open(motdfilename, O_RDONLY, 0)) != -1) {
 
2646
+       motd_file(fd);
 
2647
+       close(fd);
 
2648
+    }
 
2649
+
 
2650
+    for (;;) {
 
2651
+       if ( !imapd_userisadmin && imapd_userid
 
2652
+            && shutdown_file(shut, sizeof(shut))) {
 
2653
+           for (p = shut; *p == '['; p++); /* can't have [ be first char */
 
2654
+           prot_printf(imapd_out, "* BYE [ALERT] %s\r\n", p);
 
2655
+           shut_down(0);
 
2656
+       }
 
2657
+
 
2658
+       signals_poll();
 
2659
+
 
2660
+       /* Parse tag */
 
2661
+       c = getword(imapd_in, &tag);
 
2662
+       if (c == EOF) {
 
2663
+           if ((err = prot_error(imapd_in))!=NULL
 
2664
+               && strcmp(err, PROT_EOF_STRING)) {
 
2665
+               syslog(LOG_WARNING, "%s, closing connection", err);
 
2666
+               prot_printf(imapd_out, "* BYE %s\r\n", err);
 
2667
+           }
 
2668
+           return;
 
2669
+       }
 
2670
+       if (c != ' ' || !imparse_isatom(tag.s) || (tag.s[0] == '*' && !tag.s[1])) {
 
2671
+           prot_printf(imapd_out, "* BAD Invalid tag\r\n");
 
2672
+           eatline(imapd_in, c);
 
2673
+           continue;
 
2674
+       }
 
2675
+
 
2676
+       /* Parse command name */
 
2677
+       c = getword(imapd_in, &cmd);
 
2678
+       if (!cmd.s[0]) {
 
2679
+           prot_printf(imapd_out, "%s BAD Null command\r\n", tag.s);
 
2680
+           eatline(imapd_in, c);
 
2681
+           continue;
 
2682
+       }
 
2683
+       if (islower((unsigned char) cmd.s[0])) 
 
2684
+           cmd.s[0] = toupper((unsigned char) cmd.s[0]);
 
2685
+       for (p = &cmd.s[1]; *p; p++) {
 
2686
+           if (isupper((unsigned char) *p)) *p = tolower((unsigned char) *p);
 
2687
+       }
 
2688
+
 
2689
+       if (plaintextloginalert) {
 
2690
+           prot_printf(imapd_out, "* OK [ALERT] %s\r\n",
 
2691
+                       plaintextloginalert);
 
2692
+           plaintextloginalert = NULL;
 
2693
+       }
 
2694
+
 
2695
+       /* Only Authenticate/Login/Logout/Noop/Capability/Id/Starttls
 
2696
+          allowed when not logged in */
 
2697
+       if (!imapd_userid && !strchr("ALNCIS", cmd.s[0])) goto nologin;
 
2698
+    
 
2699
+       /* note that about half the commands (the common ones that don't
 
2700
+          hit the mailboxes file) now close the mailboxes file just in
 
2701
+          case it was open. */
 
2702
+       switch (cmd.s[0]) {
 
2703
+       case 'A':
 
2704
+           if (!strcmp(cmd.s, "Authenticate")) {
 
2705
+               int haveinitresp = 0;
 
2706
+
 
2707
+               if (c != ' ') goto missingargs;
 
2708
+               c = getword(imapd_in, &arg1);
 
2709
+               if (!imparse_isatom(arg1.s)) {
 
2710
+                   prot_printf(imapd_out, "%s BAD Invalid authenticate mechanism\r\n", tag.s);
 
2711
+                   eatline(imapd_in, c);
 
2712
+                   continue;
 
2713
+               }
 
2714
+               if (c == ' ') {
 
2715
+                   haveinitresp = 1;
 
2716
+                   c = getword(imapd_in, &arg2);
 
2717
+                   if (c == EOF) goto missingargs;
 
2718
+               }
 
2719
+               if (c == '\r') c = prot_getc(imapd_in);
 
2720
+               if (c != '\n') goto extraargs;
 
2721
+               
 
2722
+               if (imapd_userid) {
 
2723
+                   prot_printf(imapd_out, "%s BAD Already authenticated\r\n", tag.s);
 
2724
+                   continue;
 
2725
+               }
 
2726
+               cmd_authenticate(tag.s, arg1.s, haveinitresp ? arg2.s : NULL);
 
2727
+
 
2728
+               snmp_increment(AUTHENTICATE_COUNT, 1);
 
2729
+           }
 
2730
+           else if (!imapd_userid) goto nologin;
 
2731
+           else if (!strcmp(cmd.s, "Append")) {
 
2732
+               if (c != ' ') goto missingargs;
 
2733
+               c = getastring(imapd_in, imapd_out, &arg1);
 
2734
+               if (c != ' ') goto missingargs;
 
2735
+
 
2736
+               cmd_append(tag.s, arg1.s);
 
2737
+
 
2738
+               snmp_increment(APPEND_COUNT, 1);
 
2739
+           }
 
2740
+           else goto badcmd;
 
2741
+           break;
 
2742
+
 
2743
+       case 'B':
 
2744
+           if (!strcmp(cmd.s, "Bboard")) {
 
2745
+               if (c != ' ') goto missingargs;
 
2746
+               c = getastring(imapd_in, imapd_out, &arg1);
 
2747
+               if (c == EOF) goto missingargs;
 
2748
+               if (c == '\r') c = prot_getc(imapd_in);
 
2749
+               if (c != '\n') goto extraargs;
 
2750
+
 
2751
+               cmd_select(tag.s, cmd.s, arg1.s);
 
2752
+
 
2753
+               snmp_increment(BBOARD_COUNT, 1);
 
2754
+           }
 
2755
+           else goto badcmd;
 
2756
+           break;
 
2757
+
 
2758
+       case 'C':
 
2759
+           if (!strcmp(cmd.s, "Capability")) {
 
2760
+               if (c == '\r') c = prot_getc(imapd_in);
 
2761
+               if (c != '\n') goto extraargs;
 
2762
+               cmd_capability(tag.s);
 
2763
+
 
2764
+               snmp_increment(CAPABILITY_COUNT, 1);
 
2765
+           }
 
2766
+           else if (!imapd_userid) goto nologin;
 
2767
+           else if (!strcmp(cmd.s, "Check")) {
 
2768
+               if (!imapd_mailbox) goto nomailbox;
 
2769
+               if (c == '\r') c = prot_getc(imapd_in);
 
2770
+               if (c != '\n') goto extraargs;
 
2771
+
 
2772
+               cmd_noop(tag.s, cmd.s);
 
2773
+
 
2774
+               snmp_increment(CHECK_COUNT, 1);
 
2775
+           }
 
2776
+           else if (!strcmp(cmd.s, "Copy")) {
 
2777
+               if (!imapd_mailbox) goto nomailbox;
 
2778
+               usinguid = 0;
 
2779
+               if (c != ' ') goto missingargs;
 
2780
+           copy:
 
2781
+               c = getword(imapd_in, &arg1);
 
2782
+               if (c == '\r') goto missingargs;
 
2783
+               if (c != ' ' || !imparse_issequence(arg1.s)) goto badsequence;
 
2784
+               c = getastring(imapd_in, imapd_out, &arg2);
 
2785
+               if (c == EOF) goto missingargs;
 
2786
+               if (c == '\r') c = prot_getc(imapd_in);
 
2787
+               if (c != '\n') goto extraargs;
 
2788
+
 
2789
+               cmd_copy(tag.s, arg1.s, arg2.s, usinguid);
 
2790
+
 
2791
+               snmp_increment(COPY_COUNT, 1);
 
2792
+           }
 
2793
+           else if (!strcmp(cmd.s, "Create")) {
 
2794
+               havepartition = 0;
 
2795
+               if (c != ' ') goto missingargs;
 
2796
+               c = getastring(imapd_in, imapd_out, &arg1);
 
2797
+               if (c == EOF) goto missingargs;
 
2798
+               if (c == ' ') {
 
2799
+                   havepartition = 1;
 
2800
+                   c = getword(imapd_in, &arg2);
 
2801
+                   if (!imparse_isatom(arg2.s)) goto badpartition;
 
2802
+               }
 
2803
+               if (c == '\r') c = prot_getc(imapd_in);
 
2804
+               if (c != '\n') goto extraargs;
 
2805
+               cmd_create(tag.s, arg1.s, havepartition ? arg2.s : 0, 0);
 
2806
+
 
2807
+               snmp_increment(CREATE_COUNT, 1);
 
2808
+           }
 
2809
+           else if (!strcmp(cmd.s, "Close")) {
 
2810
+               if (!imapd_mailbox) goto nomailbox;
 
2811
+               if (c == '\r') c = prot_getc(imapd_in);
 
2812
+               if (c != '\n') goto extraargs;
 
2813
+
 
2814
+               cmd_close(tag.s);
 
2815
+
 
2816
+               snmp_increment(CLOSE_COUNT, 1);
 
2817
+           }
 
2818
+           else goto badcmd;
 
2819
+           break;
 
2820
+
 
2821
+       case 'D':
 
2822
+           if (!strcmp(cmd.s, "Delete")) {
 
2823
+               if (c != ' ') goto missingargs;
 
2824
+               c = getastring(imapd_in, imapd_out, &arg1);
 
2825
+               if (c == EOF) goto missingargs;
 
2826
+               if (c == '\r') c = prot_getc(imapd_in);
 
2827
+               if (c != '\n') goto extraargs;
 
2828
+               cmd_delete(tag.s, arg1.s, 0);
 
2829
+
 
2830
+               snmp_increment(DELETE_COUNT, 1);
 
2831
+           }
 
2832
+           else if (!strcmp(cmd.s, "Deleteacl")) {
 
2833
+               if (c != ' ') goto missingargs;
 
2834
+               c = getastring(imapd_in, imapd_out, &arg1);
 
2835
+               if (c != ' ') goto missingargs;
 
2836
+               c = getastring(imapd_in, imapd_out, &arg2);
 
2837
+               if (c == EOF) goto missingargs;
 
2838
+               if (c == '\r') c = prot_getc(imapd_in);
 
2839
+               if (c != '\n') goto extraargs;
 
2840
+               cmd_setacl(tag.s, arg1.s, arg2.s, NULL);
 
2841
+
 
2842
+               snmp_increment(DELETEACL_COUNT, 1);
 
2843
+           }
 
2844
+           else if (!strcmp(cmd.s, "Dump")) {
 
2845
+               int uid_start = 0;
 
2846
+               
 
2847
+               if(c != ' ') goto missingargs;
 
2848
+               c = getastring(imapd_in, imapd_out, &arg1);
 
2849
+               if(c == ' ') {
 
2850
+                   c = getastring(imapd_in, imapd_out, &arg2);
 
2851
+                   if(!imparse_isnumber(arg2.s)) goto extraargs;
 
2852
+                   uid_start = atoi(arg2.s);
 
2853
+               }
 
2854
+               
 
2855
+               if(c == '\r') c = prot_getc(imapd_in);
 
2856
+               if(c != '\n') goto extraargs;
 
2857
+               
 
2858
+               cmd_dump(tag.s, arg1.s, uid_start);
 
2859
+           /*  snmp_increment(DUMP_COUNT, 1);*/
 
2860
+           }
 
2861
+           else goto badcmd;
 
2862
+           break;
 
2863
+
 
2864
+       case 'E':
 
2865
+           if (!strcmp(cmd.s, "Expunge")) {
 
2866
+               if (!imapd_mailbox) goto nomailbox;
 
2867
+               if (c == '\r') c = prot_getc(imapd_in);
 
2868
+               if (c != '\n') goto extraargs;
 
2869
+
 
2870
+               cmd_expunge(tag.s, 0);
 
2871
+
 
2872
+               snmp_increment(EXPUNGE_COUNT, 1);
 
2873
+           }
 
2874
+           else if (!strcmp(cmd.s, "Examine")) {
 
2875
+               if (c != ' ') goto missingargs;
 
2876
+               c = getastring(imapd_in, imapd_out, &arg1);
 
2877
+               if (c == EOF) goto missingargs;
 
2878
+               if (c == '\r') c = prot_getc(imapd_in);
 
2879
+               if (c != '\n') goto extraargs;
 
2880
+
 
2881
+               cmd_select(tag.s, cmd.s, arg1.s);
 
2882
+
 
2883
+               snmp_increment(EXAMINE_COUNT, 1);
 
2884
+           }
 
2885
+           else goto badcmd;
 
2886
+           break;
 
2887
+
 
2888
+       case 'F':
 
2889
+           if (!strcmp(cmd.s, "Fetch")) {
 
2890
+               if (!imapd_mailbox) goto nomailbox;
 
2891
+               usinguid = 0;
 
2892
+               if (c != ' ') goto missingargs;
 
2893
+           fetch:
 
2894
+               c = getword(imapd_in, &arg1);
 
2895
+               if (c == '\r') goto missingargs;
 
2896
+               if (c != ' ' || !imparse_issequence(arg1.s)) goto badsequence;
 
2897
+
 
2898
+               cmd_fetch(tag.s, arg1.s, usinguid);
 
2899
+
 
2900
+               snmp_increment(FETCH_COUNT, 1);
 
2901
+           }
 
2902
+           else if (!strcmp(cmd.s, "Find")) {
 
2903
+               c = getword(imapd_in, &arg1);
 
2904
+               if (c != ' ') goto missingargs;
 
2905
+               c = getastring(imapd_in, imapd_out, &arg2);
 
2906
+               if (c == EOF) goto missingargs;
 
2907
+               if (c == '\r') c = prot_getc(imapd_in);
 
2908
+               if (c != '\n') goto extraargs;
 
2909
+               cmd_find(tag.s, arg1.s, arg2.s);
 
2910
+
 
2911
+               snmp_increment(FIND_COUNT, 1);
 
2912
+           }
 
2913
+           else goto badcmd;
 
2914
+           break;
 
2915
+
 
2916
+       case 'G':
 
2917
+           if (!strcmp(cmd.s, "Getacl")) {
 
2918
+               if (c != ' ') goto missingargs;
 
2919
+               c = getastring(imapd_in, imapd_out, &arg1);
 
2920
+               if (c == EOF) goto missingargs;
 
2921
+               if (c == '\r') c = prot_getc(imapd_in);
 
2922
+               if (c != '\n') goto extraargs;
 
2923
+               cmd_getacl(tag.s, arg1.s);
 
2924
+
 
2925
+               snmp_increment(GETACL_COUNT, 1);
 
2926
+           }
 
2927
+           else if (!strcmp(cmd.s, "Getannotation")) {
 
2928
+               if (c != ' ') goto missingargs;
 
2929
+               c = getastring(imapd_in, imapd_out, &arg1);
 
2930
+               if (c != ' ') goto missingargs;
 
2931
+
 
2932
+               cmd_getannotation(tag.s, arg1.s);
 
2933
+
 
2934
+               snmp_increment(GETANNOTATION_COUNT, 1);
 
2935
+           }
 
2936
+           else if (!strcmp(cmd.s, "Getquota")) {
 
2937
+               if (c != ' ') goto missingargs;
 
2938
+               c = getastring(imapd_in, imapd_out, &arg1);
 
2939
+               if (c == EOF) goto missingargs;
 
2940
+               if (c == '\r') c = prot_getc(imapd_in);
 
2941
+               if (c != '\n') goto extraargs;
 
2942
+               cmd_getquota(tag.s, arg1.s);
 
2943
+
 
2944
+               snmp_increment(GETQUOTA_COUNT, 1);
 
2945
+           }
 
2946
+           else if (!strcmp(cmd.s, "Getquotaroot")) {
 
2947
+               if (c != ' ') goto missingargs;
 
2948
+               c = getastring(imapd_in, imapd_out, &arg1);
 
2949
+               if (c == EOF) goto missingargs;
 
2950
+               if (c == '\r') c = prot_getc(imapd_in);
 
2951
+               if (c != '\n') goto extraargs;
 
2952
+               cmd_getquotaroot(tag.s, arg1.s);
 
2953
+
 
2954
+               snmp_increment(GETQUOTAROOT_COUNT, 1);
 
2955
+           }
 
2956
+           else goto badcmd;
 
2957
+           break;
 
2958
+
 
2959
+       case 'I':
 
2960
+           if (!strcmp(cmd.s, "Id")) {
 
2961
+               if (c != ' ') goto missingargs;
 
2962
+               cmd_id(tag.s);
 
2963
+
 
2964
+               snmp_increment(ID_COUNT, 1);
 
2965
+           }
 
2966
+           else if (!imapd_userid) goto nologin;
 
2967
+           else if (!strcmp(cmd.s, "Idle")) {
 
2968
+               if (!idle_enabled()) {
 
2969
+                   /* we don't support idle */
 
2970
+                   goto badcmd;
 
2971
+               }
 
2972
+
 
2973
+               if (c == '\r') c = prot_getc(imapd_in);
 
2974
+               if (c != '\n') goto extraargs;
 
2975
+               cmd_idle(tag.s);
 
2976
+
 
2977
+               snmp_increment(IDLE_COUNT, 1);
 
2978
+           }
 
2979
+           else goto badcmd;
 
2980
+           break;
 
2981
+
 
2982
+       case 'L':
 
2983
+           if (!strcmp(cmd.s, "Login")) {
 
2984
+               if (c != ' ') goto missingargs;
 
2985
+               c = getastring(imapd_in, imapd_out, &arg1);
 
2986
+               if(c != ' ') goto missingargs;
 
2987
+
 
2988
+               cmd_login(tag.s, arg1.s);
 
2989
+
 
2990
+               snmp_increment(LOGIN_COUNT, 1);
 
2991
+           }
 
2992
+           else if (!strcmp(cmd.s, "Logout")) {
 
2993
+               if (c == '\r') c = prot_getc(imapd_in);
 
2994
+               if (c != '\n') goto extraargs;
 
2995
+
 
2996
+               snmp_increment(LOGOUT_COUNT, 1);                
 
2997
+
 
2998
+               prot_printf(imapd_out, "* BYE %s\r\n", 
 
2999
+                           error_message(IMAP_BYE_LOGOUT));
 
3000
+               prot_printf(imapd_out, "%s OK %s\r\n", tag.s, 
 
3001
+                           error_message(IMAP_OK_COMPLETED));
 
3002
+               return;
 
3003
+           }
 
3004
+           else if (!imapd_userid) goto nologin;
 
3005
+           else if (!strcmp(cmd.s, "List")) {
 
3006
+               int listopts = LIST_CHILDREN;
 
3007
+#ifdef ENABLE_LISTEXT
 
3008
+               /* Check for and parse LISTEXT options */
 
3009
+               c = prot_getc(imapd_in);
 
3010
+               if (c == '(') {
 
3011
+                   c = getlistopts(tag.s, &listopts);
 
3012
+                   if (c == EOF) {
 
3013
+                       eatline(imapd_in, c);
 
3014
+                       continue;
 
3015
+                   }
 
3016
+               }
 
3017
+               else
 
3018
+                   prot_ungetc(c, imapd_in);
 
3019
+#endif /* ENABLE_LISTEXT */
 
3020
+               if (imapd_magicplus) listopts |= LIST_SUBSCRIBED;
 
3021
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3022
+               if (c != ' ') goto missingargs;
 
3023
+               c = getastring(imapd_in, imapd_out, &arg2);
 
3024
+               if (c == '\r') c = prot_getc(imapd_in);
 
3025
+               if (c != '\n') goto extraargs;
 
3026
+               cmd_list(tag.s, listopts, arg1.s, arg2.s);
 
3027
+
 
3028
+               snmp_increment(LIST_COUNT, 1);
 
3029
+           }
 
3030
+           else if (!strcmp(cmd.s, "Lsub")) {
 
3031
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3032
+               if (c != ' ') goto missingargs;
 
3033
+               c = getastring(imapd_in, imapd_out, &arg2);
 
3034
+               if (c == '\r') c = prot_getc(imapd_in);
 
3035
+               if (c != '\n') goto extraargs;
 
3036
+               cmd_list(tag.s, LIST_LSUB | LIST_CHILDREN, arg1.s, arg2.s);
 
3037
+
 
3038
+               snmp_increment(LSUB_COUNT, 1);
 
3039
+           }
 
3040
+           else if (!strcmp(cmd.s, "Listrights")) {
 
3041
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3042
+               if (c != ' ') goto missingargs;
 
3043
+               c = getastring(imapd_in, imapd_out, &arg2);
 
3044
+               if (c == '\r') c = prot_getc(imapd_in);
 
3045
+               if (c != '\n') goto extraargs;
 
3046
+               cmd_listrights(tag.s, arg1.s, arg2.s);
 
3047
+
 
3048
+               snmp_increment(LISTRIGHTS_COUNT, 1);
 
3049
+           }
 
3050
+           else if (!strcmp(cmd.s, "Localcreate")) {
 
3051
+               /* create a local-only mailbox */
 
3052
+               havepartition = 0;
 
3053
+               if (c != ' ') goto missingargs;
 
3054
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3055
+               if (c == EOF) goto missingargs;
 
3056
+               if (c == ' ') {
 
3057
+                   havepartition = 1;
 
3058
+                   c = getword(imapd_in, &arg2);
 
3059
+                   if (!imparse_isatom(arg2.s)) goto badpartition;
 
3060
+               }
 
3061
+               if (c == '\r') c = prot_getc(imapd_in);
 
3062
+               if (c != '\n') goto extraargs;
 
3063
+               cmd_create(tag.s, arg1.s, havepartition ? arg2.s : NULL, 1);
 
3064
+
 
3065
+               /* xxxx snmp_increment(CREATE_COUNT, 1); */
 
3066
+           }
 
3067
+           else if (!strcmp(cmd.s, "Localdelete")) {
 
3068
+               /* delete a mailbox locally only */
 
3069
+               if (c != ' ') goto missingargs;
 
3070
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3071
+               if (c == EOF) goto missingargs;
 
3072
+               if (c == '\r') c = prot_getc(imapd_in);
 
3073
+               if (c != '\n') goto extraargs;
 
3074
+               cmd_delete(tag.s, arg1.s, 1);
 
3075
+
 
3076
+               /* xxxx snmp_increment(DELETE_COUNT, 1); */
 
3077
+           }
 
3078
+           else goto badcmd;
 
3079
+           break;
 
3080
+
 
3081
+       case 'M':
 
3082
+           if (!strcmp(cmd.s, "Myrights")) {
 
3083
+               if (c != ' ') goto missingargs;
 
3084
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3085
+               if (c == EOF) goto missingargs;
 
3086
+               if (c == '\r') c = prot_getc(imapd_in);
 
3087
+               if (c != '\n') goto extraargs;
 
3088
+               cmd_myrights(tag.s, arg1.s);
 
3089
+
 
3090
+               /* xxxx snmp_increment(MYRIGHTS_COUNT, 1); */
 
3091
+           }
 
3092
+           else if (!strcmp(cmd.s, "Mupdatepush")) {
 
3093
+               if (c != ' ') goto missingargs;
 
3094
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3095
+               if(c == EOF) goto missingargs;
 
3096
+               if(c == '\r') c = prot_getc(imapd_in);
 
3097
+               if(c != '\n') goto extraargs;
 
3098
+               cmd_mupdatepush(tag.s, arg1.s);
 
3099
+               
 
3100
+               /* xxxx snmp_increment(MUPDATEPUSH_COUNT, 1); */
 
3101
+           } else goto badcmd;
 
3102
+           break;
 
3103
+
 
3104
+       case 'N':
 
3105
+           if (!strcmp(cmd.s, "Noop")) {
 
3106
+               if (c == '\r') c = prot_getc(imapd_in);
 
3107
+               if (c != '\n') goto extraargs;
 
3108
+
 
3109
+               cmd_noop(tag.s, cmd.s);
 
3110
+
 
3111
+               /* xxxx snmp_increment(NOOP_COUNT, 1); */
 
3112
+           }
 
3113
+#ifdef ENABLE_X_NETSCAPE_HACK
 
3114
+           else if (!strcmp(cmd.s, "Netscape")) {
 
3115
+               if (c == '\r') c = prot_getc(imapd_in);
 
3116
+               if (c != '\n') goto extraargs;
 
3117
+               cmd_netscrape(tag.s);
 
3118
+           }
 
3119
+#endif
 
3120
+           else if (!imapd_userid) goto nologin;
 
3121
+           else if (!strcmp(cmd.s, "Namespace")) {
 
3122
+               if (c == '\r') c = prot_getc(imapd_in);
 
3123
+               if (c != '\n') goto extraargs;
 
3124
+               cmd_namespace(tag.s);
 
3125
+
 
3126
+               /* xxxx snmp_increment(NAMESPACE_COUNT, 1); */
 
3127
+           }
 
3128
+           else goto badcmd;
 
3129
+           break;
 
3130
+
 
3131
+       case 'P':
 
3132
+           if (!strcmp(cmd.s, "Partial")) {
 
3133
+               if (!imapd_mailbox) goto nomailbox;
 
3134
+               if (c != ' ') goto missingargs;
 
3135
+               c = getword(imapd_in, &arg1);
 
3136
+               if (c != ' ') goto missingargs;
 
3137
+               c = getword(imapd_in, &arg2);
 
3138
+               if (c != ' ') goto missingargs;
 
3139
+               c = getword(imapd_in, &arg3);
 
3140
+               if (c != ' ') goto missingargs;
 
3141
+               c = getword(imapd_in, &arg4);
 
3142
+               if (c == '\r') c = prot_getc(imapd_in);
 
3143
+               if (c != '\n') goto extraargs;
 
3144
+
 
3145
+               cmd_partial(tag.s, arg1.s, arg2.s, arg3.s, arg4.s);
 
3146
+
 
3147
+               /* xxxx snmp_increment(PARTIAL_COUNT, 1); */
 
3148
+           }
 
3149
+           else goto badcmd;
 
3150
+           break;
 
3151
+
 
3152
+       case 'R':
 
3153
+           if (!strcmp(cmd.s, "Rename")) {
 
3154
+               havepartition = 0;
 
3155
+               if (c != ' ') goto missingargs;
 
3156
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3157
+               if (c != ' ') goto missingargs;
 
3158
+               c = getastring(imapd_in, imapd_out, &arg2);
 
3159
+               if (c == EOF) goto missingargs;
 
3160
+               if (c == ' ') {
 
3161
+                   havepartition = 1;
 
3162
+                   c = getword(imapd_in, &arg3);
 
3163
+                   if (!imparse_isatom(arg3.s)) goto badpartition;
 
3164
+               }
 
3165
+               if (c == '\r') c = prot_getc(imapd_in);
 
3166
+               if (c != '\n') goto extraargs;
 
3167
+               cmd_rename(tag.s, arg1.s, arg2.s, havepartition ? arg3.s : 0);
 
3168
+
 
3169
+               /* xxxx snmp_increment(RENAME_COUNT, 1); */
 
3170
+           } else if(!strcmp(cmd.s, "Reconstruct")) {
 
3171
+               recursive = 0;
 
3172
+               if (c != ' ') goto missingargs;
 
3173
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3174
+               if(c == ' ') {
 
3175
+                   /* Optional RECURSEIVE argument */
 
3176
+                   c = getword(imapd_in, &arg2);
 
3177
+                   if(!imparse_isatom(arg2.s))
 
3178
+                       goto extraargs;
 
3179
+                   else if(!strcasecmp(arg2.s, "RECURSIVE"))
 
3180
+                       recursive = 1;
 
3181
+                   else
 
3182
+                       goto extraargs;
 
3183
+               }
 
3184
+               if(c == '\r') c = prot_getc(imapd_in);
 
3185
+               if(c != '\n') goto extraargs;
 
3186
+               cmd_reconstruct(tag.s, arg1.s, recursive);
 
3187
+
 
3188
+               /* snmp_increment(RECONSTRUCT_COUNT, 1); */
 
3189
+           } 
 
3190
+           else if (!strcmp(cmd.s, "Rlist")) {
 
3191
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3192
+               if (c != ' ') goto missingargs;
 
3193
+               c = getastring(imapd_in, imapd_out, &arg2);
 
3194
+               if (c == '\r') c = prot_getc(imapd_in);
 
3195
+               if (c != '\n') goto extraargs;
 
3196
+               cmd_list(tag.s, LIST_CHILDREN | LIST_REMOTE, arg1.s, arg2.s);
 
3197
+
 
3198
+/*             snmp_increment(LIST_COUNT, 1); */
 
3199
+           }
 
3200
+           else if (!strcmp(cmd.s, "Rlsub")) {
 
3201
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3202
+               if (c != ' ') goto missingargs;
 
3203
+               c = getastring(imapd_in, imapd_out, &arg2);
 
3204
+               if (c == '\r') c = prot_getc(imapd_in);
 
3205
+               if (c != '\n') goto extraargs;
 
3206
+               cmd_list(tag.s, LIST_LSUB | LIST_CHILDREN | LIST_REMOTE,
 
3207
+                        arg1.s, arg2.s);
 
3208
+/*             snmp_increment(LSUB_COUNT, 1); */
 
3209
+           } else goto badcmd;
 
3210
+           break;
 
3211
+           
 
3212
+       case 'S':
 
3213
+           if (!strcmp(cmd.s, "Starttls")) {
 
3214
+               if (!tls_enabled()) {
 
3215
+                   /* we don't support starttls */
 
3216
+                   goto badcmd;
 
3217
+               }
 
3218
+
 
3219
+               if (c == '\r') c = prot_getc(imapd_in);
 
3220
+               if (c != '\n') goto extraargs;
 
3221
+
 
3222
+               /* if we've already done SASL fail */
 
3223
+               if (imapd_userid != NULL) {
 
3224
+                   prot_printf(imapd_out, 
 
3225
+              "%s BAD Can't Starttls after authentication\r\n", tag.s);
 
3226
+                   continue;
 
3227
+               }
 
3228
+               
 
3229
+               /* check if already did a successful tls */
 
3230
+               if (imapd_starttls_done == 1) {
 
3231
+                   prot_printf(imapd_out, 
 
3232
+                               "%s BAD Already did a successful Starttls\r\n",
 
3233
+                               tag.s);
 
3234
+                   continue;
 
3235
+               }
 
3236
+               cmd_starttls(tag.s, 0); 
 
3237
+
 
3238
+               snmp_increment(STARTTLS_COUNT, 1);      
 
3239
+               continue;
 
3240
+           }
 
3241
+           if (!imapd_userid) {
 
3242
+               goto nologin;
 
3243
+           } else if (!strcmp(cmd.s, "Store")) {
 
3244
+               if (!imapd_mailbox) goto nomailbox;
 
3245
+               usinguid = 0;
 
3246
+               if (c != ' ') goto missingargs;
 
3247
+           store:
 
3248
+               c = getword(imapd_in, &arg1);
 
3249
+               if (c != ' ' || !imparse_issequence(arg1.s)) goto badsequence;
 
3250
+               c = getword(imapd_in, &arg2);
 
3251
+               if (c != ' ') goto missingargs;
 
3252
+
 
3253
+               cmd_store(tag.s, arg1.s, arg2.s, usinguid);
 
3254
+
 
3255
+               snmp_increment(STORE_COUNT, 1);
 
3256
+           }
 
3257
+           else if (!strcmp(cmd.s, "Select")) {
 
3258
+               if (c != ' ') goto missingargs;
 
3259
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3260
+               if (c == EOF) goto missingargs;
 
3261
+               if (c == '\r') c = prot_getc(imapd_in);
 
3262
+               if (c != '\n') goto extraargs;
 
3263
+
 
3264
+               cmd_select(tag.s, cmd.s, arg1.s);
 
3265
+
 
3266
+               snmp_increment(SELECT_COUNT, 1);
 
3267
+           }
 
3268
+           else if (!strcmp(cmd.s, "Search")) {
 
3269
+               if (!imapd_mailbox) goto nomailbox;
 
3270
+               usinguid = 0;
 
3271
+               if (c != ' ') goto missingargs;
 
3272
+           search:
 
3273
+
 
3274
+               cmd_search(tag.s, usinguid);
 
3275
+
 
3276
+               snmp_increment(SEARCH_COUNT, 1);
 
3277
+           }
 
3278
+           else if (!strcmp(cmd.s, "Subscribe")) {
 
3279
+               if (c != ' ') goto missingargs;
 
3280
+               havenamespace = 0;
 
3281
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3282
+               if (c == ' ') {
 
3283
+                   havenamespace = 1;
 
3284
+                   c = getastring(imapd_in, imapd_out, &arg2);
 
3285
+               }
 
3286
+               if (c == EOF) goto missingargs;
 
3287
+               if (c == '\r') c = prot_getc(imapd_in);
 
3288
+               if (c != '\n') goto extraargs;
 
3289
+               if (havenamespace) {
 
3290
+                   cmd_changesub(tag.s, arg1.s, arg2.s, 1);
 
3291
+               }
 
3292
+               else {
 
3293
+                   cmd_changesub(tag.s, (char *)0, arg1.s, 1);
 
3294
+               }
 
3295
+               snmp_increment(SUBSCRIBE_COUNT, 1);
 
3296
+           }           
 
3297
+           else if (!strcmp(cmd.s, "Setacl")) {
 
3298
+               if (c != ' ') goto missingargs;
 
3299
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3300
+               if (c != ' ') goto missingargs;
 
3301
+               c = getastring(imapd_in, imapd_out, &arg2);
 
3302
+               if (c != ' ') goto missingargs;
 
3303
+               c = getastring(imapd_in, imapd_out, &arg3);
 
3304
+               if (c == EOF) goto missingargs;
 
3305
+               if (c == '\r') c = prot_getc(imapd_in);
 
3306
+               if (c != '\n') goto extraargs;
 
3307
+               cmd_setacl(tag.s, arg1.s, arg2.s, arg3.s);
 
3308
+
 
3309
+               snmp_increment(SETACL_COUNT, 1);
 
3310
+           }
 
3311
+           else if (!strcmp(cmd.s, "Setannotation")) {
 
3312
+               if (c != ' ') goto missingargs;
 
3313
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3314
+               if (c != ' ') goto missingargs;
 
3315
+
 
3316
+               cmd_setannotation(tag.s, arg1.s);
 
3317
+
 
3318
+               snmp_increment(SETANNOTATION_COUNT, 1);
 
3319
+           }
 
3320
+           else if (!strcmp(cmd.s, "Setquota")) {
 
3321
+               if (c != ' ') goto missingargs;
 
3322
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3323
+               if (c != ' ') goto missingargs;
 
3324
+               cmd_setquota(tag.s, arg1.s);
 
3325
+
 
3326
+               snmp_increment(SETQUOTA_COUNT, 1);
 
3327
+           }
 
3328
+           else if (!strcmp(cmd.s, "Sort")) {
 
3329
+               if (!imapd_mailbox) goto nomailbox;
 
3330
+               usinguid = 0;
 
3331
+               if (c != ' ') goto missingargs;
 
3332
+           sort:
 
3333
+               cmd_sort(tag.s, usinguid);
 
3334
+
 
3335
+               snmp_increment(SORT_COUNT, 1);
 
3336
+           }
 
3337
+           else if (!strcmp(cmd.s, "Status")) {
 
3338
+               if (c != ' ') goto missingargs;
 
3339
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3340
+               if (c != ' ') goto missingargs;
 
3341
+               cmd_status(tag.s, arg1.s);
 
3342
+
 
3343
+               snmp_increment(STATUS_COUNT, 1);
 
3344
+           }
 
3345
+           else goto badcmd;
 
3346
+           break;
 
3347
+
 
3348
+       case 'T':
 
3349
+           if (!strcmp(cmd.s, "Thread")) {
 
3350
+               if (!imapd_mailbox) goto nomailbox;
 
3351
+               usinguid = 0;
 
3352
+               if (c != ' ') goto missingargs;
 
3353
+           thread:
 
3354
+               cmd_thread(tag.s, usinguid);
 
3355
+
 
3356
+               snmp_increment(THREAD_COUNT, 1);
 
3357
+           }
 
3358
+           else goto badcmd;
 
3359
+           break;
 
3360
+
 
3361
+       case 'U':
 
3362
+           if (!strcmp(cmd.s, "Uid")) {
 
3363
+               if (!imapd_mailbox) goto nomailbox;
 
3364
+               usinguid = 1;
 
3365
+               if (c != ' ') goto missingargs;
 
3366
+               c = getword(imapd_in, &arg1);
 
3367
+               if (c != ' ') goto missingargs;
 
3368
+               lcase(arg1.s);
 
3369
+               if (!strcmp(arg1.s, "fetch")) {
 
3370
+                   goto fetch;
 
3371
+               }
 
3372
+               else if (!strcmp(arg1.s, "store")) {
 
3373
+                   goto store;
 
3374
+               }
 
3375
+               else if (!strcmp(arg1.s, "search")) {
 
3376
+                   goto search;
 
3377
+               }
 
3378
+               else if (!strcmp(arg1.s, "sort")) {
 
3379
+                   goto sort;
 
3380
+               }
 
3381
+               else if (!strcmp(arg1.s, "thread")) {
 
3382
+                   goto thread;
 
3383
+               }
 
3384
+               else if (!strcmp(arg1.s, "copy")) {
 
3385
+                   goto copy;
 
3386
+               }
 
3387
+               else if (!strcmp(arg1.s, "expunge")) {
 
3388
+                   c = getword(imapd_in, &arg1);
 
3389
+                   if (!imparse_issequence(arg1.s)) goto badsequence;
 
3390
+                   if (c == '\r') c = prot_getc(imapd_in);
 
3391
+                   if (c != '\n') goto extraargs;
 
3392
+                   cmd_expunge(tag.s, arg1.s);
 
3393
+
 
3394
+                   snmp_increment(EXPUNGE_COUNT, 1);
 
3395
+               }
 
3396
+               else {
 
3397
+                   prot_printf(imapd_out, "%s BAD Unrecognized UID subcommand\r\n", tag.s);
 
3398
+                   eatline(imapd_in, c);
 
3399
+               }
 
3400
+           }
 
3401
+           else if (!strcmp(cmd.s, "Unsubscribe")) {
 
3402
+               if (c != ' ') goto missingargs;
 
3403
+               havenamespace = 0;
 
3404
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3405
+               if (c == ' ') {
 
3406
+                   havenamespace = 1;
 
3407
+                   c = getastring(imapd_in, imapd_out, &arg2);
 
3408
+               }
 
3409
+               if (c == EOF) goto missingargs;
 
3410
+               if (c == '\r') c = prot_getc(imapd_in);
 
3411
+               if (c != '\n') goto extraargs;
 
3412
+               if (havenamespace) {
 
3413
+                   cmd_changesub(tag.s, arg1.s, arg2.s, 0);
 
3414
+               }
 
3415
+               else {
 
3416
+                   cmd_changesub(tag.s, (char *)0, arg1.s, 0);
 
3417
+               }
 
3418
+
 
3419
+               snmp_increment(UNSUBSCRIBE_COUNT, 1);
 
3420
+           }           
 
3421
+           else if (!strcmp(cmd.s, "Unselect")) {
 
3422
+               if (!imapd_mailbox) goto nomailbox;
 
3423
+               if (c == '\r') c = prot_getc(imapd_in);
 
3424
+               if (c != '\n') goto extraargs;
 
3425
+               cmd_unselect(tag.s);
 
3426
+
 
3427
+               snmp_increment(UNSELECT_COUNT, 1);
 
3428
+           }
 
3429
+           else if (!strcmp(cmd.s, "Undump")) {
 
3430
+               if(c != ' ') goto missingargs;
 
3431
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3432
+
 
3433
+               /* we want to get a list at this point */
 
3434
+               if(c != ' ') goto missingargs;
 
3435
+               
 
3436
+               cmd_undump(tag.s, arg1.s);
 
3437
+           /*  snmp_increment(UNDUMP_COUNT, 1);*/
 
3438
+           }
 
3439
+           else goto badcmd;
 
3440
+           break;
 
3441
+
 
3442
+       case 'X':
 
3443
+           if (!strcmp(cmd.s, "Xfer")) {
 
3444
+               int havepartition = 0;
 
3445
+               
 
3446
+               /* Mailbox */
 
3447
+               if(c != ' ') goto missingargs;
 
3448
+               c = getastring(imapd_in, imapd_out, &arg1);
 
3449
+
 
3450
+               /* Dest Server */
 
3451
+               if(c != ' ') goto missingargs;
 
3452
+               c = getastring(imapd_in, imapd_out, &arg2);
 
3453
+
 
3454
+               if(c == ' ') {
 
3455
+                   /* Dest Partition */
 
3456
+                   c = getastring(imapd_in, imapd_out, &arg3);
 
3457
+                   if (!imparse_isatom(arg3.s)) goto badpartition;
 
3458
+                   havepartition = 1;
 
3459
+               }
 
3460
+               
 
3461
+               if (c == '\r') c = prot_getc(imapd_in);
 
3462
+               if (c != '\n') goto extraargs;
 
3463
+
 
3464
+               cmd_xfer(tag.s, arg1.s, arg2.s,
 
3465
+                        (havepartition ? arg3.s : NULL));
 
3466
+           /*  snmp_increment(XFER_COUNT, 1);*/
 
3467
+           }
 
3468
+           else goto badcmd;
 
3469
+           break;
 
3470
+
 
3471
+       default:
 
3472
+       badcmd:
 
3473
+           prot_printf(imapd_out, "%s BAD Unrecognized command\r\n", tag.s);
 
3474
+           eatline(imapd_in, c);
 
3475
+       }
 
3476
+
 
3477
+       continue;
 
3478
+
 
3479
+    nologin:
 
3480
+       prot_printf(imapd_out, "%s BAD Please login first\r\n", tag.s);
 
3481
+       eatline(imapd_in, c);
 
3482
+       continue;
 
3483
+
 
3484
+    nomailbox:
 
3485
+       prot_printf(imapd_out, "%s BAD Please select a mailbox first\r\n", tag.s);
 
3486
+       eatline(imapd_in, c);
 
3487
+       continue;
 
3488
+
 
3489
+    missingargs:
 
3490
+       prot_printf(imapd_out, "%s BAD Missing required argument to %s\r\n", tag.s, cmd.s);
 
3491
+       eatline(imapd_in, c);
 
3492
+       continue;
 
3493
+
 
3494
+    extraargs:
 
3495
+       prot_printf(imapd_out, "%s BAD Unexpected extra arguments to %s\r\n", tag.s, cmd.s);
 
3496
+       eatline(imapd_in, c);
 
3497
+       continue;
 
3498
+
 
3499
+    badsequence:
 
3500
+       prot_printf(imapd_out, "%s BAD Invalid sequence in %s\r\n", tag.s, cmd.s);
 
3501
+       eatline(imapd_in, c);
 
3502
+       continue;
 
3503
+
 
3504
+    badpartition:
 
3505
+       prot_printf(imapd_out, "%s BAD Invalid partition name in %s\r\n",
 
3506
+              tag.s, cmd.s);
 
3507
+       eatline(imapd_in, c);
 
3508
+       continue;
 
3509
+    }
 
3510
+}
 
3511
+
 
3512
+/*
 
3513
+ * Perform a LOGIN command
 
3514
+ */
 
3515
+void cmd_login(char *tag, char *user)
 
3516
+{
 
3517
+    char userbuf[MAX_MAILBOX_NAME+1];
 
3518
+    unsigned userlen;
 
3519
+    const char *canon_user = userbuf;
 
3520
+    char c;
 
3521
+    struct buf passwdbuf;
 
3522
+    char *passwd;
 
3523
+    const char *reply = NULL;
 
3524
+    int r;
 
3525
+    
 
3526
+    if (imapd_userid) {
 
3527
+       eatline(imapd_in, ' ');
 
3528
+       prot_printf(imapd_out, "%s BAD Already logged in\r\n", tag);
 
3529
+       return;
 
3530
+    }
 
3531
+
 
3532
+    r = imapd_canon_user(imapd_saslconn, NULL, user, 0,
 
3533
+                        SASL_CU_AUTHID | SASL_CU_AUTHZID, NULL,
 
3534
+                        userbuf, sizeof(userbuf), &userlen);
 
3535
+
 
3536
+    if (r) {
 
3537
+       syslog(LOG_NOTICE, "badlogin: %s plaintext %s invalid user",
 
3538
+              imapd_clienthost, beautify_string(user));
 
3539
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, 
 
3540
+                   error_message(IMAP_INVALID_USER));
 
3541
+       return;
 
3542
+    }
 
3543
+
 
3544
+    /* possibly disallow login */
 
3545
+    if ((imapd_starttls_done == 0) &&
 
3546
+       (config_getswitch(IMAPOPT_ALLOWPLAINTEXT) == 0) &&
 
3547
+       !is_userid_anonymous(canon_user)) {
 
3548
+       eatline(imapd_in, ' ');
 
3549
+       prot_printf(imapd_out, "%s NO Login only available under a layer\r\n",
 
3550
+                   tag);
 
3551
+       return;
 
3552
+    }
 
3553
+
 
3554
+    memset(&passwdbuf,0,sizeof(struct buf));
 
3555
+    c = getastring(imapd_in, imapd_out, &passwdbuf);
 
3556
+
 
3557
+    if(c == '\r') c = prot_getc(imapd_in);
 
3558
+    if (c != '\n') {
 
3559
+       freebuf(&passwdbuf);
 
3560
+       prot_printf(imapd_out,
 
3561
+                   "%s BAD Unexpected extra arguments to LOGIN\r\n",
 
3562
+                   tag);
 
3563
+       eatline(imapd_in, c);
 
3564
+       return;
 
3565
+    }
 
3566
+
 
3567
+    passwd = passwdbuf.s;
 
3568
+
 
3569
+    if (is_userid_anonymous(canon_user)) {
 
3570
+       if (config_getswitch(IMAPOPT_ALLOWANONYMOUSLOGIN)) {
 
3571
+           passwd = beautify_string(passwd);
 
3572
+           if (strlen(passwd) > 500) passwd[500] = '\0';
 
3573
+           syslog(LOG_NOTICE, "login: %s anonymous %s",
 
3574
+                  imapd_clienthost, passwd);
 
3575
+           reply = "Anonymous access granted";
 
3576
+           imapd_userid = xstrdup("anonymous");
 
3577
+       }
 
3578
+       else {
 
3579
+           syslog(LOG_NOTICE, "badlogin: %s anonymous login refused",
 
3580
+                  imapd_clienthost);
 
3581
+           prot_printf(imapd_out, "%s NO %s\r\n", tag,
 
3582
+                  error_message(IMAP_ANONYMOUS_NOT_PERMITTED));
 
3583
+           freebuf(&passwdbuf);
 
3584
+           return;
 
3585
+       }
 
3586
+    }
 
3587
+    else if ((r = sasl_checkpass(imapd_saslconn,
 
3588
+                                canon_user,
 
3589
+                                strlen(canon_user),
 
3590
+                                passwd,
 
3591
+                                strlen(passwd))) != SASL_OK) {
 
3592
+       syslog(LOG_NOTICE, "badlogin: %s plaintext %s %s",
 
3593
+              imapd_clienthost, canon_user, sasl_errdetail(imapd_saslconn));
 
3594
+
 
3595
+       sleep(3);
 
3596
+
 
3597
+       if ((reply = sasl_errstring(r, NULL, NULL)) != NULL) {
 
3598
+           prot_printf(imapd_out, "%s NO Login failed: %s\r\n", tag, reply);
 
3599
+       } else {
 
3600
+           prot_printf(imapd_out, "%s NO Login failed: %d\r\n", tag, r);
 
3601
+       }
 
3602
+
 
3603
+       snmp_increment_args(AUTHENTICATION_NO, 1,
 
3604
+                           VARIABLE_AUTH, 0 /* hash_simple("LOGIN") */,
 
3605
+                           VARIABLE_LISTEND);
 
3606
+       freebuf(&passwdbuf);
 
3607
+       return;
 
3608
+    }
 
3609
+    else {
 
3610
+       r = sasl_getprop(imapd_saslconn, SASL_USERNAME,
 
3611
+                        (const void **) &canon_user);
 
3612
+
 
3613
+       if(r != SASL_OK) {
 
3614
+           if ((reply = sasl_errstring(r, NULL, NULL)) != NULL) {
 
3615
+               prot_printf(imapd_out, "%s NO Login failed: %s\r\n",
 
3616
+                           tag, reply);
 
3617
+           } else {
 
3618
+               prot_printf(imapd_out, "%s NO Login failed: %d\r\n", tag, r);
 
3619
+           }
 
3620
+
 
3621
+           snmp_increment_args(AUTHENTICATION_NO, 1,
 
3622
+                               VARIABLE_AUTH, 0 /* hash_simple("LOGIN") */,
 
3623
+                               VARIABLE_LISTEND);
 
3624
+           freebuf(&passwdbuf);
 
3625
+           return;
 
3626
+       }
 
3627
+
 
3628
+       reply = "User logged in";
 
3629
+       imapd_userid = xstrdup(canon_user);
 
3630
+       snmp_increment_args(AUTHENTICATION_YES, 1,
 
3631
+                           VARIABLE_AUTH, 0 /*hash_simple("LOGIN") */, 
 
3632
+                           VARIABLE_LISTEND);
 
3633
+       syslog(LOG_NOTICE, "login: %s %s%s plaintext%s %s", imapd_clienthost,
 
3634
+              imapd_userid, imapd_magicplus ? imapd_magicplus : "",
 
3635
+              imapd_starttls_done ? "+TLS" : "", 
 
3636
+              reply ? reply : "");
 
3637
+
 
3638
+       /* Apply penalty only if not under layer */
 
3639
+       if (!imapd_starttls_done) {
 
3640
+           int plaintextloginpause = config_getint(IMAPOPT_PLAINTEXTLOGINPAUSE);
 
3641
+           if (plaintextloginpause) {
 
3642
+               sleep(plaintextloginpause);
 
3643
+           }
 
3644
+
 
3645
+           /* Fetch plaintext login nag message */
 
3646
+           plaintextloginalert = config_getstring(IMAPOPT_PLAINTEXTLOGINALERT);
 
3647
+       }
 
3648
+    }
 
3649
+    
 
3650
+    imapd_authstate = auth_newstate(imapd_userid);
 
3651
+
 
3652
+    imapd_userisadmin = global_authisa(imapd_authstate, IMAPOPT_ADMINS);
 
3653
+
 
3654
+    prot_printf(imapd_out, "%s OK %s\r\n", tag, reply);
 
3655
+
 
3656
+    /* Create telemetry log */
 
3657
+    imapd_logfd = telemetry_log(imapd_userid, imapd_in, imapd_out, 0);
 
3658
+
 
3659
+    /* Set namespace */
 
3660
+    if ((r = mboxname_init_namespace(&imapd_namespace,
 
3661
+                                    imapd_userisadmin || imapd_userisproxyadmin)) != 0) {
 
3662
+       syslog(LOG_ERR, error_message(r));
 
3663
+       fatal(error_message(r), EC_CONFIG);
 
3664
+    }
 
3665
+
 
3666
+    /* Translate any separators in userid */
 
3667
+    mboxname_hiersep_tointernal(&imapd_namespace, imapd_userid,
 
3668
+                               config_virtdomains ?
 
3669
+                               strcspn(imapd_userid, "@") : 0);
 
3670
+
 
3671
+    freebuf(&passwdbuf);
 
3672
+    return;
 
3673
+}
 
3674
+
 
3675
+/*
 
3676
+ * Perform an AUTHENTICATE command
 
3677
+ */
 
3678
+void
 
3679
+cmd_authenticate(char *tag, char *authtype, char *resp)
 
3680
+{
 
3681
+    int sasl_result;
 
3682
+    
 
3683
+    const int *ssfp;
 
3684
+    char *ssfmsg=NULL;
 
3685
+
 
3686
+    const char *canon_user;
 
3687
+
 
3688
+    int r;
 
3689
+
 
3690
+    r = saslserver(imapd_saslconn, authtype, resp, "", "+ ", "",
 
3691
+                  imapd_in, imapd_out, &sasl_result, NULL);
 
3692
+
 
3693
+    if (r) {
 
3694
+       const char *errorstring = NULL;
 
3695
+
 
3696
+       switch (r) {
 
3697
+       case IMAP_SASL_CANCEL:
 
3698
+           prot_printf(imapd_out,
 
3699
+                       "%s BAD Client canceled authentication\r\n", tag);
 
3700
+           break;
 
3701
+       case IMAP_SASL_PROTERR:
 
3702
+           errorstring = prot_error(imapd_in);
 
3703
+
 
3704
+           prot_printf(imapd_out,
 
3705
+                       "%s NO Error reading client response: %s\r\n",
 
3706
+                       tag, errorstring ? errorstring : "");
 
3707
+           break;
 
3708
+       default: 
 
3709
+           /* failed authentication */
 
3710
+           errorstring = sasl_errstring(sasl_result, NULL, NULL);
 
3711
+
 
3712
+           syslog(LOG_NOTICE, "badlogin: %s %s [%s]",
 
3713
+                  imapd_clienthost, authtype, sasl_errdetail(imapd_saslconn));
 
3714
+
 
3715
+           snmp_increment_args(AUTHENTICATION_NO, 1,
 
3716
+                               VARIABLE_AUTH, 0, /* hash_simple(authtype) */ 
 
3717
+                               VARIABLE_LISTEND);
 
3718
+           sleep(3);
 
3719
+
 
3720
+           if (errorstring) {
 
3721
+               prot_printf(imapd_out, "%s NO %s\r\n", tag, errorstring);
 
3722
+           } else {
 
3723
+               prot_printf(imapd_out, "%s NO Error authenticating\r\n", tag);
 
3724
+           }
 
3725
+       }
 
3726
+
 
3727
+       reset_saslconn(&imapd_saslconn);
 
3728
+       return;
 
3729
+    }
 
3730
+
 
3731
+    /* successful authentication */
 
3732
+
 
3733
+    /* get the userid from SASL --- already canonicalized from
 
3734
+     * mysasl_proxy_policy()
 
3735
+     */
 
3736
+    sasl_result = sasl_getprop(imapd_saslconn, SASL_USERNAME,
 
3737
+                              (const void **) &canon_user);
 
3738
+    if (sasl_result != SASL_OK) {
 
3739
+       prot_printf(imapd_out, "%s NO weird SASL error %d SASL_USERNAME\r\n", 
 
3740
+                   tag, sasl_result);
 
3741
+       syslog(LOG_ERR, "weird SASL error %d getting SASL_USERNAME", 
 
3742
+              sasl_result);
 
3743
+       reset_saslconn(&imapd_saslconn);
 
3744
+       return;
 
3745
+    }
 
3746
+
 
3747
+    /* If we're proxying, the authzid may contain a magic plus,
 
3748
+       so re-canonify it */
 
3749
+    if (config_getswitch(IMAPOPT_IMAPMAGICPLUS) && strchr(canon_user, '+')) {
 
3750
+       char userbuf[MAX_MAILBOX_NAME+1];
 
3751
+       unsigned userlen;
 
3752
+
 
3753
+       sasl_result = imapd_canon_user(imapd_saslconn, NULL, canon_user, 0,
 
3754
+                                      SASL_CU_AUTHID | SASL_CU_AUTHZID,
 
3755
+                                      NULL, userbuf, sizeof(userbuf), &userlen);
 
3756
+       if (sasl_result != SASL_OK) {
 
3757
+           prot_printf(imapd_out, 
 
3758
+                       "%s NO SASL canonification error %d\r\n", 
 
3759
+                       tag, sasl_result);
 
3760
+           reset_saslconn(&imapd_saslconn);
 
3761
+           return;
 
3762
+       }
 
3763
+
 
3764
+       imapd_userid = xstrdup(userbuf);
 
3765
+    } else {
 
3766
+       imapd_userid = xstrdup(canon_user);
 
3767
+    }
 
3768
+
 
3769
+    proc_register("imapd", imapd_clienthost, imapd_userid, (char *)0);
 
3770
+
 
3771
+    syslog(LOG_NOTICE, "login: %s %s%s %s%s %s", imapd_clienthost,
 
3772
+          imapd_userid, imapd_magicplus ? imapd_magicplus : "",
 
3773
+          authtype, imapd_starttls_done ? "+TLS" : "", "User logged in");
 
3774
+
 
3775
+    sasl_getprop(imapd_saslconn, SASL_SSF, (const void **) &ssfp);
 
3776
+
 
3777
+    /* really, we should be doing a sasl_getprop on SASL_SSF_EXTERNAL,
 
3778
+       but the current libsasl doesn't allow that. */
 
3779
+    if (imapd_starttls_done) {
 
3780
+       switch(*ssfp) {
 
3781
+       case 0: ssfmsg = "tls protection"; break;
 
3782
+       case 1: ssfmsg = "tls plus integrity protection"; break;
 
3783
+       default: ssfmsg = "tls plus privacy protection"; break;
 
3784
+       }
 
3785
+    } else {
 
3786
+       switch(*ssfp) {
 
3787
+       case 0: ssfmsg = "no protection"; break;
 
3788
+       case 1: ssfmsg = "integrity protection"; break;
 
3789
+       default: ssfmsg = "privacy protection"; break;
 
3790
+       }
 
3791
+    }
 
3792
+
 
3793
+    snmp_increment_args(AUTHENTICATION_YES, 1,
 
3794
+                       VARIABLE_AUTH, 0, /* hash_simple(authtype) */
 
3795
+                       VARIABLE_LISTEND);
 
3796
+
 
3797
+    prot_printf(imapd_out, "%s OK Success (%s)\r\n", tag, ssfmsg);
 
3798
+
 
3799
+    prot_setsasl(imapd_in,  imapd_saslconn);
 
3800
+    prot_setsasl(imapd_out, imapd_saslconn);
 
3801
+
 
3802
+    /* Create telemetry log */
 
3803
+    imapd_logfd = telemetry_log(imapd_userid, imapd_in, imapd_out, 0);
 
3804
+
 
3805
+    /* Set namespace */
 
3806
+    if ((r = mboxname_init_namespace(&imapd_namespace,
 
3807
+                                    imapd_userisadmin || imapd_userisproxyadmin)) != 0) {
 
3808
+       syslog(LOG_ERR, error_message(r));
 
3809
+       fatal(error_message(r), EC_CONFIG);
 
3810
+    }
 
3811
+
 
3812
+    /* Translate any separators in userid */
 
3813
+    mboxname_hiersep_tointernal(&imapd_namespace, imapd_userid,
 
3814
+                               config_virtdomains ?
 
3815
+                               strcspn(imapd_userid, "@") : 0);
 
3816
+
 
3817
+    return;
 
3818
+}
 
3819
+
 
3820
+/*
 
3821
+ * Perform a NOOP command
 
3822
+ */
 
3823
+void
 
3824
+cmd_noop(char *tag, char *cmd __attribute__((unused)))
 
3825
+{
 
3826
+    if (imapd_mailbox) {
 
3827
+       index_check(imapd_mailbox, 0, 1);
 
3828
+    }
 
3829
+    prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
3830
+               error_message(IMAP_OK_COMPLETED));
 
3831
+}
 
3832
+
 
3833
+/*
 
3834
+ * Parse and perform an ID command.
 
3835
+ *
 
3836
+ * the command has been parsed up to the parameter list.
 
3837
+ *
 
3838
+ * we only allow one ID in non-authenticated state from a given client.
 
3839
+ * we only allow MAXIDFAILED consecutive failed IDs from a given client.
 
3840
+ * we only record MAXIDLOG ID responses from a given client.
 
3841
+ */
 
3842
+void cmd_id(char *tag)
 
3843
+{
 
3844
+    static int did_id = 0;
 
3845
+    static int failed_id = 0;
 
3846
+    static int logged_id = 0;
 
3847
+    int error = 0;
 
3848
+    int c = EOF, npair = 0;
 
3849
+    static struct buf arg, field;
 
3850
+    struct attvaluelist *params = 0;
 
3851
+
 
3852
+    /* check if we've already had an ID in non-authenticated state */
 
3853
+    if (!imapd_userid && did_id) {
 
3854
+       prot_printf(imapd_out,
 
3855
+                   "%s NO Only one Id allowed in non-authenticated state\r\n",
 
3856
+                   tag);
 
3857
+       eatline(imapd_in, c);
 
3858
+       return;
 
3859
+    }
 
3860
+
 
3861
+    /* check if we've had too many failed IDs in a row */
 
3862
+    if (failed_id >= MAXIDFAILED) {
 
3863
+       prot_printf(imapd_out, "%s NO Too many (%u) invalid Id commands\r\n",
 
3864
+                   tag, failed_id);
 
3865
+       eatline(imapd_in, c);
 
3866
+       return;
 
3867
+    }
 
3868
+
 
3869
+    /* ok, accept parameter list */
 
3870
+    c = getword(imapd_in, &arg);
 
3871
+    /* check for "NIL" or start of parameter list */
 
3872
+    if (strcasecmp(arg.s, "NIL") && c != '(') {
 
3873
+       prot_printf(imapd_out, "%s BAD Invalid parameter list in Id\r\n", tag);
 
3874
+       eatline(imapd_in, c);
 
3875
+       failed_id++;
 
3876
+       return;
 
3877
+    }
 
3878
+
 
3879
+    /* parse parameter list */
 
3880
+    if (c == '(') {
 
3881
+       for (;;) {
 
3882
+           if (c == ')') {
 
3883
+               /* end of string/value pairs */
 
3884
+               break;
 
3885
+           }
 
3886
+
 
3887
+           /* get field name */
 
3888
+           c = getstring(imapd_in, imapd_out, &field);
 
3889
+           if (c != ' ') {
 
3890
+               prot_printf(imapd_out,
 
3891
+                           "%s BAD Invalid/missing field name in Id\r\n",
 
3892
+                           tag);
 
3893
+               error = 1;
 
3894
+               break;
 
3895
+           }
 
3896
+
 
3897
+           /* get field value */
 
3898
+           c = getnstring(imapd_in, imapd_out, &arg);
 
3899
+           if (c != ' ' && c != ')') {
 
3900
+               prot_printf(imapd_out,
 
3901
+                           "%s BAD Invalid/missing value in Id\r\n",
 
3902
+                           tag);
 
3903
+               error = 1;
 
3904
+               break;
 
3905
+           }
 
3906
+
 
3907
+           /* ok, we're anal, but we'll still process the ID command */
 
3908
+           if (strlen(field.s) > MAXIDFIELDLEN) {
 
3909
+               prot_printf(imapd_out, 
 
3910
+                           "%s BAD field longer than %u octets in Id\r\n",
 
3911
+                           tag, MAXIDFIELDLEN);
 
3912
+               error = 1;
 
3913
+               break;
 
3914
+           }
 
3915
+           if (strlen(arg.s) > MAXIDVALUELEN) {
 
3916
+               prot_printf(imapd_out,
 
3917
+                           "%s BAD value longer than %u octets in Id\r\n",
 
3918
+                           tag, MAXIDVALUELEN);
 
3919
+               error = 1;
 
3920
+               break;
 
3921
+           }
 
3922
+           if (++npair > MAXIDPAIRS) {
 
3923
+               prot_printf(imapd_out,
 
3924
+                           "%s BAD too many (%u) field-value pairs in ID\r\n",
 
3925
+                           tag, MAXIDPAIRS);
 
3926
+               error = 1;
 
3927
+               break;
 
3928
+           }
 
3929
+           
 
3930
+           /* ok, we're happy enough */
 
3931
+           appendattvalue(&params, field.s, arg.s);
 
3932
+       }
 
3933
+
 
3934
+       if (error || c != ')') {
 
3935
+           /* erp! */
 
3936
+           eatline(imapd_in, c);
 
3937
+           freeattvalues(params);
 
3938
+           failed_id++;
 
3939
+           return;
 
3940
+       }
 
3941
+       c = prot_getc(imapd_in);
 
3942
+    }
 
3943
+
 
3944
+    /* check for CRLF */
 
3945
+    if (c == '\r') c = prot_getc(imapd_in);
 
3946
+    if (c != '\n') {
 
3947
+       prot_printf(imapd_out,
 
3948
+                   "%s BAD Unexpected extra arguments to Id\r\n", tag);
 
3949
+       eatline(imapd_in, c);
 
3950
+       freeattvalues(params);
 
3951
+       failed_id++;
 
3952
+       return;
 
3953
+    }
 
3954
+
 
3955
+    /* log the client's ID string.
 
3956
+       eventually this should be a callback or something. */
 
3957
+    if (npair && logged_id < MAXIDLOG) {
 
3958
+       char logbuf[MAXIDLOGLEN + 1] = "";
 
3959
+       struct attvaluelist *pptr;
 
3960
+
 
3961
+       for (pptr = params; pptr; pptr = pptr->next) {
 
3962
+           /* should we check for and format literals here ??? */
 
3963
+           snprintf(logbuf + strlen(logbuf), MAXIDLOGLEN - strlen(logbuf),
 
3964
+                    " \"%s\" ", pptr->attrib);
 
3965
+           if (!strcmp(pptr->value, "NIL"))
 
3966
+               snprintf(logbuf + strlen(logbuf), MAXIDLOGLEN - strlen(logbuf),
 
3967
+                        "NIL");
 
3968
+           else
 
3969
+               snprintf(logbuf + strlen(logbuf), MAXIDLOGLEN - strlen(logbuf),
 
3970
+                       "\"%s\"", pptr->value);
 
3971
+       }
 
3972
+
 
3973
+       syslog(LOG_INFO, "client id:%s", logbuf);
 
3974
+
 
3975
+       logged_id++;
 
3976
+    }
 
3977
+
 
3978
+    freeattvalues(params);
 
3979
+
 
3980
+    /* spit out our ID string.
 
3981
+       eventually this might be configurable. */
 
3982
+    if (config_getswitch(IMAPOPT_IMAPIDRESPONSE)) {
 
3983
+       id_response(imapd_out);
 
3984
+       prot_printf(imapd_out, ")\r\n");
 
3985
+    }
 
3986
+    else
 
3987
+       prot_printf(imapd_out, "* ID NIL\r\n");
 
3988
+
 
3989
+    prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
3990
+               error_message(IMAP_OK_COMPLETED));
 
3991
+
 
3992
+    failed_id = 0;
 
3993
+    did_id = 1;
 
3994
+}
 
3995
+
 
3996
+/*
 
3997
+ * Perform an IDLE command
 
3998
+ */
 
3999
+void cmd_idle(char *tag)
 
4000
+{
 
4001
+    int c;
 
4002
+    static struct buf arg;
 
4003
+
 
4004
+    /* Setup for doing mailbox updates */
 
4005
+    if (!idle_init(idle_update)) {
 
4006
+       prot_printf(imapd_out, 
 
4007
+                   "%s NO cannot start idling\r\n", tag);
 
4008
+       return;
 
4009
+    }
 
4010
+
 
4011
+    /* Tell client we are idling and waiting for end of command */
 
4012
+    prot_printf(imapd_out, "+ idling\r\n");
 
4013
+    prot_flush(imapd_out);
 
4014
+
 
4015
+    /* Start doing mailbox updates */
 
4016
+    if (imapd_mailbox) index_check(imapd_mailbox, 0, 1);
 
4017
+    idle_start(imapd_mailbox);
 
4018
+
 
4019
+    /* Get continuation data */
 
4020
+    c = getword(imapd_in, &arg);
 
4021
+
 
4022
+    /* Stop updates and do any necessary cleanup */
 
4023
+    idle_done(imapd_mailbox);
 
4024
+
 
4025
+    if (imapd_mailbox) index_check(imapd_mailbox, 0, 1);
 
4026
+
 
4027
+    if (c != EOF) {
 
4028
+       if (!strcasecmp(arg.s, "Done") &&
 
4029
+           (c = (c == '\r') ? prot_getc(imapd_in) : c) == '\n') {
 
4030
+           prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
4031
+                       error_message(IMAP_OK_COMPLETED));
 
4032
+       }
 
4033
+
 
4034
+       else {
 
4035
+           prot_printf(imapd_out, 
 
4036
+                       "%s BAD Invalid Idle continuation\r\n", tag);
 
4037
+           eatline(imapd_in, c);
 
4038
+       }
 
4039
+    }
 
4040
+
 
4041
+    return;
 
4042
+}
 
4043
+
 
4044
+/* Send unsolicited untagged responses to the client */
 
4045
+void idle_update(idle_flags_t flags)
 
4046
+{
 
4047
+    if ((flags & IDLE_MAILBOX) && imapd_mailbox)
 
4048
+       index_check(imapd_mailbox, 0, 1);
 
4049
+
 
4050
+    if (flags & IDLE_ALERT) {
 
4051
+       char shut[1024];
 
4052
+       if (! imapd_userisadmin && shutdown_file(shut, sizeof(shut))) {
 
4053
+           char *p;
 
4054
+           for (p = shut; *p == '['; p++); /* can't have [ be first char */
 
4055
+           prot_printf(imapd_out, "* BYE [ALERT] %s\r\n", p);
 
4056
+           shut_down(0);
 
4057
+       }
 
4058
+    }
 
4059
+
 
4060
+    prot_flush(imapd_out);
 
4061
+}
 
4062
+
 
4063
+/*
 
4064
+ * Perform a CAPABILITY command
 
4065
+ */
 
4066
+void cmd_capability(char *tag)
 
4067
+{
 
4068
+    const char *sasllist; /* the list of SASL mechanisms */
 
4069
+    unsigned mechcount;
 
4070
+
 
4071
+    if (imapd_mailbox) {
 
4072
+       index_check(imapd_mailbox, 0, 0);
 
4073
+    }
 
4074
+    prot_printf(imapd_out, "* CAPABILITY " CAPABILITY_STRING);
 
4075
+
 
4076
+    if (idle_enabled()) {
 
4077
+       prot_printf(imapd_out, " IDLE");
 
4078
+    }
 
4079
+
 
4080
+    if (tls_enabled() && !imapd_starttls_done && !imapd_authstate) {
 
4081
+       prot_printf(imapd_out, " STARTTLS");
 
4082
+    }
 
4083
+    if (imapd_authstate ||
 
4084
+       (!imapd_starttls_done && !config_getswitch(IMAPOPT_ALLOWPLAINTEXT))) {
 
4085
+       prot_printf(imapd_out, " LOGINDISABLED");
 
4086
+    }
 
4087
+
 
4088
+    if(config_mupdate_server) {
 
4089
+       prot_printf(imapd_out, " MUPDATE=mupdate://%s/", config_mupdate_server);
 
4090
+    }
 
4091
+
 
4092
+    /* add the SASL mechs */
 
4093
+    if (!imapd_authstate &&
 
4094
+       sasl_listmech(imapd_saslconn, NULL, 
 
4095
+                     "AUTH=", " AUTH=", " SASL-IR",
 
4096
+                     &sasllist,
 
4097
+                     NULL, &mechcount) == SASL_OK && mechcount > 0) {
 
4098
+       prot_printf(imapd_out, " %s", sasllist);      
 
4099
+    } else {
 
4100
+       /* else don't show anything */
 
4101
+    }
 
4102
+
 
4103
+#ifdef ENABLE_LISTEXT
 
4104
+    prot_printf(imapd_out, " LISTEXT LIST-SUBSCRIBED");
 
4105
+#endif /* ENABLE_LISTEXT */
 
4106
+
 
4107
+#ifdef ENABLE_X_NETSCAPE_HACK
 
4108
+    prot_printf(imapd_out, " X-NETSCAPE");
 
4109
+#endif
 
4110
+    prot_printf(imapd_out, "\r\n%s OK %s\r\n", tag,
 
4111
+               error_message(IMAP_OK_COMPLETED));
 
4112
+}
 
4113
+
 
4114
+/*
 
4115
+ * Parse and perform an APPEND command.
 
4116
+ * The command has been parsed up to and including
 
4117
+ * the mailbox name.
 
4118
+ */
 
4119
+static int isokflag(char *s)
 
4120
+{
 
4121
+    if (s[0] == '\\') {
 
4122
+       lcase(s);
 
4123
+       if (!strcmp(s, "\\seen")) return 1;
 
4124
+       if (!strcmp(s, "\\answered")) return 1;
 
4125
+       if (!strcmp(s, "\\flagged")) return 1;
 
4126
+       if (!strcmp(s, "\\draft")) return 1;
 
4127
+       if (!strcmp(s, "\\deleted")) return 1;
 
4128
+       
 
4129
+       /* uh oh, system flag i don't recognize */
 
4130
+       return 0;
 
4131
+    } else {
 
4132
+       /* valid user flag? */
 
4133
+       return imparse_isatom(s);
 
4134
+    }
 
4135
+}
 
4136
+
 
4137
+#define FLAGGROW 10
 
4138
+void cmd_append(char *tag, char *name)
 
4139
+
 
4140
+{
 
4141
+    int c;
 
4142
+    static struct buf arg;
 
4143
+    char *p;
 
4144
+    time_t now = time(NULL);
 
4145
+    unsigned size, totalsize = 0;
 
4146
+    int sawdigit = 0;
 
4147
+    int isnowait = 0;
 
4148
+    int r, i;
 
4149
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
4150
+    struct appendstate mailbox;
 
4151
+    unsigned long uidvalidity;
 
4152
+    unsigned long firstuid, num;
 
4153
+    long doappenduid = 0;
 
4154
+    const char *parseerr = NULL;
 
4155
+    FILE *f;
 
4156
+    int numalloc = 5;
 
4157
+    struct appendstage *curstage;
 
4158
+
 
4159
+    /* See if we can append */
 
4160
+    r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
4161
+                                              imapd_userid, mailboxname);
 
4162
+    if (!r) {
 
4163
+       r = append_check(mailboxname, MAILBOX_FORMAT_NORMAL,
 
4164
+                        imapd_authstate, ACL_INSERT, totalsize);
 
4165
+    }
 
4166
+    if (r) {
 
4167
+       eatline(imapd_in, ' ');
 
4168
+       prot_printf(imapd_out, "%s NO %s%s\r\n",
 
4169
+                   tag,
 
4170
+                   (r == IMAP_MAILBOX_NONEXISTENT &&
 
4171
+                    mboxlist_createmailboxcheck(mailboxname, 0, 0,
 
4172
+                                                imapd_userisadmin,
 
4173
+                                                imapd_userid, imapd_authstate,
 
4174
+                                                (char **)0, (char **)0) == 0)
 
4175
+                   ? "[TRYCREATE] " : "", error_message(r));
 
4176
+       return;
 
4177
+    }
 
4178
+
 
4179
+    stage = xmalloc(numalloc * sizeof(struct appendstage *));
 
4180
+
 
4181
+    c = ' '; /* just parsed a space */
 
4182
+    /* we loop, to support MULTIAPPEND */
 
4183
+    while (!r && c == ' ') {
 
4184
+       /* Grow the stage array, if necessary */
 
4185
+       if (numstage == numalloc) {
 
4186
+           /* Avoid integer wrap as arg to xrealloc */
 
4187
+           if (numalloc > INT_MAX/(2*sizeof(struct appendstage *)))
 
4188
+               goto done;
 
4189
+           numalloc *= 2;
 
4190
+           stage = xrealloc(stage, numalloc * sizeof(struct appendstage *));
 
4191
+       }
 
4192
+       curstage = stage[numstage] = xzmalloc(sizeof(struct appendstage));
 
4193
+       numstage++;
 
4194
+       /* Parse flags */
 
4195
+       c = getword(imapd_in, &arg);
 
4196
+       if  (c == '(' && !arg.s[0]) {
 
4197
+           curstage->nflags = 0;
 
4198
+           do {
 
4199
+               c = getword(imapd_in, &arg);
 
4200
+               if (!curstage->nflags && !arg.s[0] && c == ')') break; /* empty list */
 
4201
+               if (!isokflag(arg.s)) {
 
4202
+                   parseerr = "Invalid flag in Append command";
 
4203
+                   r = IMAP_PROTOCOL_ERROR;
 
4204
+                   goto done;
 
4205
+               }
 
4206
+               if (curstage->nflags == curstage->flagalloc) {
 
4207
+                   curstage->flagalloc += FLAGGROW;
 
4208
+                   curstage->flag =
 
4209
+                       (char **) xrealloc((char *) curstage->flag, 
 
4210
+                                          curstage->flagalloc * sizeof(char *));
 
4211
+               }
 
4212
+               curstage->flag[curstage->nflags] = xstrdup(arg.s);
 
4213
+               curstage->nflags++;
 
4214
+           } while (c == ' ');
 
4215
+           if (c != ')') {
 
4216
+               parseerr = 
 
4217
+                   "Missing space or ) after flag name in Append command";
 
4218
+               r = IMAP_PROTOCOL_ERROR;
 
4219
+               goto done;
 
4220
+           }
 
4221
+           c = prot_getc(imapd_in);
 
4222
+           if (c != ' ') {
 
4223
+               parseerr = "Missing space after flag list in Append command";
 
4224
+               r = IMAP_PROTOCOL_ERROR;
 
4225
+               goto done;
 
4226
+           }
 
4227
+           c = getword(imapd_in, &arg);
 
4228
+       }
 
4229
+
 
4230
+       /* Parse internaldate */
 
4231
+       if (c == '\"' && !arg.s[0]) {
 
4232
+           prot_ungetc(c, imapd_in);
 
4233
+           c = getdatetime(&(curstage->internaldate));
 
4234
+           if (c != ' ') {
 
4235
+               parseerr = "Invalid date-time in Append command";
 
4236
+               r = IMAP_PROTOCOL_ERROR;
 
4237
+               goto done;
 
4238
+           }
 
4239
+           c = getword(imapd_in, &arg);
 
4240
+       } else {
 
4241
+           curstage->internaldate = now;
 
4242
+       }
 
4243
+
 
4244
+       p = arg.s;
 
4245
+       /* Check for literal8 */
 
4246
+       if (*p == '~') {
 
4247
+           p++;
 
4248
+           /* We don't support binary append yet */
 
4249
+           r = IMAP_NO_UNKNOWN_CTE;
 
4250
+           goto done;
 
4251
+       }
 
4252
+       if (*p != '{') {
 
4253
+           parseerr = "Missing required argument to Append command";
 
4254
+           r = IMAP_PROTOCOL_ERROR;
 
4255
+           goto done;
 
4256
+       }
 
4257
+       
 
4258
+       /* Read size from literal */
 
4259
+       isnowait = 0;
 
4260
+       size = 0;
 
4261
+       for (++p; *p && isdigit((int) *p); p++) {
 
4262
+           sawdigit++;
 
4263
+           size = size*10 + *p - '0';
 
4264
+#if 0
 
4265
+            if (size < 0) {
 
4266
+                lose();
 
4267
+            }
 
4268
+#endif
 
4269
+       }
 
4270
+       if (*p == '+') {
 
4271
+           isnowait++;
 
4272
+           p++;
 
4273
+       }
 
4274
+       
 
4275
+       if (c == '\r') {
 
4276
+           c = prot_getc(imapd_in);
 
4277
+       }
 
4278
+       else {
 
4279
+           prot_ungetc(c, imapd_in);
 
4280
+           c = ' ';            /* Force a syntax error */
 
4281
+       }
 
4282
+       
 
4283
+       if (*p != '}' || p[1] || c != '\n' || !sawdigit) {
 
4284
+           parseerr = "Invalid literal in Append command";
 
4285
+           r = IMAP_PROTOCOL_ERROR;
 
4286
+           goto done;
 
4287
+       }
 
4288
+
 
4289
+       if (!isnowait) {
 
4290
+           /* Tell client to send the message */
 
4291
+           prot_printf(imapd_out, "+ go ahead\r\n");
 
4292
+           prot_flush(imapd_out);
 
4293
+       }
 
4294
+       
 
4295
+       /* Stage the message */
 
4296
+       f = append_newstage(mailboxname, now, numstage, &(curstage->stage));
 
4297
+       if (f) {
 
4298
+           totalsize += size;
 
4299
+           r = message_copy_strict(imapd_in, f, size);
 
4300
+           fclose(f);
 
4301
+       } else {
 
4302
+           r = IMAP_IOERROR;
 
4303
+       }
 
4304
+       
 
4305
+       /* if we see a SP, we're trying to append more than one message */
 
4306
+
 
4307
+       /* Parse newline terminating command */
 
4308
+       c = prot_getc(imapd_in);
 
4309
+    }
 
4310
+
 
4311
+ done:
 
4312
+    if (r) {
 
4313
+       eatline(imapd_in, c);
 
4314
+    } else {
 
4315
+       /* we should be looking at the end of the line */
 
4316
+       if (c == '\r') c = prot_getc(imapd_in);
 
4317
+       if (c != '\n') {
 
4318
+           parseerr = "junk after literal";
 
4319
+           r = IMAP_PROTOCOL_ERROR;
 
4320
+           eatline(imapd_in, c);
 
4321
+       }
 
4322
+    }
 
4323
+
 
4324
+    /* Append from the stage(s) */
 
4325
+    if (!r) {
 
4326
+       r = append_setup(&mailbox, mailboxname, MAILBOX_FORMAT_NORMAL,
 
4327
+                        imapd_userid, imapd_authstate, ACL_INSERT, totalsize);
 
4328
+    }
 
4329
+    if (!r) {
 
4330
+       doappenduid = (mailbox.m.myrights & ACL_READ);
 
4331
+
 
4332
+       for (i = 0; !r && i < numstage; i++) {
 
4333
+           r = append_fromstage(&mailbox, stage[i]->stage, stage[i]->internaldate, 
 
4334
+                                (const char **) stage[i]->flag, stage[i]->nflags, 0);
 
4335
+       }
 
4336
+
 
4337
+       if (!r) {
 
4338
+           r = append_commit(&mailbox, totalsize, &uidvalidity, &firstuid, &num);
 
4339
+       } else {
 
4340
+           append_abort(&mailbox);
 
4341
+       }
 
4342
+    }
 
4343
+
 
4344
+    /* Cleanup the stage(s) */
 
4345
+    while (numstage) {
 
4346
+       curstage = stage[--numstage];
 
4347
+
 
4348
+       append_removestage(curstage->stage);
 
4349
+       while (curstage->nflags--) {
 
4350
+           free(curstage->flag[curstage->nflags]);
 
4351
+       }
 
4352
+       if (curstage->flag) free((char *) curstage->flag);
 
4353
+       free(curstage);
 
4354
+    }
 
4355
+    if (stage) free(stage);
 
4356
+    stage = NULL;
 
4357
+
 
4358
+    if (imapd_mailbox) {
 
4359
+       index_check(imapd_mailbox, 0, 0);
 
4360
+    }
 
4361
+
 
4362
+    if (r == IMAP_PROTOCOL_ERROR && parseerr) {
 
4363
+       prot_printf(imapd_out, "%s BAD %s\r\n", tag, parseerr);
 
4364
+    } else if (r) {
 
4365
+       prot_printf(imapd_out, "%s NO %s%s\r\n",
 
4366
+                   tag,
 
4367
+                   (r == IMAP_MAILBOX_NONEXISTENT &&
 
4368
+                    mboxlist_createmailboxcheck(mailboxname, 0, 0,
 
4369
+                                                imapd_userisadmin,
 
4370
+                                                imapd_userid, imapd_authstate,
 
4371
+                                                (char **)0, (char **)0) == 0)
 
4372
+                   ? "[TRYCREATE] " : "", error_message(r));
 
4373
+    } else if (doappenduid) {
 
4374
+       prot_printf(imapd_out, "%s OK [APPENDUID %lu", tag, uidvalidity);
 
4375
+       if (num == 1) {
 
4376
+           prot_printf(imapd_out, " %lu", firstuid);
 
4377
+       } else {
 
4378
+           prot_printf(imapd_out, " %lu:%lu", firstuid, firstuid + num - 1);
 
4379
+       }
 
4380
+       prot_printf(imapd_out, "] %s\r\n", error_message(IMAP_OK_COMPLETED));
 
4381
+    } else {
 
4382
+       prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
4383
+                   error_message(IMAP_OK_COMPLETED));
 
4384
+    }
 
4385
+}
 
4386
+
 
4387
+/*
 
4388
+ * Perform a SELECT/EXAMINE/BBOARD command
 
4389
+ */
 
4390
+void cmd_select(char *tag, char *cmd, char *name)
 
4391
+{
 
4392
+    struct mailbox mailbox;
 
4393
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
4394
+    int r = 0;
 
4395
+    double usage;
 
4396
+    int doclose = 0;
 
4397
+    static char lastqr[MAX_MAILBOX_PATH+1] = "";
 
4398
+    static time_t nextalert = 0;
 
4399
+
 
4400
+    if (imapd_mailbox) {
 
4401
+       index_closemailbox(imapd_mailbox);
 
4402
+       mailbox_close(imapd_mailbox);
 
4403
+       imapd_mailbox = 0;
 
4404
+    }
 
4405
+
 
4406
+    if (cmd[0] == 'B') {
 
4407
+       /* BBoard namespace is empty */
 
4408
+       r = IMAP_MAILBOX_NONEXISTENT;
 
4409
+    }
 
4410
+    else {
 
4411
+       r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
4412
+                                                  imapd_userid, mailboxname);
 
4413
+    }
 
4414
+
 
4415
+    if (!r) {
 
4416
+       r = mlookup(tag, name, mailboxname, NULL, NULL, NULL, NULL, NULL);
 
4417
+    }
 
4418
+    if (r == IMAP_MAILBOX_MOVED) return;
 
4419
+
 
4420
+    if (!r) {
 
4421
+       r = mailbox_open_header(mailboxname, imapd_authstate, &mailbox);
 
4422
+    }
 
4423
+
 
4424
+    if (!r) {
 
4425
+       doclose = 1;
 
4426
+       r = mailbox_open_index(&mailbox);
 
4427
+    }
 
4428
+    if (!r && !(mailbox.myrights & ACL_READ)) {
 
4429
+       r = (imapd_userisadmin || (mailbox.myrights & ACL_LOOKUP)) ?
 
4430
+         IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
 
4431
+    }
 
4432
+    if (!r && chdir(mailbox.path)) {
 
4433
+       syslog(LOG_ERR, "IOERROR: changing directory to %s: %m", mailbox.path);
 
4434
+       r = IMAP_IOERROR;
 
4435
+    }
 
4436
+
 
4437
+    if (r) {
 
4438
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
4439
+       if (doclose) mailbox_close(&mailbox);
 
4440
+       return;
 
4441
+    }
 
4442
+
 
4443
+    mboxstruct = mailbox;
 
4444
+    imapd_mailbox = &mboxstruct;
 
4445
+
 
4446
+    index_newmailbox(imapd_mailbox, cmd[0] == 'E');
 
4447
+
 
4448
+    /* Examine command puts mailbox in read-only mode */
 
4449
+    if (cmd[0] == 'E') {
 
4450
+       imapd_mailbox->myrights &= ~(ACL_SEEN|ACL_WRITE|ACL_DELETE);
 
4451
+    }
 
4452
+
 
4453
+    if (imapd_mailbox->myrights & ACL_DELETE) {
 
4454
+       time_t now = time(NULL);
 
4455
+
 
4456
+       /* Warn if mailbox is close to or over quota */
 
4457
+       r = quota_read(&imapd_mailbox->quota, NULL, 0);
 
4458
+       if (!r && imapd_mailbox->quota.limit > 0 &&
 
4459
+           (strcmp(imapd_mailbox->quota.root, lastqr) || now > nextalert)) {
 
4460
+           /* Warn if the following possibilities occur:
 
4461
+            * - quotawarnkb not set + quotawarn hit
 
4462
+            * - quotawarnkb set larger than mailbox + quotawarn hit
 
4463
+            * - quotawarnkb set + hit + quotawarn hit
 
4464
+            */
 
4465
+           int warnsize = config_getint(IMAPOPT_QUOTAWARNKB);
 
4466
+           if (warnsize <= 0 || warnsize >= imapd_mailbox->quota.limit ||
 
4467
+               (int)((imapd_mailbox->quota.limit * QUOTA_UNITS) -
 
4468
+                     imapd_mailbox->quota.used) < (warnsize * QUOTA_UNITS)) {
 
4469
+               usage = ((double) imapd_mailbox->quota.used * 100.0) / (double)
 
4470
+                   (imapd_mailbox->quota.limit * QUOTA_UNITS);
 
4471
+               if (usage >= 100.0) {
 
4472
+                   prot_printf(imapd_out, "* NO [ALERT] %s\r\n",
 
4473
+                               error_message(IMAP_NO_OVERQUOTA));
 
4474
+               }
 
4475
+               else if (usage > config_getint(IMAPOPT_QUOTAWARN)) {
 
4476
+                   int usageint = (int) usage;
 
4477
+                   prot_printf(imapd_out, "* NO [ALERT] ");
 
4478
+                   prot_printf(imapd_out, error_message(IMAP_NO_CLOSEQUOTA),
 
4479
+                               usageint);
 
4480
+                   prot_printf(imapd_out, "\r\n");
 
4481
+               }
 
4482
+           }
 
4483
+           strlcpy(lastqr, imapd_mailbox->quota.root, sizeof(lastqr));
 
4484
+           nextalert = now + 600; /* ALERT every 10 min regardless */
 
4485
+       }
 
4486
+    }
 
4487
+
 
4488
+    prot_printf(imapd_out, "%s OK [READ-%s] %s\r\n", tag,
 
4489
+          (imapd_mailbox->myrights & (ACL_WRITE|ACL_DELETE)) ?
 
4490
+               "WRITE" : "ONLY", error_message(IMAP_OK_COMPLETED));
 
4491
+
 
4492
+    proc_register("imapd", imapd_clienthost, imapd_userid, mailboxname);
 
4493
+    syslog(LOG_DEBUG, "open: user %s opened %s", imapd_userid, name);
 
4494
+}
 
4495
+         
 
4496
+/*
 
4497
+ * Perform a CLOSE command
 
4498
+ */
 
4499
+void
 
4500
+cmd_close(tag)
 
4501
+char *tag;
 
4502
+{
 
4503
+    int r;
 
4504
+
 
4505
+    if (!(imapd_mailbox->myrights & ACL_DELETE)) r = 0;
 
4506
+    else {
 
4507
+       r = mailbox_expunge(imapd_mailbox, 1, (int (*)())0, (char *)0);
 
4508
+    }
 
4509
+
 
4510
+    index_closemailbox(imapd_mailbox);
 
4511
+    mailbox_close(imapd_mailbox);
 
4512
+    imapd_mailbox = 0;
 
4513
+
 
4514
+    if (r) {
 
4515
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
4516
+    }
 
4517
+    else {
 
4518
+       prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
4519
+                   error_message(IMAP_OK_COMPLETED));
 
4520
+    }
 
4521
+}    
 
4522
+
 
4523
+/*
 
4524
+ * Perform an UNSELECT command -- for some support of IMAP proxy.
 
4525
+ * Just like close except no expunge.
 
4526
+ */
 
4527
+void
 
4528
+cmd_unselect(tag)
 
4529
+char* tag;
 
4530
+{
 
4531
+    index_closemailbox(imapd_mailbox);
 
4532
+    mailbox_close(imapd_mailbox);
 
4533
+    imapd_mailbox = 0;
 
4534
+
 
4535
+    prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
4536
+               error_message(IMAP_OK_COMPLETED));
 
4537
+}
 
4538
+
 
4539
+/*
 
4540
+ * Parse the syntax for a partial fetch:
 
4541
+ *   "<" number "." nz-number ">"
 
4542
+ */
 
4543
+#define PARSE_PARTIAL(start_octet, octet_count)                                \
 
4544
+    (start_octet) = (octet_count) = 0;                                  \
 
4545
+    if (*p == '<' && isdigit((int) p[1])) {                            \
 
4546
+       (start_octet) = p[1] - '0';                             \
 
4547
+       p += 2;                                                         \
 
4548
+       while (isdigit((int) *p)) {                                     \
 
4549
+           (start_octet) =                                     \
 
4550
+               (start_octet) * 10 + *p++ - '0';                \
 
4551
+       }                                                               \
 
4552
+                                                                       \
 
4553
+       if (*p == '.' && p[1] >= '1' && p[1] <= '9') {                  \
 
4554
+           (octet_count) = p[1] - '0';                         \
 
4555
+           p[0] = '>'; p[1] = '\0'; /* clip off the octet count        \
 
4556
+                                       (its not used in the reply) */  \
 
4557
+           p += 2;                                                     \
 
4558
+           while (isdigit((int) *p)) {                                 \
 
4559
+               (octet_count) =                                 \
 
4560
+                   (octet_count) * 10 + *p++ - '0';            \
 
4561
+           }                                                           \
 
4562
+       }                                                               \
 
4563
+       else p--;                                                       \
 
4564
+                                                                       \
 
4565
+       if (*p != '>') {                                                \
 
4566
+           prot_printf(imapd_out,                                      \
 
4567
+                       "%s BAD Invalid body partial\r\n", tag);        \
 
4568
+           eatline(imapd_in, c);                                       \
 
4569
+           goto freeargs;                                              \
 
4570
+       }                                                               \
 
4571
+       p++;                                                            \
 
4572
+    }
 
4573
+
 
4574
+/*
 
4575
+ * Parse and perform a FETCH/UID FETCH command
 
4576
+ * The command has been parsed up to and including
 
4577
+ * the sequence
 
4578
+ */
 
4579
+void cmd_fetch(char *tag, char *sequence, int usinguid)
 
4580
+{
 
4581
+    char *cmd = usinguid ? "UID Fetch" : "Fetch";
 
4582
+    static struct buf fetchatt, fieldname;
 
4583
+    int c;
 
4584
+    int inlist = 0;
 
4585
+    int fetchitems = 0;
 
4586
+    struct fetchargs fetchargs;
 
4587
+    struct octetinfo oi;
 
4588
+    struct strlist *newfields = 0;
 
4589
+    char *p, *section;
 
4590
+    int fetchedsomething, r;
 
4591
+    clock_t start = clock();
 
4592
+    char mytime[100];
 
4593
+
 
4594
+    memset(&fetchargs, 0, sizeof(struct fetchargs));
 
4595
+
 
4596
+    c = getword(imapd_in, &fetchatt);
 
4597
+    if (c == '(' && !fetchatt.s[0]) {
 
4598
+       inlist = 1;
 
4599
+       c = getword(imapd_in, &fetchatt);
 
4600
+    }
 
4601
+    for (;;) {
 
4602
+       ucase(fetchatt.s);
 
4603
+       switch (fetchatt.s[0]) {
 
4604
+       case 'A':
 
4605
+           if (!inlist && !strcmp(fetchatt.s, "ALL")) {
 
4606
+               fetchitems |= FETCH_ALL;
 
4607
+           }
 
4608
+           else goto badatt;
 
4609
+           break;
 
4610
+
 
4611
+       case 'B':
 
4612
+           if (!strncmp(fetchatt.s, "BINARY[", 7) ||
 
4613
+               !strncmp(fetchatt.s, "BINARY.PEEK[", 12) ||
 
4614
+               !strncmp(fetchatt.s, "BINARY.SIZE[", 12)) {
 
4615
+               int binsize = 0;
 
4616
+
 
4617
+               p = section = fetchatt.s + 7;
 
4618
+               if (!strncmp(p, "PEEK[", 5)) {
 
4619
+                   p = section += 5;
 
4620
+               }
 
4621
+               else if (!strncmp(p, "SIZE[", 5)) {
 
4622
+                   p = section += 5;
 
4623
+                   binsize = 1;
 
4624
+               }
 
4625
+               else {
 
4626
+                   fetchitems |= FETCH_SETSEEN;
 
4627
+               }
 
4628
+               while ((*p >= '1' && *p <= '9') || *p == '.') {
 
4629
+                   if (*p == '.' && !isdigit((int) p[-1])) break;
 
4630
+                   p++;
 
4631
+               }
 
4632
+
 
4633
+               if (*p != ']') {
 
4634
+                   prot_printf(imapd_out, "%s BAD Invalid body section\r\n", tag);
 
4635
+                   eatline(imapd_in, c);
 
4636
+                   goto freeargs;
 
4637
+               }
 
4638
+               p++;
 
4639
+
 
4640
+               if (!binsize) PARSE_PARTIAL(oi.start_octet, oi.octet_count);
 
4641
+
 
4642
+               if (*p) {
 
4643
+                   prot_printf(imapd_out, "%s BAD Junk after body section\r\n", tag);
 
4644
+                   eatline(imapd_in, c);
 
4645
+                   goto freeargs;
 
4646
+               }
 
4647
+               if (binsize)
 
4648
+                   appendstrlist_withdata(&fetchargs.sizesections, section, &oi, sizeof(oi));
 
4649
+               else
 
4650
+                   appendstrlist_withdata(&fetchargs.binsections, section, &oi, sizeof(oi));
 
4651
+           }
 
4652
+           else if (!strcmp(fetchatt.s, "BODY")) {
 
4653
+               fetchitems |= FETCH_BODY;
 
4654
+           }
 
4655
+           else if (!strcmp(fetchatt.s, "BODYSTRUCTURE")) {
 
4656
+               fetchitems |= FETCH_BODYSTRUCTURE;
 
4657
+           }
 
4658
+           else if (!strncmp(fetchatt.s, "BODY[", 5) ||
 
4659
+                    !strncmp(fetchatt.s, "BODY.PEEK[", 10)) {
 
4660
+               p = section = fetchatt.s + 5;
 
4661
+               if (!strncmp(p, "PEEK[", 5)) {
 
4662
+                   p = section += 5;
 
4663
+               }
 
4664
+               else {
 
4665
+                   fetchitems |= FETCH_SETSEEN;
 
4666
+               }
 
4667
+               while (isdigit((int) *p) || *p == '.') {
 
4668
+                   if (*p == '.' && !isdigit((int) p[-1])) break;
 
4669
+                   /* Obsolete section 0 can only occur before close brace */
 
4670
+                   if (*p == '0' && !isdigit((int) p[-1]) && p[1] != ']') break;
 
4671
+                   p++;
 
4672
+               }
 
4673
+
 
4674
+               if (*p == 'H' && !strncmp(p, "HEADER.FIELDS", 13) &&
 
4675
+                   (p == section || p[-1] == '.') &&
 
4676
+                   (p[13] == '\0' || !strcmp(p+13, ".NOT"))) {
 
4677
+
 
4678
+                   /*
 
4679
+                    * If not top-level or a HEADER.FIELDS.NOT, can't pull
 
4680
+                    * the headers out of the cache.
 
4681
+                    */
 
4682
+                   if (p != section || p[13] != '\0') {
 
4683
+                       fetchargs.cache_atleast = BIT32_MAX;
 
4684
+                   }
 
4685
+
 
4686
+                   if (c != ' ') {
 
4687
+                       prot_printf(imapd_out,
 
4688
+                                   "%s BAD Missing required argument to %s %s\r\n",
 
4689
+                                   tag, cmd, fetchatt.s);
 
4690
+                       eatline(imapd_in, c);
 
4691
+                       goto freeargs;
 
4692
+                   }
 
4693
+                   c = prot_getc(imapd_in);
 
4694
+                   if (c != '(') {
 
4695
+                       prot_printf(imapd_out, "%s BAD Missing required open parenthesis in %s %s\r\n",
 
4696
+                                   tag, cmd, fetchatt.s);
 
4697
+                       eatline(imapd_in, c);
 
4698
+                       goto freeargs;
 
4699
+                   }
 
4700
+                   do {
 
4701
+                       c = getastring(imapd_in, imapd_out, &fieldname);
 
4702
+                       for (p = fieldname.s; *p; p++) {
 
4703
+                           if (*p <= ' ' || *p & 0x80 || *p == ':') break;
 
4704
+                       }
 
4705
+                       if (*p || !*fieldname.s) {
 
4706
+                           prot_printf(imapd_out, "%s BAD Invalid field-name in %s %s\r\n",
 
4707
+                                       tag, cmd, fetchatt.s);
 
4708
+                           eatline(imapd_in, c);
 
4709
+                           goto freeargs;
 
4710
+                       }
 
4711
+                       appendstrlist(&newfields, fieldname.s);
 
4712
+                       if (fetchargs.cache_atleast < BIT32_MAX) {
 
4713
+                           bit32 this_ver =
 
4714
+                               mailbox_cached_header(fieldname.s);
 
4715
+                           if(this_ver > fetchargs.cache_atleast)
 
4716
+                               fetchargs.cache_atleast = this_ver;
 
4717
+                       }
 
4718
+                   } while (c == ' ');
 
4719
+                   if (c != ')') {
 
4720
+                       prot_printf(imapd_out, "%s BAD Missing required close parenthesis in %s %s\r\n",
 
4721
+                                   tag, cmd, fetchatt.s);
 
4722
+                       eatline(imapd_in, c);
 
4723
+                       goto freeargs;
 
4724
+                   }
 
4725
+
 
4726
+                   /* Grab/parse the ]<x.y> part */
 
4727
+                   c = getword(imapd_in, &fieldname);
 
4728
+                   p = fieldname.s;
 
4729
+                   if (*p++ != ']') {
 
4730
+                       prot_printf(imapd_out, "%s BAD Missing required close bracket after %s %s\r\n",
 
4731
+                                   tag, cmd, fetchatt.s);
 
4732
+                       eatline(imapd_in, c);
 
4733
+                       goto freeargs;
 
4734
+                   }
 
4735
+
 
4736
+                   PARSE_PARTIAL(oi.start_octet, oi.octet_count);
 
4737
+
 
4738
+                   if (*p) {
 
4739
+                       prot_printf(imapd_out, "%s BAD Junk after body section\r\n", tag);
 
4740
+                       eatline(imapd_in, c);
 
4741
+                       goto freeargs;
 
4742
+                   }
 
4743
+                   appendfieldlist(&fetchargs.fsections,
 
4744
+                                   section, newfields, fieldname.s,
 
4745
+                                   &oi, sizeof(oi));
 
4746
+                   newfields = 0;
 
4747
+                   break;
 
4748
+               }
 
4749
+
 
4750
+               switch (*p) {
 
4751
+               case 'H':
 
4752
+                   if (p != section && p[-1] != '.') break;
 
4753
+                   if (!strncmp(p, "HEADER]", 7)) p += 6;
 
4754
+                   break;
 
4755
+
 
4756
+               case 'M':
 
4757
+                   if (!strncmp(p-1, ".MIME]", 6)) p += 4;
 
4758
+                   break;
 
4759
+
 
4760
+               case 'T':
 
4761
+                   if (p != section && p[-1] != '.') break;
 
4762
+                   if (!strncmp(p, "TEXT]", 5)) p += 4;
 
4763
+                   break;
 
4764
+               }
 
4765
+
 
4766
+               if (*p != ']') {
 
4767
+                   prot_printf(imapd_out, "%s BAD Invalid body section\r\n", tag);
 
4768
+                   eatline(imapd_in, c);
 
4769
+                   goto freeargs;
 
4770
+               }
 
4771
+               p++;
 
4772
+
 
4773
+               PARSE_PARTIAL(oi.start_octet, oi.octet_count);
 
4774
+
 
4775
+               if (*p) {
 
4776
+                   prot_printf(imapd_out, "%s BAD Junk after body section\r\n", tag);
 
4777
+                   eatline(imapd_in, c);
 
4778
+                   goto freeargs;
 
4779
+               }
 
4780
+               appendstrlist_withdata(&fetchargs.bodysections, section,
 
4781
+                                      &oi, sizeof(oi));
 
4782
+           }
 
4783
+           else goto badatt;
 
4784
+           break;
 
4785
+
 
4786
+       case 'E':
 
4787
+           if (!strcmp(fetchatt.s, "ENVELOPE")) {
 
4788
+               fetchitems |= FETCH_ENVELOPE;
 
4789
+           }
 
4790
+           else goto badatt;
 
4791
+           break;
 
4792
+
 
4793
+       case 'F':
 
4794
+           if (!inlist && !strcmp(fetchatt.s, "FAST")) {
 
4795
+               fetchitems |= FETCH_FAST;
 
4796
+           }
 
4797
+           else if (!inlist && !strcmp(fetchatt.s, "FULL")) {
 
4798
+               fetchitems |= FETCH_FULL;
 
4799
+           }
 
4800
+           else if (!strcmp(fetchatt.s, "FLAGS")) {
 
4801
+               fetchitems |= FETCH_FLAGS;
 
4802
+           }
 
4803
+           else goto badatt;
 
4804
+           break;
 
4805
+
 
4806
+       case 'I':
 
4807
+           if (!strcmp(fetchatt.s, "INTERNALDATE")) {
 
4808
+               fetchitems |= FETCH_INTERNALDATE;
 
4809
+           }
 
4810
+           else goto badatt;
 
4811
+           break;
 
4812
+
 
4813
+       case 'R':
 
4814
+           if (!strcmp(fetchatt.s, "RFC822")) {
 
4815
+               fetchitems |= FETCH_RFC822|FETCH_SETSEEN;
 
4816
+           }
 
4817
+           else if (!strcmp(fetchatt.s, "RFC822.HEADER")) {
 
4818
+               fetchitems |= FETCH_HEADER;
 
4819
+           }
 
4820
+           else if (!strcmp(fetchatt.s, "RFC822.PEEK")) {
 
4821
+               fetchitems |= FETCH_RFC822;
 
4822
+           }
 
4823
+           else if (!strcmp(fetchatt.s, "RFC822.SIZE")) {
 
4824
+               fetchitems |= FETCH_SIZE;
 
4825
+           }
 
4826
+           else if (!strcmp(fetchatt.s, "RFC822.TEXT")) {
 
4827
+               fetchitems |= FETCH_TEXT|FETCH_SETSEEN;
 
4828
+           }
 
4829
+           else if (!strcmp(fetchatt.s, "RFC822.TEXT.PEEK")) {
 
4830
+               fetchitems |= FETCH_TEXT;
 
4831
+           }
 
4832
+           else if (!strcmp(fetchatt.s, "RFC822.HEADER.LINES") ||
 
4833
+                    !strcmp(fetchatt.s, "RFC822.HEADER.LINES.NOT")) {
 
4834
+               if (c != ' ') {
 
4835
+                   prot_printf(imapd_out, "%s BAD Missing required argument to %s %s\r\n",
 
4836
+                          tag, cmd, fetchatt.s);
 
4837
+                   eatline(imapd_in, c);
 
4838
+                   goto freeargs;
 
4839
+               }
 
4840
+               c = prot_getc(imapd_in);
 
4841
+               if (c != '(') {
 
4842
+                   prot_printf(imapd_out, "%s BAD Missing required open parenthesis in %s %s\r\n",
 
4843
+                          tag, cmd, fetchatt.s);
 
4844
+                   eatline(imapd_in, c);
 
4845
+                   goto freeargs;
 
4846
+               }
 
4847
+               do {
 
4848
+                   c = getastring(imapd_in, imapd_out, &fieldname);
 
4849
+                   for (p = fieldname.s; *p; p++) {
 
4850
+                       if (*p <= ' ' || *p & 0x80 || *p == ':') break;
 
4851
+                   }
 
4852
+                   if (*p || !*fieldname.s) {
 
4853
+                       prot_printf(imapd_out, "%s BAD Invalid field-name in %s %s\r\n",
 
4854
+                              tag, cmd, fetchatt.s);
 
4855
+                       eatline(imapd_in, c);
 
4856
+                       goto freeargs;
 
4857
+                   }
 
4858
+                   lcase(fieldname.s);;
 
4859
+                   /* 19 is magic number -- length of 
 
4860
+                    * "RFC822.HEADERS.NOT" */
 
4861
+                   appendstrlist(strlen(fetchatt.s) == 19 ?
 
4862
+                                 &fetchargs.headers : &fetchargs.headers_not,
 
4863
+                                 fieldname.s);
 
4864
+                   if (strlen(fetchatt.s) != 19) {
 
4865
+                       fetchargs.cache_atleast = BIT32_MAX;
 
4866
+                   }
 
4867
+                   if (fetchargs.cache_atleast < BIT32_MAX) {
 
4868
+                       bit32 this_ver =
 
4869
+                           mailbox_cached_header(fieldname.s);
 
4870
+                       if(this_ver > fetchargs.cache_atleast)
 
4871
+                           fetchargs.cache_atleast = this_ver;
 
4872
+                  }
 
4873
+               } while (c == ' ');
 
4874
+               if (c != ')') {
 
4875
+                   prot_printf(imapd_out, "%s BAD Missing required close parenthesis in %s %s\r\n",
 
4876
+                          tag, cmd, fetchatt.s);
 
4877
+                   eatline(imapd_in, c);
 
4878
+                   goto freeargs;
 
4879
+               }
 
4880
+               c = prot_getc(imapd_in);
 
4881
+           }
 
4882
+           else goto badatt;
 
4883
+           break;
 
4884
+
 
4885
+       case 'U':
 
4886
+           if (!strcmp(fetchatt.s, "UID")) {
 
4887
+               fetchitems |= FETCH_UID;
 
4888
+           }
 
4889
+           else goto badatt;
 
4890
+           break;
 
4891
+
 
4892
+       default:
 
4893
+       badatt:
 
4894
+           prot_printf(imapd_out, "%s BAD Invalid %s attribute %s\r\n", tag, cmd, fetchatt.s);
 
4895
+           eatline(imapd_in, c);
 
4896
+           goto freeargs;
 
4897
+       }
 
4898
+
 
4899
+       if (inlist && c == ' ') c = getword(imapd_in, &fetchatt);
 
4900
+       else break;
 
4901
+    }
 
4902
+    
 
4903
+    if (inlist && c == ')') {
 
4904
+       inlist = 0;
 
4905
+       c = prot_getc(imapd_in);
 
4906
+    }
 
4907
+    if (inlist) {
 
4908
+       prot_printf(imapd_out, "%s BAD Missing close parenthesis in %s\r\n", tag, cmd);
 
4909
+       eatline(imapd_in, c);
 
4910
+       goto freeargs;
 
4911
+    }
 
4912
+    if (c == '\r') c = prot_getc(imapd_in);
 
4913
+    if (c != '\n') {
 
4914
+       prot_printf(imapd_out, "%s BAD Unexpected extra arguments to %s\r\n", tag, cmd);
 
4915
+       eatline(imapd_in, c);
 
4916
+       goto freeargs;
 
4917
+    }
 
4918
+
 
4919
+    if (!fetchitems && !fetchargs.bodysections && !fetchargs.fsections &&
 
4920
+       !fetchargs.binsections && !fetchargs.sizesections &&
 
4921
+       !fetchargs.headers && !fetchargs.headers_not) {
 
4922
+       prot_printf(imapd_out, "%s BAD Missing required argument to %s\r\n", tag, cmd);
 
4923
+       goto freeargs;
 
4924
+    }
 
4925
+
 
4926
+    if (usinguid) {
 
4927
+       fetchitems |= FETCH_UID;
 
4928
+       index_check(imapd_mailbox, 1, 0);
 
4929
+    }
 
4930
+
 
4931
+    fetchargs.fetchitems = fetchitems;
 
4932
+    r = index_fetch(imapd_mailbox, sequence, usinguid, &fetchargs,
 
4933
+               &fetchedsomething);
 
4934
+
 
4935
+    snprintf(mytime, sizeof(mytime), "%2.3f", 
 
4936
+            (clock() - start) / (double) CLOCKS_PER_SEC);
 
4937
+
 
4938
+    if (r) {
 
4939
+       prot_printf(imapd_out, "%s NO %s (%s sec)\r\n", tag,
 
4940
+                   error_message(r), mytime);
 
4941
+    } else if (fetchedsomething || usinguid) {
 
4942
+       prot_printf(imapd_out, "%s OK %s (%s sec)\r\n", tag,
 
4943
+                   error_message(IMAP_OK_COMPLETED), mytime);
 
4944
+    } else {
 
4945
+       /* normal FETCH, nothing came back */
 
4946
+       prot_printf(imapd_out, "%s NO %s (%s sec)\r\n", tag,
 
4947
+                   error_message(IMAP_NO_NOSUCHMSG), mytime);
 
4948
+    }
 
4949
+
 
4950
+ freeargs:
 
4951
+    freestrlist(newfields);
 
4952
+    freestrlist(fetchargs.bodysections);
 
4953
+    freefieldlist(fetchargs.fsections);
 
4954
+    freestrlist(fetchargs.headers);
 
4955
+    freestrlist(fetchargs.headers_not);
 
4956
+}
 
4957
+
 
4958
+#undef PARSE_PARTIAL /* cleanup */
 
4959
+
 
4960
+/*
 
4961
+ * Perform a PARTIAL command
 
4962
+ */
 
4963
+void cmd_partial(const char *tag, const char *msgno, char *data,
 
4964
+                const char *start, const char *count)
 
4965
+{
 
4966
+    const char *pc;
 
4967
+    char *p;
 
4968
+    struct fetchargs fetchargs;
 
4969
+    char *section;
 
4970
+    int prev;
 
4971
+    int fetchedsomething;
 
4972
+
 
4973
+    memset(&fetchargs, 0, sizeof(struct fetchargs));
 
4974
+
 
4975
+    for (pc = msgno; *pc; pc++) {
 
4976
+       if (!isdigit((int) *pc)) break;
 
4977
+    }
 
4978
+    if (*pc || !*msgno) {
 
4979
+       prot_printf(imapd_out, "%s BAD Invalid message number\r\n", tag);
 
4980
+       return;
 
4981
+    }
 
4982
+
 
4983
+    lcase(data);
 
4984
+    if (!strcmp(data, "rfc822")) {
 
4985
+       fetchargs.fetchitems = FETCH_RFC822|FETCH_SETSEEN;
 
4986
+    }
 
4987
+    else if (!strcmp(data, "rfc822.header")) {
 
4988
+       fetchargs.fetchitems = FETCH_HEADER;
 
4989
+    }
 
4990
+    else if (!strcmp(data, "rfc822.peek")) {
 
4991
+       fetchargs.fetchitems = FETCH_RFC822;
 
4992
+    }
 
4993
+    else if (!strcmp(data, "rfc822.text")) {
 
4994
+       fetchargs.fetchitems = FETCH_TEXT|FETCH_SETSEEN;
 
4995
+    }
 
4996
+    else if (!strcmp(data, "rfc822.text.peek")) {
 
4997
+       fetchargs.fetchitems = FETCH_TEXT;
 
4998
+    }
 
4999
+    else if (!strncmp(data, "body[", 5) ||
 
5000
+            !strncmp(data, "body.peek[", 10)) {
 
5001
+       p = section = data + 5;
 
5002
+       if (!strncmp(p, "peek[", 5)) {
 
5003
+           p = section += 5;
 
5004
+       }
 
5005
+       else {
 
5006
+           fetchargs.fetchitems = FETCH_SETSEEN;
 
5007
+       }
 
5008
+       while (isdigit((int) *p) || *p == '.') {
 
5009
+           if (*p == '.' && (p == section || !isdigit((int) p[1]))) break;
 
5010
+           p++;
 
5011
+       }
 
5012
+       if (p == section || *p != ']' || p[1]) {
 
5013
+           prot_printf(imapd_out, "%s BAD Invalid body section\r\n", tag);
 
5014
+           freestrlist(fetchargs.bodysections);
 
5015
+           return;
 
5016
+       }
 
5017
+       *(p+1) = '\0'; /* Keep the closing bracket in place */
 
5018
+       appendstrlist(&fetchargs.bodysections, section);
 
5019
+    }
 
5020
+    else {
 
5021
+       prot_printf(imapd_out, "%s BAD Invalid Partial item\r\n", tag);
 
5022
+       freestrlist(fetchargs.bodysections);
 
5023
+       return;
 
5024
+    }
 
5025
+
 
5026
+    for (pc = start; *pc; pc++) {
 
5027
+       if (!isdigit((int) *pc)) break;
 
5028
+       prev = fetchargs.start_octet;
 
5029
+       fetchargs.start_octet = fetchargs.start_octet*10 + *pc - '0';
 
5030
+       if(fetchargs.start_octet < prev) {
 
5031
+           fetchargs.start_octet = 0;
 
5032
+           break;
 
5033
+       }
 
5034
+    }
 
5035
+    if (*pc || !fetchargs.start_octet) {
 
5036
+       prot_printf(imapd_out, "%s BAD Invalid starting octet\r\n", tag);
 
5037
+       freestrlist(fetchargs.bodysections);
 
5038
+       return;
 
5039
+    }
 
5040
+    fetchargs.start_octet--;   /* Normalize to be 0-based */
 
5041
+    
 
5042
+    prev = fetchargs.octet_count;
 
5043
+    for (pc = count; *pc; pc++) {
 
5044
+       if (!isdigit((int) *pc)) break;
 
5045
+       prev = fetchargs.octet_count;
 
5046
+       fetchargs.octet_count = fetchargs.octet_count*10 + *pc - '0';
 
5047
+       if(fetchargs.octet_count < prev) {
 
5048
+           prev = -1;
 
5049
+           break;
 
5050
+       }
 
5051
+    }
 
5052
+    if (*pc || !*count || prev == -1) {
 
5053
+       prot_printf(imapd_out, "%s BAD Invalid octet count\r\n", tag);
 
5054
+       freestrlist(fetchargs.bodysections);
 
5055
+       return;
 
5056
+    }
 
5057
+
 
5058
+    fetchargs.fetchitems |= FETCH_IS_PARTIAL;
 
5059
+
 
5060
+    index_fetch(imapd_mailbox, msgno, 0, &fetchargs, &fetchedsomething);
 
5061
+
 
5062
+    index_check(imapd_mailbox, 0, 0);
 
5063
+
 
5064
+    if (fetchedsomething) {
 
5065
+       prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
5066
+                   error_message(IMAP_OK_COMPLETED));
 
5067
+    } else {
 
5068
+       prot_printf(imapd_out,
 
5069
+                   "%s BAD Invalid sequence in PARTIAL command\r\n",
 
5070
+                   tag);
 
5071
+    }
 
5072
+
 
5073
+    freestrlist(fetchargs.bodysections);
 
5074
+}
 
5075
+
 
5076
+/*
 
5077
+ * Parse and perform a STORE/UID STORE command
 
5078
+ * The command has been parsed up to and including
 
5079
+ * the FLAGS/+FLAGS/-FLAGS
 
5080
+ */
 
5081
+void cmd_store(char *tag, char *sequence, char *operation, int usinguid)
 
5082
+{
 
5083
+    char *cmd = usinguid ? "UID Store" : "Store";
 
5084
+    struct storeargs storeargs;
 
5085
+    static struct buf flagname;
 
5086
+    int len, c;
 
5087
+    char **flag = 0;
 
5088
+    int nflags = 0, flagalloc = 0;
 
5089
+    int flagsparsed = 0, inlist = 0;
 
5090
+    int r;
 
5091
+
 
5092
+    memset(&storeargs, 0, sizeof storeargs);
 
5093
+
 
5094
+    lcase(operation);
 
5095
+
 
5096
+    len = strlen(operation);
 
5097
+    if (len > 7 && !strcmp(operation+len-7, ".silent")) {
 
5098
+       storeargs.silent = 1;
 
5099
+       operation[len-7] = '\0';
 
5100
+    }
 
5101
+    
 
5102
+    if (!strcmp(operation, "+flags")) {
 
5103
+       storeargs.operation = STORE_ADD;
 
5104
+    }
 
5105
+    else if (!strcmp(operation, "-flags")) {
 
5106
+       storeargs.operation = STORE_REMOVE;
 
5107
+    }
 
5108
+    else if (!strcmp(operation, "flags")) {
 
5109
+       storeargs.operation = STORE_REPLACE;
 
5110
+    }
 
5111
+    else {
 
5112
+       prot_printf(imapd_out, "%s BAD Invalid %s attribute\r\n", tag, cmd);
 
5113
+       eatline(imapd_in, ' ');
 
5114
+       return;
 
5115
+    }
 
5116
+
 
5117
+    for (;;) {
 
5118
+       c = getword(imapd_in, &flagname);
 
5119
+       if (c == '(' && !flagname.s[0] && !flagsparsed && !inlist) {
 
5120
+           inlist = 1;
 
5121
+           continue;
 
5122
+       }
 
5123
+
 
5124
+       if (!flagname.s[0]) break;
 
5125
+
 
5126
+       if (flagname.s[0] == '\\') {
 
5127
+           lcase(flagname.s);
 
5128
+           if (!strcmp(flagname.s, "\\seen")) {
 
5129
+               storeargs.seen = 1;
 
5130
+           }
 
5131
+           else if (!strcmp(flagname.s, "\\answered")) {
 
5132
+               storeargs.system_flags |= FLAG_ANSWERED;
 
5133
+           }
 
5134
+           else if (!strcmp(flagname.s, "\\flagged")) {
 
5135
+               storeargs.system_flags |= FLAG_FLAGGED;
 
5136
+           }
 
5137
+           else if (!strcmp(flagname.s, "\\deleted")) {
 
5138
+               storeargs.system_flags |= FLAG_DELETED;
 
5139
+           }
 
5140
+           else if (!strcmp(flagname.s, "\\draft")) {
 
5141
+               storeargs.system_flags |= FLAG_DRAFT;
 
5142
+           }
 
5143
+           else {
 
5144
+               prot_printf(imapd_out, "%s BAD Invalid system flag in %s command\r\n",
 
5145
+                      tag, cmd);
 
5146
+               eatline(imapd_in, c);
 
5147
+               goto freeflags;
 
5148
+           }
 
5149
+       }
 
5150
+       else if (!imparse_isatom(flagname.s)) {
 
5151
+           prot_printf(imapd_out, "%s BAD Invalid flag name %s in %s command\r\n",
 
5152
+                  tag, flagname.s, cmd);
 
5153
+           eatline(imapd_in, c);
 
5154
+           goto freeflags;
 
5155
+       }
 
5156
+       else {
 
5157
+           if (nflags == flagalloc) {
 
5158
+               flagalloc += FLAGGROW;
 
5159
+               flag = (char **)xrealloc((char *)flag,
 
5160
+                                        flagalloc*sizeof(char *));
 
5161
+           }
 
5162
+           flag[nflags] = xstrdup(flagname.s);
 
5163
+           nflags++;
 
5164
+       }
 
5165
+
 
5166
+       flagsparsed++;
 
5167
+       if (c != ' ') break;
 
5168
+    }
 
5169
+
 
5170
+    if (!inlist && !flagsparsed) {
 
5171
+       prot_printf(imapd_out, "%s BAD Missing required argument to %s\r\n", tag, cmd);
 
5172
+       eatline(imapd_in, c);
 
5173
+       return;
 
5174
+    }
 
5175
+    if (inlist && c == ')') {
 
5176
+       inlist = 0;
 
5177
+       c = prot_getc(imapd_in);
 
5178
+    }
 
5179
+    if (inlist) {
 
5180
+       prot_printf(imapd_out, "%s BAD Missing close parenthesis in %s\r\n", tag, cmd);
 
5181
+       eatline(imapd_in, c);
 
5182
+       goto freeflags;
 
5183
+    }
 
5184
+    if (c == '\r') c = prot_getc(imapd_in);
 
5185
+    if (c != '\n') {
 
5186
+       prot_printf(imapd_out, "%s BAD Unexpected extra arguments to %s\r\n", tag, cmd);
 
5187
+       eatline(imapd_in, c);
 
5188
+       goto freeflags;
 
5189
+    }
 
5190
+
 
5191
+    r = index_store(imapd_mailbox, sequence, usinguid, &storeargs,
 
5192
+                   flag, nflags);
 
5193
+
 
5194
+    if (usinguid) {
 
5195
+       index_check(imapd_mailbox, 1, 0);
 
5196
+    }
 
5197
+
 
5198
+    if (r) {
 
5199
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
5200
+    }
 
5201
+    else {
 
5202
+       prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
5203
+                   error_message(IMAP_OK_COMPLETED));
 
5204
+    }
 
5205
+
 
5206
+ freeflags:
 
5207
+    while (nflags--) {
 
5208
+       free(flag[nflags]);
 
5209
+    }
 
5210
+    if (flag) free((char *)flag);
 
5211
+}
 
5212
+
 
5213
+void
 
5214
+cmd_search(tag, usinguid)
 
5215
+char *tag;
 
5216
+int usinguid;
 
5217
+{
 
5218
+    int c;
 
5219
+    int charset = 0;
 
5220
+    struct searchargs *searchargs;
 
5221
+    clock_t start = clock();
 
5222
+    char mytime[100];
 
5223
+    int n;
 
5224
+
 
5225
+    searchargs = (struct searchargs *)xzmalloc(sizeof(struct searchargs));
 
5226
+
 
5227
+    c = getsearchprogram(tag, searchargs, &charset, 1);
 
5228
+    if (c == EOF) {
 
5229
+       eatline(imapd_in, ' ');
 
5230
+       freesearchargs(searchargs);
 
5231
+       return;
 
5232
+    }
 
5233
+
 
5234
+    if (c == '\r') c = prot_getc(imapd_in);
 
5235
+    if (c != '\n') {
 
5236
+       prot_printf(imapd_out, "%s BAD Unexpected extra arguments to Search\r\n", tag);
 
5237
+       eatline(imapd_in, c);
 
5238
+       freesearchargs(searchargs);
 
5239
+       return;
 
5240
+    }
 
5241
+
 
5242
+    if (charset == -1) {
 
5243
+       prot_printf(imapd_out, "%s NO %s\r\n", tag,
 
5244
+              error_message(IMAP_UNRECOGNIZED_CHARSET));
 
5245
+    }
 
5246
+    else {
 
5247
+       n = index_search(imapd_mailbox, searchargs, usinguid);
 
5248
+       snprintf(mytime, sizeof(mytime), "%2.3f", 
 
5249
+                (clock() - start) / (double) CLOCKS_PER_SEC);
 
5250
+       prot_printf(imapd_out, "%s OK %s (%d msgs in %s secs)\r\n", tag,
 
5251
+                   error_message(IMAP_OK_COMPLETED), n, mytime);
 
5252
+    }
 
5253
+
 
5254
+    freesearchargs(searchargs);
 
5255
+}
 
5256
+
 
5257
+/*
 
5258
+ * Perform a SORT/UID SORT command
 
5259
+ */    
 
5260
+void
 
5261
+cmd_sort(tag, usinguid)
 
5262
+char *tag;
 
5263
+int usinguid;
 
5264
+{
 
5265
+    int c;
 
5266
+    struct sortcrit *sortcrit = NULL;
 
5267
+    static struct buf arg;
 
5268
+    int charset = 0;
 
5269
+    struct searchargs *searchargs;
 
5270
+    clock_t start = clock();
 
5271
+    char mytime[100];
 
5272
+    int n;
 
5273
+
 
5274
+    c = getsortcriteria(tag, &sortcrit);
 
5275
+    if (c == EOF) {
 
5276
+       eatline(imapd_in, ' ');
 
5277
+       freesortcrit(sortcrit);
 
5278
+       return;
 
5279
+    }
 
5280
+
 
5281
+    /* get charset */
 
5282
+    if (c != ' ') {
 
5283
+       prot_printf(imapd_out, "%s BAD Missing charset in Sort\r\n",
 
5284
+                   tag);
 
5285
+       eatline(imapd_in, c);
 
5286
+       freesortcrit(sortcrit);
 
5287
+       return;
 
5288
+    }
 
5289
+
 
5290
+    c = getword(imapd_in, &arg);
 
5291
+    if (c != ' ') {
 
5292
+       prot_printf(imapd_out, "%s BAD Missing search criteria in Sort\r\n",
 
5293
+                   tag);
 
5294
+       eatline(imapd_in, c);
 
5295
+       freesortcrit(sortcrit);
 
5296
+       return;
 
5297
+    }
 
5298
+    lcase(arg.s);
 
5299
+    charset = charset_lookupname(arg.s);
 
5300
+
 
5301
+    if (charset == -1) {
 
5302
+       prot_printf(imapd_out, "%s NO %s\r\n", tag,
 
5303
+              error_message(IMAP_UNRECOGNIZED_CHARSET));
 
5304
+       eatline(imapd_in, c);
 
5305
+       freesortcrit(sortcrit);
 
5306
+       return;
 
5307
+    }
 
5308
+
 
5309
+    searchargs = (struct searchargs *)xzmalloc(sizeof(struct searchargs));
 
5310
+
 
5311
+    c = getsearchprogram(tag, searchargs, &charset, 0);
 
5312
+    if (c == EOF) {
 
5313
+       eatline(imapd_in, ' ');
 
5314
+       freesearchargs(searchargs);
 
5315
+       freesortcrit(sortcrit);
 
5316
+       return;
 
5317
+    }
 
5318
+
 
5319
+    if (c == '\r') c = prot_getc(imapd_in);
 
5320
+    if (c != '\n') {
 
5321
+       prot_printf(imapd_out, 
 
5322
+                   "%s BAD Unexpected extra arguments to Sort\r\n", tag);
 
5323
+       eatline(imapd_in, c);
 
5324
+       freesearchargs(searchargs);
 
5325
+       freesortcrit(sortcrit);
 
5326
+       return;
 
5327
+    }
 
5328
+
 
5329
+    n = index_sort(imapd_mailbox, sortcrit, searchargs, usinguid);
 
5330
+    snprintf(mytime, sizeof(mytime), "%2.3f",
 
5331
+            (clock() - start) / (double) CLOCKS_PER_SEC);
 
5332
+    prot_printf(imapd_out, "%s OK %s (%d msgs in %s secs)\r\n", tag,
 
5333
+               error_message(IMAP_OK_COMPLETED), n, mytime);
 
5334
+
 
5335
+    freesortcrit(sortcrit);
 
5336
+    freesearchargs(searchargs);
 
5337
+    return;
 
5338
+}
 
5339
+
 
5340
+/*
 
5341
+ * Perform a THREAD/UID THREAD command
 
5342
+ */    
 
5343
+void
 
5344
+cmd_thread(tag, usinguid)
 
5345
+char *tag;
 
5346
+int usinguid;
 
5347
+{
 
5348
+    static struct buf arg;
 
5349
+    int c;
 
5350
+    int charset = 0;
 
5351
+    int alg;
 
5352
+    struct searchargs *searchargs;
 
5353
+    clock_t start = clock();
 
5354
+    char mytime[100];
 
5355
+    int n;
 
5356
+
 
5357
+    /* get algorithm */
 
5358
+    c = getword(imapd_in, &arg);
 
5359
+    if (c != ' ') {
 
5360
+       prot_printf(imapd_out, "%s BAD Missing algorithm in Thread\r\n", tag);
 
5361
+       eatline(imapd_in, c);
 
5362
+       return;
 
5363
+    }
 
5364
+
 
5365
+    if ((alg = find_thread_algorithm(arg.s)) == -1) {
 
5366
+       prot_printf(imapd_out, "%s BAD Invalid Thread algorithm %s\r\n",
 
5367
+                   tag, arg.s);
 
5368
+       eatline(imapd_in, c);
 
5369
+       return;
 
5370
+    }
 
5371
+
 
5372
+    /* get charset */
 
5373
+    c = getword(imapd_in, &arg);
 
5374
+    if (c != ' ') {
 
5375
+       prot_printf(imapd_out, "%s BAD Missing charset in Thread\r\n",
 
5376
+                   tag);
 
5377
+       eatline(imapd_in, c);
 
5378
+       return;
 
5379
+    }
 
5380
+    lcase(arg.s);
 
5381
+    charset = charset_lookupname(arg.s);
 
5382
+
 
5383
+    if (charset == -1) {
 
5384
+       prot_printf(imapd_out, "%s NO %s\r\n", tag,
 
5385
+              error_message(IMAP_UNRECOGNIZED_CHARSET));
 
5386
+       eatline(imapd_in, c);
 
5387
+       return;
 
5388
+    }
 
5389
+
 
5390
+    searchargs = (struct searchargs *)xzmalloc(sizeof(struct searchargs));
 
5391
+
 
5392
+    c = getsearchprogram(tag, searchargs, &charset, 0);
 
5393
+    if (c == EOF) {
 
5394
+       eatline(imapd_in, ' ');
 
5395
+       freesearchargs(searchargs);
 
5396
+       return;
 
5397
+    }
 
5398
+
 
5399
+    if (c == '\r') c = prot_getc(imapd_in);
 
5400
+    if (c != '\n') {
 
5401
+       prot_printf(imapd_out, 
 
5402
+                   "%s BAD Unexpected extra arguments to Thread\r\n", tag);
 
5403
+       eatline(imapd_in, c);
 
5404
+       freesearchargs(searchargs);
 
5405
+       return;
 
5406
+    }
 
5407
+
 
5408
+    n = index_thread(imapd_mailbox, alg, searchargs, usinguid);
 
5409
+    snprintf(mytime, sizeof(mytime), "%2.3f", 
 
5410
+            (clock() - start) / (double) CLOCKS_PER_SEC);
 
5411
+    prot_printf(imapd_out, "%s OK %s (%d msgs in %s secs)\r\n", tag,
 
5412
+               error_message(IMAP_OK_COMPLETED), n, mytime);
 
5413
+
 
5414
+    freesearchargs(searchargs);
 
5415
+    return;
 
5416
+}
 
5417
+
 
5418
+/*
 
5419
+ * Perform a COPY/UID COPY command
 
5420
+ */    
 
5421
+void
 
5422
+cmd_copy(tag, sequence, name, usinguid)
 
5423
+char *tag;
 
5424
+char *sequence;
 
5425
+char *name;
 
5426
+int usinguid;
 
5427
+{
 
5428
+    int r;
 
5429
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
5430
+    char *copyuid;
 
5431
+
 
5432
+    r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
5433
+                                              imapd_userid, mailboxname);
 
5434
+    if (!r) {
 
5435
+       r = index_copy(imapd_mailbox, sequence, usinguid, mailboxname,
 
5436
+                      &copyuid, !config_getswitch(IMAPOPT_SINGLEINSTANCESTORE));
 
5437
+    }
 
5438
+
 
5439
+    index_check(imapd_mailbox, usinguid, 0);
 
5440
+
 
5441
+    if (r && !(usinguid && r == IMAP_NO_NOSUCHMSG)) {
 
5442
+       prot_printf(imapd_out, "%s NO %s%s\r\n", tag,
 
5443
+                   (r == IMAP_MAILBOX_NONEXISTENT &&
 
5444
+                    mboxlist_createmailboxcheck(mailboxname, 0, 0,
 
5445
+                                                imapd_userisadmin,
 
5446
+                                                imapd_userid, imapd_authstate,
 
5447
+                                                (char **)0, (char **)0) == 0)
 
5448
+                   ? "[TRYCREATE] " : "", error_message(r));
 
5449
+    }
 
5450
+    else if (copyuid) {
 
5451
+           prot_printf(imapd_out, "%s OK [COPYUID %s] %s\r\n", tag,
 
5452
+                       copyuid, error_message(IMAP_OK_COMPLETED));
 
5453
+           free(copyuid);
 
5454
+    }
 
5455
+    else {
 
5456
+       prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
5457
+                   error_message(IMAP_OK_COMPLETED));
 
5458
+    }
 
5459
+}    
 
5460
+
 
5461
+/*
 
5462
+ * Perform an EXPUNGE command
 
5463
+ */
 
5464
+void
 
5465
+cmd_expunge(tag, sequence)
 
5466
+char *tag;
 
5467
+char *sequence;
 
5468
+{
 
5469
+    int r;
 
5470
+
 
5471
+    if (!(imapd_mailbox->myrights & ACL_DELETE)) r = IMAP_PERMISSION_DENIED;
 
5472
+    else if (sequence) {
 
5473
+       r = mailbox_expunge(imapd_mailbox, 1, index_expungeuidlist, sequence);
 
5474
+    }
 
5475
+    else {
 
5476
+       r = mailbox_expunge(imapd_mailbox, 1, (mailbox_decideproc_t *)0,
 
5477
+                           (void *)0);
 
5478
+    }
 
5479
+
 
5480
+    index_check(imapd_mailbox, 0, 0);
 
5481
+
 
5482
+    if (r) {
 
5483
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
5484
+    }
 
5485
+    else {
 
5486
+       prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
5487
+                   error_message(IMAP_OK_COMPLETED));
 
5488
+    }
 
5489
+}    
 
5490
+
 
5491
+/*
 
5492
+ * Perform a CREATE command
 
5493
+ */
 
5494
+void
 
5495
+cmd_create(char *tag, char *name, char *partition, int localonly)
 
5496
+{
 
5497
+    int r = 0;
 
5498
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
5499
+    int autocreatequota;
 
5500
+
 
5501
+    if (partition && !imapd_userisadmin) {
 
5502
+       r = IMAP_PERMISSION_DENIED;
 
5503
+    }
 
5504
+
 
5505
+    if (name[0] && name[strlen(name)-1] == imapd_namespace.hier_sep) {
 
5506
+       /* We don't care about trailing hierarchy delimiters. */
 
5507
+       name[strlen(name)-1] = '\0';
 
5508
+    }
 
5509
+
 
5510
+    if (!r) {
 
5511
+       r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
5512
+                                                  imapd_userid, mailboxname);
 
5513
+    }
 
5514
+
 
5515
+    if (!r) {
 
5516
+       /* xxx we do forced user creates on LOCALCREATE to facilitate
 
5517
+        * mailbox moves */
 
5518
+       r = mboxlist_createmailbox(mailboxname, 0, partition,
 
5519
+                                  imapd_userisadmin, 
 
5520
+                                  imapd_userid, imapd_authstate,
 
5521
+                                  localonly, localonly, 0);
 
5522
+
 
5523
+       if (r == IMAP_PERMISSION_DENIED && !strcasecmp(name, "INBOX") &&
 
5524
+           (autocreatequota = config_getint(IMAPOPT_AUTOCREATEQUOTA))) {
 
5525
+
 
5526
+           /* Auto create */
 
5527
+           r = mboxlist_createmailbox(mailboxname, 0,
 
5528
+                                      partition, 1, imapd_userid,
 
5529
+                                      imapd_authstate, 0, 0, 0);
 
5530
+           
 
5531
+           if (!r && autocreatequota > 0) {
 
5532
+               (void) mboxlist_setquota(mailboxname, autocreatequota, 0);
 
5533
+           }
 
5534
+       }
 
5535
+    }
 
5536
+
 
5537
+    if (imapd_mailbox) {
 
5538
+       index_check(imapd_mailbox, 0, 0);
 
5539
+    }
 
5540
+
 
5541
+    if (r) {
 
5542
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
5543
+    }
 
5544
+    else {
 
5545
+       prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
5546
+                   error_message(IMAP_OK_COMPLETED));
 
5547
+    }
 
5548
+}      
 
5549
+
 
5550
+/* Callback for use by cmd_delete */
 
5551
+static int delmbox(char *name,
 
5552
+                  int matchlen __attribute__((unused)),
 
5553
+                  int maycreate __attribute__((unused)),
 
5554
+                  void *rock __attribute__((unused)))
 
5555
+{
 
5556
+    int r;
 
5557
+
 
5558
+    r = mboxlist_deletemailbox(name, imapd_userisadmin,
 
5559
+                              imapd_userid, imapd_authstate,
 
5560
+                              0, 0, 0);
 
5561
+    
 
5562
+    if(r) {
 
5563
+       prot_printf(imapd_out, "* NO delete %s: %s\r\n",
 
5564
+                   name, error_message(r));
 
5565
+    }
 
5566
+    
 
5567
+    return 0;
 
5568
+}
 
5569
+
 
5570
+/*
 
5571
+ * Perform a DELETE command
 
5572
+ */
 
5573
+void cmd_delete(char *tag, char *name, int localonly)
 
5574
+{
 
5575
+    int r;
 
5576
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
5577
+    char *p;
 
5578
+    int domainlen = 0;
 
5579
+
 
5580
+    r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
5581
+                                              imapd_userid, mailboxname);
 
5582
+
 
5583
+    if (!r) {
 
5584
+       if (config_virtdomains && (p = strchr(mailboxname, '!')))
 
5585
+           domainlen = p - mailboxname + 1;
 
5586
+
 
5587
+       r = mboxlist_deletemailbox(mailboxname, imapd_userisadmin,
 
5588
+                                  imapd_userid, imapd_authstate, 1,
 
5589
+                                  localonly, 0);
 
5590
+    }
 
5591
+
 
5592
+    /* was it a top-level user mailbox? */
 
5593
+    /* localonly deletes are only per-mailbox */
 
5594
+    if (!r && !localonly &&
 
5595
+       !strncmp(mailboxname+domainlen, "user.", 5) &&
 
5596
+       !strchr(mailboxname+domainlen+5, '.')) {
 
5597
+       int mailboxname_len = strlen(mailboxname);
 
5598
+
 
5599
+       /* If we aren't too close to MAX_MAILBOX_NAME, append .* */
 
5600
+       p = mailboxname + mailboxname_len; /* end of mailboxname */
 
5601
+       if (mailboxname_len < sizeof(mailboxname) - 3) {
 
5602
+           strcpy(p, ".*");
 
5603
+       }
 
5604
+       
 
5605
+       /* build a list of mailboxes - we're using internal names here */
 
5606
+       mboxlist_findall(NULL, mailboxname, imapd_userisadmin, imapd_userid,
 
5607
+                        imapd_authstate, delmbox, NULL);
 
5608
+
 
5609
+       /* take care of deleting ACLs, subscriptions, seen state and quotas */
 
5610
+       *p = '\0'; /* clip off pattern */
 
5611
+       if ((!domainlen) || 
 
5612
+           (domainlen+1 < (sizeof(mailboxname) - mailboxname_len))) {
 
5613
+           if (domainlen) {
 
5614
+               /* fully qualify the userid */
 
5615
+               snprintf(p, (sizeof(mailboxname) - mailboxname_len), "@%.*s", 
 
5616
+                        domainlen-1, mailboxname);
 
5617
+           }
 
5618
+           user_deletedata(mailboxname+domainlen+5, imapd_userid,
 
5619
+                           imapd_authstate, 1);
 
5620
+       }
 
5621
+    }
 
5622
+
 
5623
+    if (imapd_mailbox) {
 
5624
+       index_check(imapd_mailbox, 0, 0);
 
5625
+    }
 
5626
+
 
5627
+    if (r) {
 
5628
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
5629
+    }
 
5630
+    else {
 
5631
+       prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
5632
+                   error_message(IMAP_OK_COMPLETED));
 
5633
+    }
 
5634
+}      
 
5635
+
 
5636
+struct renrock 
 
5637
+{
 
5638
+    int ol;
 
5639
+    int nl;
 
5640
+    int rename_user;
 
5641
+    char *olduser, *newuser;
 
5642
+    char *acl_olduser, *acl_newuser;
 
5643
+    char *newmailboxname;
 
5644
+    char *partition;
 
5645
+};
 
5646
+
 
5647
+/* Callback for use by cmd_rename */
 
5648
+static int renmbox(char *name,
 
5649
+                  int matchlen __attribute__((unused)),
 
5650
+                  int maycreate __attribute__((unused)),
 
5651
+                  void *rock)
 
5652
+{
 
5653
+    char oldextname[MAX_MAILBOX_NAME+1];
 
5654
+    char newextname[MAX_MAILBOX_NAME+1];
 
5655
+    struct renrock *text = (struct renrock *)rock;
 
5656
+    int r;
 
5657
+
 
5658
+    if((text->nl + strlen(name + text->ol)) > MAX_MAILBOX_NAME)
 
5659
+       return 0;
 
5660
+
 
5661
+    strcpy(text->newmailboxname + text->nl, name + text->ol);
 
5662
+
 
5663
+    r = mboxlist_renamemailbox(name, text->newmailboxname,
 
5664
+                              text->partition,
 
5665
+                              1, imapd_userid, imapd_authstate);
 
5666
+    
 
5667
+    (*imapd_namespace.mboxname_toexternal)(&imapd_namespace,
 
5668
+                                          name,
 
5669
+                                          imapd_userid, oldextname);
 
5670
+    (*imapd_namespace.mboxname_toexternal)(&imapd_namespace,
 
5671
+                                          text->newmailboxname,
 
5672
+                                          imapd_userid, newextname);
 
5673
+
 
5674
+    if(r) {
 
5675
+       prot_printf(imapd_out, "* NO rename %s %s: %s\r\n",
 
5676
+                   oldextname, newextname, error_message(r));
 
5677
+       if (RENAME_STOP_ON_ERROR) return r;
 
5678
+    } else {
 
5679
+       /* If we're renaming a user, change quotaroot and ACL */
 
5680
+       if (text->rename_user) {
 
5681
+           user_copyquotaroot(name, text->newmailboxname);
 
5682
+           user_renameacl(text->newmailboxname,
 
5683
+                          text->acl_olduser, text->acl_newuser);
 
5684
+       }
 
5685
+
 
5686
+       /* Rename mailbox annotations */
 
5687
+       annotatemore_rename(name, text->newmailboxname,
 
5688
+                           text->rename_user ? text->olduser : NULL,
 
5689
+                           text->newuser);
 
5690
+       
 
5691
+       prot_printf(imapd_out, "* OK rename %s %s\r\n",
 
5692
+                   oldextname, newextname);
 
5693
+    }
 
5694
+
 
5695
+    prot_flush(imapd_out);
 
5696
+
 
5697
+    return 0;
 
5698
+}
 
5699
+
 
5700
+/*
 
5701
+ * Perform a RENAME command
 
5702
+ */
 
5703
+void cmd_rename(const char *tag, 
 
5704
+               char *oldname, char *newname, char *partition)
 
5705
+{
 
5706
+    int r = 0;
 
5707
+    char oldmailboxname[MAX_MAILBOX_NAME+3];
 
5708
+    char newmailboxname[MAX_MAILBOX_NAME+2];
 
5709
+    char oldextname[MAX_MAILBOX_NAME+1];
 
5710
+    char newextname[MAX_MAILBOX_NAME+1];
 
5711
+    int omlen, nmlen;
 
5712
+    char *p;
 
5713
+    int recursive_rename = 1;
 
5714
+    int rename_user = 0;
 
5715
+    char olduser[128], newuser[128];
 
5716
+    char acl_olduser[128], acl_newuser[128];
 
5717
+
 
5718
+    /* canonicalize names */
 
5719
+    if (partition && !imapd_userisadmin) {
 
5720
+       r = IMAP_PERMISSION_DENIED;
 
5721
+    }
 
5722
+
 
5723
+    if (!r)
 
5724
+       r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, oldname,
 
5725
+                                                  imapd_userid, oldmailboxname);
 
5726
+    if (!r)
 
5727
+       r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, newname,
 
5728
+                                                  imapd_userid, newmailboxname);
 
5729
+
 
5730
+    /* if this is my inbox, don't do recursive renames */
 
5731
+    if (!strcasecmp(oldname, "inbox")) {
 
5732
+       recursive_rename = 0;
 
5733
+    }
 
5734
+    /* check if we're an admin renaming a user */
 
5735
+    else if (config_getswitch(IMAPOPT_ALLOWUSERMOVES) &&
 
5736
+            mboxname_isusermailbox(oldmailboxname, 1) &&
 
5737
+            mboxname_isusermailbox(newmailboxname, 1) &&
 
5738
+            strcmp(oldmailboxname, newmailboxname) && /* different user */
 
5739
+            imapd_userisadmin) {
 
5740
+       rename_user = 1;
 
5741
+    }
 
5742
+
 
5743
+    /* if we're renaming something inside of something else, 
 
5744
+       don't recursively rename stuff */
 
5745
+    omlen = strlen(oldmailboxname);
 
5746
+    nmlen = strlen(newmailboxname);
 
5747
+    if (omlen < nmlen) {
 
5748
+       if (!strncmp(oldmailboxname, newmailboxname, omlen) &&
 
5749
+           newmailboxname[omlen] == '.') {
 
5750
+           recursive_rename = 0;
 
5751
+       }
 
5752
+    } else {
 
5753
+       if (!strncmp(oldmailboxname, newmailboxname, nmlen) &&
 
5754
+           oldmailboxname[nmlen] == '.') {
 
5755
+           recursive_rename = 0;
 
5756
+       }
 
5757
+    }
 
5758
+
 
5759
+    /* verify that the mailbox doesn't have a wildcard in it */
 
5760
+    for (p = oldmailboxname; !r && *p; p++) {
 
5761
+       if (*p == '*' || *p == '%') r = IMAP_MAILBOX_BADNAME;
 
5762
+    }
 
5763
+
 
5764
+    /* attempt to rename the base mailbox */
 
5765
+    if (!r) {
 
5766
+       r = mboxlist_renamemailbox(oldmailboxname, newmailboxname, partition,
 
5767
+                                  imapd_userisadmin, 
 
5768
+                                  imapd_userid, imapd_authstate);
 
5769
+    }
 
5770
+
 
5771
+    /* If we're renaming a user, take care of changing quotaroot, ACL,
 
5772
+       seen state, subscriptions and sieve scripts */
 
5773
+    if (!r && rename_user) {
 
5774
+       char *domain;
 
5775
+
 
5776
+       /* create canonified userids */
 
5777
+
 
5778
+       domain = strchr(oldmailboxname, '!');
 
5779
+       strcpy(olduser, domain ? domain+6 : oldmailboxname+5);
 
5780
+       if (domain)
 
5781
+           sprintf(olduser+strlen(olduser), "@%.*s",
 
5782
+                   domain - oldmailboxname, oldmailboxname);
 
5783
+       strcpy(acl_olduser, olduser);
 
5784
+
 
5785
+       /* Translate any separators in source old userid (for ACLs) */
 
5786
+       mboxname_hiersep_toexternal(&imapd_namespace, acl_olduser,
 
5787
+                                   config_virtdomains ?
 
5788
+                                   strcspn(acl_olduser, "@") : 0);
 
5789
+
 
5790
+       domain = strchr(newmailboxname, '!');
 
5791
+       strcpy(newuser, domain ? domain+6 : newmailboxname+5);
 
5792
+       if (domain)
 
5793
+           sprintf(newuser+strlen(newuser), "@%.*s",
 
5794
+                   domain - newmailboxname, newmailboxname);
 
5795
+       strcpy(acl_newuser, newuser);
 
5796
+
 
5797
+       /* Translate any separators in destination new userid (for ACLs) */
 
5798
+       mboxname_hiersep_toexternal(&imapd_namespace, acl_newuser,
 
5799
+                                   config_virtdomains ?
 
5800
+                                   strcspn(acl_newuser, "@") : 0);
 
5801
+
 
5802
+       user_copyquotaroot(oldmailboxname, newmailboxname);
 
5803
+       user_renameacl(newmailboxname, acl_olduser, acl_newuser);
 
5804
+       user_renamedata(olduser, newuser, imapd_userid, imapd_authstate);
 
5805
+
 
5806
+       /* XXX report status/progress of meta-data */
 
5807
+    }
 
5808
+
 
5809
+    if (!r) {
 
5810
+       /* Rename mailbox annotations */
 
5811
+       annotatemore_rename(oldmailboxname, newmailboxname,
 
5812
+                           rename_user ? olduser : NULL,
 
5813
+                           newuser);
 
5814
+    }
 
5815
+
 
5816
+    /* rename all mailboxes matching this */
 
5817
+    if (!r && recursive_rename) {
 
5818
+       struct renrock rock;
 
5819
+       int ol = omlen + 1;
 
5820
+       int nl = nmlen + 1;
 
5821
+
 
5822
+       (*imapd_namespace.mboxname_toexternal)(&imapd_namespace,
 
5823
+                                              oldmailboxname,
 
5824
+                                              imapd_userid, oldextname);
 
5825
+       (*imapd_namespace.mboxname_toexternal)(&imapd_namespace,
 
5826
+                                              newmailboxname,
 
5827
+                                              imapd_userid, newextname);
 
5828
+
 
5829
+       prot_printf(imapd_out, "* OK rename %s %s\r\n",
 
5830
+                   oldextname, newextname);
 
5831
+       prot_flush(imapd_out);
 
5832
+
 
5833
+       strcat(oldmailboxname, ".*");
 
5834
+       strcat(newmailboxname, ".");
 
5835
+
 
5836
+       /* setup the rock */
 
5837
+       rock.newmailboxname = newmailboxname;
 
5838
+       rock.ol = ol;
 
5839
+       rock.nl = nl;
 
5840
+       rock.olduser = olduser;
 
5841
+       rock.newuser = newuser;
 
5842
+       rock.acl_olduser = acl_olduser;
 
5843
+       rock.acl_newuser = acl_newuser;
 
5844
+       rock.partition = partition;
 
5845
+       rock.rename_user = rename_user;
 
5846
+       
 
5847
+       /* add submailboxes; we pretend we're an admin since we successfully
 
5848
+          renamed the parent - we're using internal names here */
 
5849
+       r = mboxlist_findall(NULL, oldmailboxname, 1, imapd_userid,
 
5850
+                            imapd_authstate, renmbox, &rock);
 
5851
+    }
 
5852
+
 
5853
+    /* take care of deleting old ACLs, subscriptions, seen state and quotas */
 
5854
+    if (!r && rename_user)
 
5855
+       user_deletedata(olduser, imapd_userid, imapd_authstate, 1);
 
5856
+
 
5857
+    if (imapd_mailbox) {
 
5858
+       index_check(imapd_mailbox, 0, 0);
 
5859
+    }
 
5860
+
 
5861
+    if (r) {
 
5862
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
5863
+    } else {
 
5864
+       prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
5865
+                   error_message(IMAP_OK_COMPLETED));
 
5866
+    }
 
5867
+}      
 
5868
+
 
5869
+/*
 
5870
+ * Perform a RECONSTRUCT command
 
5871
+ */
 
5872
+void
 
5873
+cmd_reconstruct(const char *tag, const char *name, int recursive)
 
5874
+{
 
5875
+    int r = 0;
 
5876
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
5877
+    char quotaroot[MAX_MAILBOX_NAME+1];
 
5878
+    struct mailbox mailbox;
 
5879
+
 
5880
+    /* administrators only please */
 
5881
+    if (!imapd_userisadmin) {
 
5882
+       r = IMAP_PERMISSION_DENIED;
 
5883
+    }
 
5884
+
 
5885
+    if (!r) {
 
5886
+       r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
5887
+                                                  imapd_userid, mailboxname);
 
5888
+    }
 
5889
+    
 
5890
+    if (!r) {
 
5891
+       r = mlookup(tag, name, mailboxname, NULL, NULL, NULL, NULL, NULL);
 
5892
+    }
 
5893
+    if (r == IMAP_MAILBOX_MOVED) return;
 
5894
+
 
5895
+    if (!r) {
 
5896
+       int pid;
 
5897
+           
 
5898
+       /* Reconstruct it */
 
5899
+
 
5900
+       pid = fork();
 
5901
+       if(pid == -1) {
 
5902
+           r = IMAP_SYS_ERROR;
 
5903
+       } else if(pid == 0) {
 
5904
+           char buf[4096];
 
5905
+           int ret;
 
5906
+           
 
5907
+           /* Child - exec reconstruct*/           
 
5908
+           syslog(LOG_NOTICE, "Reconstructing '%s' (%s) for user '%s'",
 
5909
+                  mailboxname, recursive ? "recursive" : "not recursive",
 
5910
+                  imapd_userid);
 
5911
+
 
5912
+           fclose(stdin);
 
5913
+           fclose(stdout);
 
5914
+           fclose(stderr);
 
5915
+
 
5916
+           ret = snprintf(buf, sizeof(buf), "%s/reconstruct", SERVICE_PATH);
 
5917
+           if(ret < 0 || ret >= sizeof(buf)) {
 
5918
+               /* in child, so fatailing won't disconnect our user */ 
 
5919
+               fatal("reconstruct buffer not sufficiently big", EC_CONFIG);
 
5920
+           }
 
5921
+
 
5922
+           if(recursive) {
 
5923
+               execl(buf, buf, "-C", config_filename, "-r", "-f",
 
5924
+                     mailboxname, NULL);
 
5925
+           } else {
 
5926
+               execl(buf, buf, "-C", config_filename, mailboxname, NULL);
 
5927
+           }
 
5928
+           
 
5929
+           /* if we are here, we have a problem */
 
5930
+           exit(-1);
 
5931
+       } else {
 
5932
+           int status;
 
5933
+
 
5934
+           /* Parent, wait on child */
 
5935
+           if(waitpid(pid, &status, 0) < 0) r = IMAP_SYS_ERROR;
 
5936
+
 
5937
+           /* Did we fail? */
 
5938
+           if(WEXITSTATUS(status) != 0) r = IMAP_SYS_ERROR;
 
5939
+       }
 
5940
+    }
 
5941
+
 
5942
+    /* Still in parent, need to re-quota the mailbox*/
 
5943
+
 
5944
+    /* Find its quota root */
 
5945
+    if (!r) {
 
5946
+       r = mailbox_open_header(mailboxname, imapd_authstate, &mailbox);
 
5947
+    }
 
5948
+
 
5949
+    if(!r) {
 
5950
+       if(mailbox.quota.root) {
 
5951
+           strcpy(quotaroot, mailbox.quota.root);
 
5952
+       } else {
 
5953
+           strcpy(quotaroot, mailboxname);
 
5954
+       }
 
5955
+       mailbox_close(&mailbox);
 
5956
+    }
 
5957
+    
 
5958
+    /* Run quota -f */
 
5959
+    if (!r) {
 
5960
+       int pid;
 
5961
+
 
5962
+       pid = fork();
 
5963
+       if(pid == -1) {
 
5964
+           r = IMAP_SYS_ERROR;
 
5965
+       } else if(pid == 0) {
 
5966
+           char buf[4096];
 
5967
+           int ret;
 
5968
+           
 
5969
+           /* Child - exec reconstruct*/           
 
5970
+           syslog(LOG_NOTICE,
 
5971
+                  "Regenerating quota roots starting with '%s' for user '%s'",
 
5972
+                  mailboxname, imapd_userid);
 
5973
+
 
5974
+           fclose(stdin);
 
5975
+           fclose(stdout);
 
5976
+           fclose(stderr);
 
5977
+
 
5978
+           ret = snprintf(buf, sizeof(buf), "%s/quota", SERVICE_PATH);
 
5979
+           if(ret < 0 || ret >= sizeof(buf)) {
 
5980
+               /* in child, so fatailing won't disconnect our user */ 
 
5981
+               fatal("quota buffer not sufficiently big", EC_CONFIG);
 
5982
+           }
 
5983
+
 
5984
+           execl(buf, buf, "-C", config_filename, "-f", quotaroot, NULL);
 
5985
+           
 
5986
+           /* if we are here, we have a problem */
 
5987
+           exit(-1);
 
5988
+       } else {
 
5989
+           int status;
 
5990
+
 
5991
+           /* Parent, wait on child */
 
5992
+           if(waitpid(pid, &status, 0) < 0) r = IMAP_SYS_ERROR;
 
5993
+
 
5994
+           /* Did we fail? */
 
5995
+           if(WEXITSTATUS(status) != 0) r = IMAP_SYS_ERROR;
 
5996
+       }
 
5997
+    }
 
5998
+
 
5999
+    if (r) {
 
6000
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
6001
+    } else {
 
6002
+       prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
6003
+                   error_message(IMAP_OK_COMPLETED));
 
6004
+    }
 
6005
+}      
 
6006
+
 
6007
+/*
 
6008
+ * Perform a FIND command
 
6009
+ */
 
6010
+void
 
6011
+cmd_find(tag, namespace, pattern)
 
6012
+char *tag;
 
6013
+char *namespace;
 
6014
+char *pattern;
 
6015
+{
 
6016
+    char *p;
 
6017
+    lcase(namespace);
 
6018
+
 
6019
+    for (p = pattern; *p; p++) {
 
6020
+       if (*p == '%') *p = '?';
 
6021
+    }
 
6022
+
 
6023
+    /* Translate any separators in pattern */
 
6024
+    mboxname_hiersep_tointernal(&imapd_namespace, pattern,
 
6025
+                               config_virtdomains ?
 
6026
+                               strcspn(pattern, "@") : 0);
 
6027
+
 
6028
+    if (!strcasecmp(namespace, "mailboxes")) {
 
6029
+       int force = config_getswitch(IMAPOPT_ALLOWALLSUBSCRIBE);
 
6030
+
 
6031
+       (*imapd_namespace.mboxlist_findsub)(&imapd_namespace, pattern,
 
6032
+                                           imapd_userisadmin, imapd_userid,
 
6033
+                                           imapd_authstate, mailboxdata,
 
6034
+                                           NULL, force);
 
6035
+    }
 
6036
+    else if (!strcasecmp(namespace, "all.mailboxes")) {
 
6037
+       (*imapd_namespace.mboxlist_findall)(&imapd_namespace, pattern,
 
6038
+                                           imapd_userisadmin, imapd_userid,
 
6039
+                                           imapd_authstate, mailboxdata, NULL);
 
6040
+    }
 
6041
+    else if (!strcasecmp(namespace, "bboards")
 
6042
+            || !strcasecmp(namespace, "all.bboards")) {
 
6043
+       ;
 
6044
+    }
 
6045
+    else {
 
6046
+       prot_printf(imapd_out, "%s BAD Invalid FIND subcommand\r\n", tag);
 
6047
+       return;
 
6048
+    }
 
6049
+    prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
6050
+               error_message(IMAP_OK_COMPLETED));
 
6051
+}
 
6052
+
 
6053
+static int mstringdatacalls;
 
6054
+
 
6055
+/*
 
6056
+ * Perform a LIST or LSUB command
 
6057
+ */
 
6058
+void cmd_list(char *tag, int listopts, char *reference, char *pattern)
 
6059
+{
 
6060
+    char *buf = NULL;
 
6061
+    int patlen = 0;
 
6062
+    int reflen = 0;
 
6063
+    static int ignorereference = 0;
 
6064
+    clock_t start = clock();
 
6065
+    char mytime[100];
 
6066
+    int (*findall)(struct namespace *namespace,
 
6067
+                  const char *pattern, int isadmin, char *userid, 
 
6068
+                  struct auth_state *auth_state, int (*proc)(),
 
6069
+                  void *rock);
 
6070
+    int (*findsub)(struct namespace *namespace,
 
6071
+                  const char *pattern, int isadmin, char *userid, 
 
6072
+                  struct auth_state *auth_state, int (*proc)(),
 
6073
+                  void *rock, int force);
 
6074
+
 
6075
+    /* Ignore the reference argument?
 
6076
+       (the behavior in 1.5.10 & older) */
 
6077
+    if (ignorereference == 0) {
 
6078
+       ignorereference = config_getswitch(IMAPOPT_IGNOREREFERENCE);
 
6079
+    }
 
6080
+
 
6081
+    /* Reset state in mstringdata */
 
6082
+    mstringdata(NULL, NULL, 0, 0, 0);
 
6083
+
 
6084
+    if (!pattern[0] && !(listopts & LIST_LSUB)) {
 
6085
+       /* Special case: query top-level hierarchy separator */
 
6086
+       prot_printf(imapd_out, "* LIST (\\Noselect) \"%c\" \"\"\r\n",
 
6087
+                   imapd_namespace.hier_sep);
 
6088
+    } else {
 
6089
+       /* Do we need to concatenate fields? */
 
6090
+       if (!ignorereference || pattern[0] == imapd_namespace.hier_sep) {
 
6091
+           /* Either
 
6092
+            * - name begins with dot
 
6093
+            * - we're configured to honor the reference argument */
 
6094
+
 
6095
+           /* Allocate a buffer, figure out how to stick the arguments
 
6096
+              together, do it, then do that instead of using pattern. */
 
6097
+           patlen = strlen(pattern);
 
6098
+           reflen = strlen(reference);
 
6099
+           
 
6100
+           buf = xmalloc(patlen + reflen + 1);
 
6101
+           buf[0] = '\0';
 
6102
+
 
6103
+           if (*reference) {
 
6104
+               /* check for LIST A. .B, change to LIST "" A.B */
 
6105
+               if (reference[reflen-1] == imapd_namespace.hier_sep &&
 
6106
+                   pattern[0] == imapd_namespace.hier_sep) {
 
6107
+                   reference[--reflen] = '\0';
 
6108
+               }
 
6109
+               strcpy(buf, reference);
 
6110
+           }
 
6111
+           strcat(buf, pattern);
 
6112
+           pattern = buf;
 
6113
+       }
 
6114
+
 
6115
+       /* Translate any separators in pattern */
 
6116
+       mboxname_hiersep_tointernal(&imapd_namespace, pattern,
 
6117
+                                   config_virtdomains ?
 
6118
+                                   strcspn(pattern, "@") : 0);
 
6119
+
 
6120
+       /* Check to see if we should only list the personal namespace */
 
6121
+       if (!strcmp(pattern, "*")
 
6122
+           && config_getswitch(IMAPOPT_FOOLSTUPIDCLIENTS)) {
 
6123
+           if (buf) free(buf);
 
6124
+           buf = xstrdup("INBOX*");
 
6125
+           pattern = buf;
 
6126
+           findsub = mboxlist_findsub;
 
6127
+           findall = mboxlist_findall;
 
6128
+       }
 
6129
+       else {
 
6130
+           findsub = imapd_namespace.mboxlist_findsub;
 
6131
+           findall = imapd_namespace.mboxlist_findall;
 
6132
+       }
 
6133
+
 
6134
+       if (listopts & (LIST_LSUB | LIST_SUBSCRIBED)) {
 
6135
+           int force = config_getswitch(IMAPOPT_ALLOWALLSUBSCRIBE);
 
6136
+
 
6137
+           (*findsub)(&imapd_namespace, pattern,
 
6138
+                      imapd_userisadmin, imapd_userid, imapd_authstate,
 
6139
+                      listdata, &listopts, force);
 
6140
+       }
 
6141
+       else {
 
6142
+           (*findall)(&imapd_namespace, pattern,
 
6143
+                      imapd_userisadmin, imapd_userid, imapd_authstate,
 
6144
+                      listdata, &listopts);
 
6145
+       }
 
6146
+
 
6147
+       listdata((char *)0, 0, 0, &listopts);
 
6148
+
 
6149
+       if (buf) free(buf);
 
6150
+    }
 
6151
+    snprintf(mytime, sizeof(mytime), "%2.3f",
 
6152
+            (clock() - start) / (double) CLOCKS_PER_SEC);
 
6153
+    prot_printf(imapd_out, "%s OK %s (%s secs %d calls)\r\n", tag,
 
6154
+               error_message(IMAP_OK_COMPLETED), mytime, mstringdatacalls);
 
6155
+}
 
6156
+  
 
6157
+/*
 
6158
+ * Perform a SUBSCRIBE (add is nonzero) or
 
6159
+ * UNSUBSCRIBE (add is zero) command
 
6160
+ */
 
6161
+void cmd_changesub(char *tag, char *namespace, 
 
6162
+                  char *name, int add)
 
6163
+{
 
6164
+    int r;
 
6165
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
6166
+    int force = config_getswitch(IMAPOPT_ALLOWALLSUBSCRIBE);
 
6167
+
 
6168
+    if (namespace) lcase(namespace);
 
6169
+    if (!namespace || !strcmp(namespace, "mailbox")) {
 
6170
+       int len = strlen(name);
 
6171
+       if (force && imapd_namespace.isalt &&
 
6172
+           (((len == strlen(imapd_namespace.prefix[NAMESPACE_USER]) - 1) &&
 
6173
+             !strncmp(name, imapd_namespace.prefix[NAMESPACE_USER], len)) ||
 
6174
+            ((len == strlen(imapd_namespace.prefix[NAMESPACE_SHARED]) - 1) &&
 
6175
+             !strncmp(name, imapd_namespace.prefix[NAMESPACE_SHARED], len)))) {
 
6176
+           r = 0;
 
6177
+       }
 
6178
+       else {
 
6179
+           r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
6180
+                                                      imapd_userid, mailboxname);
 
6181
+           if (!r) {
 
6182
+               r = mboxlist_changesub(mailboxname, imapd_userid, 
 
6183
+                                      imapd_authstate, add, force);
 
6184
+           }
 
6185
+       }
 
6186
+    }
 
6187
+    else if (!strcmp(namespace, "bboard")) {
 
6188
+       r = add ? IMAP_MAILBOX_NONEXISTENT : 0;
 
6189
+    }
 
6190
+    else {
 
6191
+       prot_printf(imapd_out, "%s BAD Invalid %s subcommand\r\n", tag,
 
6192
+              add ? "Subscribe" : "Unsubscribe");
 
6193
+       return;
 
6194
+    }
 
6195
+
 
6196
+    if (r) {
 
6197
+       prot_printf(imapd_out, "%s NO %s: %s\r\n", tag,
 
6198
+              add ? "Subscribe" : "Unsubscribe", error_message(r));
 
6199
+    }
 
6200
+    else {
 
6201
+       prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
6202
+                   error_message(IMAP_OK_COMPLETED));
 
6203
+    }
 
6204
+}
 
6205
+
 
6206
+/*
 
6207
+ * Perform a GETACL command
 
6208
+ */
 
6209
+void cmd_getacl(const char *tag, const char *name)
 
6210
+{
 
6211
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
6212
+    int r, access;
 
6213
+    char *acl;
 
6214
+    char *rights, *nextid;
 
6215
+
 
6216
+    r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
6217
+                                              imapd_userid, mailboxname);
 
6218
+
 
6219
+    if (!r) {
 
6220
+       r = mlookup(tag, name, mailboxname, NULL, NULL, NULL, &acl, NULL);
 
6221
+    }
 
6222
+    if (r == IMAP_MAILBOX_MOVED) return;
 
6223
+
 
6224
+    if (!r) {
 
6225
+       access = cyrus_acl_myrights(imapd_authstate, acl);
 
6226
+
 
6227
+       if (!(access & (ACL_READ|ACL_ADMIN)) &&
 
6228
+           !imapd_userisadmin &&
 
6229
+           !mboxname_userownsmailbox(imapd_userid, mailboxname)) {
 
6230
+           r = (access&ACL_LOOKUP) ?
 
6231
+             IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
 
6232
+       }
 
6233
+    }
 
6234
+    if (r) {
 
6235
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
6236
+       return;
 
6237
+    }
 
6238
+    
 
6239
+    prot_printf(imapd_out, "* ACL ");
 
6240
+    printastring(name);
 
6241
+    
 
6242
+    while (acl) {
 
6243
+       rights = strchr(acl, '\t');
 
6244
+       if (!rights) break;
 
6245
+       *rights++ = '\0';
 
6246
+       
 
6247
+       nextid = strchr(rights, '\t');
 
6248
+       if (!nextid) break;
 
6249
+       *nextid++ = '\0';
 
6250
+       
 
6251
+       prot_printf(imapd_out, " ");
 
6252
+       printastring(acl);
 
6253
+       prot_printf(imapd_out, " ");
 
6254
+       printastring(rights);
 
6255
+       acl = nextid;
 
6256
+    }
 
6257
+    prot_printf(imapd_out, "\r\n");
 
6258
+    prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
6259
+               error_message(IMAP_OK_COMPLETED));
 
6260
+}
 
6261
+
 
6262
+/*
 
6263
+ * Perform a LISTRIGHTS command
 
6264
+ */
 
6265
+void
 
6266
+cmd_listrights(tag, name, identifier)
 
6267
+char *tag;
 
6268
+char *name;
 
6269
+char *identifier;
 
6270
+{
 
6271
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
6272
+    int r, rights;
 
6273
+    char *acl;
 
6274
+
 
6275
+    r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
6276
+                                              imapd_userid, mailboxname);
 
6277
+
 
6278
+    if (!r) {
 
6279
+       r = mlookup(tag, name, mailboxname, NULL, NULL, NULL, &acl, NULL);
 
6280
+    }
 
6281
+    if (r == IMAP_MAILBOX_MOVED) return;
 
6282
+
 
6283
+    if (!r) {
 
6284
+       rights = cyrus_acl_myrights(imapd_authstate, acl);
 
6285
+
 
6286
+       if (!rights && !imapd_userisadmin &&
 
6287
+           !mboxname_userownsmailbox(imapd_userid, mailboxname)) {
 
6288
+           r = IMAP_MAILBOX_NONEXISTENT;
 
6289
+       }
 
6290
+    }
 
6291
+
 
6292
+    if (!r) {
 
6293
+       struct auth_state *authstate = auth_newstate(identifier);
 
6294
+       char *canon_identifier;
 
6295
+       int canonidlen = 0;
 
6296
+       int implicit;
 
6297
+       char rightsdesc[100], optional[33];
 
6298
+
 
6299
+       if (global_authisa(authstate, IMAPOPT_ADMINS))
 
6300
+           canon_identifier = identifier; /* don't canonify global admins */
 
6301
+       else
 
6302
+           canon_identifier = canonify_userid(identifier, imapd_userid, NULL);
 
6303
+       auth_freestate(authstate);
 
6304
+
 
6305
+       if (canon_identifier) canonidlen = strlen(canon_identifier);
 
6306
+
 
6307
+       if (!canon_identifier) {
 
6308
+           implicit = 0;
 
6309
+       }
 
6310
+       else if (mboxname_userownsmailbox(canon_identifier, mailboxname)) {
 
6311
+           /* identifier's personal mailbox */
 
6312
+           implicit = config_implicitrights;
 
6313
+       }
 
6314
+       else if (mboxname_isusermailbox(mailboxname, 1)) {
 
6315
+           /* anyone can post to an INBOX */
 
6316
+           implicit = ACL_POST;
 
6317
+       }
 
6318
+       else {
 
6319
+           implicit = 0;
 
6320
+       }
 
6321
+
 
6322
+       /* calculate optional rights */
 
6323
+       cyrus_acl_masktostr(implicit ^ (canon_identifier ? ACL_FULL : 0),
 
6324
+                           optional);
 
6325
+
 
6326
+       /* build the rights string */
 
6327
+       if (implicit) {
 
6328
+           cyrus_acl_masktostr(implicit, rightsdesc);
 
6329
+       }
 
6330
+       else {
 
6331
+           strcpy(rightsdesc, "\"\"");
 
6332
+       }
 
6333
+
 
6334
+       if (*optional) {
 
6335
+           int i, n = strlen(optional);
 
6336
+           char *p = rightsdesc + strlen(rightsdesc);
 
6337
+
 
6338
+           for (i = 0; i < n; i++) {
 
6339
+               *p++ = ' ';
 
6340
+               *p++ = optional[i];
 
6341
+           }
 
6342
+           *p = '\0';
 
6343
+       }
 
6344
+
 
6345
+       prot_printf(imapd_out, "* LISTRIGHTS ");
 
6346
+       printastring(name);
 
6347
+       prot_putc(' ', imapd_out);
 
6348
+       printastring(identifier);
 
6349
+       prot_printf(imapd_out, " %s", rightsdesc);
 
6350
+
 
6351
+       prot_printf(imapd_out, "\r\n%s OK %s\r\n", tag,
 
6352
+                   error_message(IMAP_OK_COMPLETED));
 
6353
+       return;
 
6354
+    }
 
6355
+
 
6356
+    prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
6357
+}
 
6358
+
 
6359
+/*
 
6360
+ * Perform a MYRIGHTS command
 
6361
+ */
 
6362
+void cmd_myrights(const char *tag, const char *name)
 
6363
+{
 
6364
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
6365
+    int r, rights = 0;
 
6366
+    char *acl;
 
6367
+    char str[ACL_MAXSTR];
 
6368
+
 
6369
+    r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
6370
+                                              imapd_userid, mailboxname);
 
6371
+
 
6372
+    if (!r) {
 
6373
+       r = mlookup(tag, name, mailboxname, NULL, NULL, NULL, &acl, NULL);
 
6374
+    }
 
6375
+    if (r == IMAP_MAILBOX_MOVED) return;
 
6376
+
 
6377
+    if (!r) {
 
6378
+       rights = cyrus_acl_myrights(imapd_authstate, acl);
 
6379
+
 
6380
+       /* Add in implicit rights */
 
6381
+       if (imapd_userisadmin) {
 
6382
+           rights |= ACL_LOOKUP|ACL_ADMIN;
 
6383
+       }
 
6384
+       else if (mboxname_userownsmailbox(imapd_userid, mailboxname)) {
 
6385
+           rights |= config_implicitrights;
 
6386
+       }
 
6387
+
 
6388
+       if (!rights) {
 
6389
+           r = IMAP_MAILBOX_NONEXISTENT;
 
6390
+       }
 
6391
+    }
 
6392
+    if (r) {
 
6393
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
6394
+       return;
 
6395
+    }
 
6396
+    
 
6397
+    prot_printf(imapd_out, "* MYRIGHTS ");
 
6398
+    printastring(name);
 
6399
+    prot_printf(imapd_out, " ");
 
6400
+    printastring(cyrus_acl_masktostr(rights, str));
 
6401
+    prot_printf(imapd_out, "\r\n%s OK %s\r\n", tag,
 
6402
+               error_message(IMAP_OK_COMPLETED));
 
6403
+}
 
6404
+
 
6405
+/*
 
6406
+ * Perform a SETACL command
 
6407
+ */
 
6408
+void cmd_setacl(const char *tag, const char *name,
 
6409
+               const char *identifier, const char *rights)
 
6410
+{
 
6411
+    int r;
 
6412
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
6413
+
 
6414
+    r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
6415
+                                              imapd_userid, mailboxname);
 
6416
+
 
6417
+    /* is it remote? */
 
6418
+    if (!r) {
 
6419
+       r = mlookup(tag, name, mailboxname, NULL, NULL, NULL, NULL, NULL);
 
6420
+    }
 
6421
+    if (r == IMAP_MAILBOX_MOVED) return;
 
6422
+    
 
6423
+    if (!r) {
 
6424
+       r = mboxlist_setacl(mailboxname, identifier, rights,
 
6425
+                           imapd_userisadmin, imapd_userid, imapd_authstate);
 
6426
+    }
 
6427
+
 
6428
+    if (r) {
 
6429
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
6430
+       return;
 
6431
+    }
 
6432
+    
 
6433
+    prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
6434
+               error_message(IMAP_OK_COMPLETED));
 
6435
+}
 
6436
+
 
6437
+/*
 
6438
+ * Perform a GETQUOTA command
 
6439
+ */
 
6440
+void
 
6441
+cmd_getquota(const char *tag, const char *name)
 
6442
+{
 
6443
+    int r;
 
6444
+    struct quota quota;
 
6445
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
6446
+
 
6447
+    if (!imapd_userisadmin) r = IMAP_PERMISSION_DENIED;
 
6448
+    else {
 
6449
+       r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
6450
+                                                  imapd_userid, mailboxname);
 
6451
+       if (!r) {
 
6452
+           quota.root = mailboxname;
 
6453
+           r = quota_read(&quota, NULL, 0);
 
6454
+       }
 
6455
+    }
 
6456
+    
 
6457
+    if (!r) {
 
6458
+       prot_printf(imapd_out, "* QUOTA ");
 
6459
+       printastring(name);
 
6460
+       prot_printf(imapd_out, " (");
 
6461
+       if (quota.limit >= 0) {
 
6462
+           prot_printf(imapd_out, "STORAGE %lu %d",
 
6463
+                       quota.used/QUOTA_UNITS, quota.limit);
 
6464
+       }
 
6465
+       prot_printf(imapd_out, ")\r\n");
 
6466
+    }
 
6467
+
 
6468
+    if (r) {
 
6469
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
6470
+       return;
 
6471
+    }
 
6472
+    
 
6473
+    prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
6474
+               error_message(IMAP_OK_COMPLETED));
 
6475
+}
 
6476
+
 
6477
+
 
6478
+/*
 
6479
+ * Perform a GETQUOTAROOT command
 
6480
+ */
 
6481
+void
 
6482
+cmd_getquotaroot(const char *tag, const char *name)
 
6483
+{
 
6484
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
6485
+    struct mailbox mailbox;
 
6486
+    int r;
 
6487
+    int doclose = 0;
 
6488
+
 
6489
+    r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
6490
+                                              imapd_userid, mailboxname);
 
6491
+
 
6492
+    if (!r) {
 
6493
+       r = mlookup(tag, name, mailboxname, NULL, NULL, NULL, NULL, NULL);
 
6494
+    }
 
6495
+    if (r == IMAP_MAILBOX_MOVED) return;
 
6496
+
 
6497
+    if (!r) {
 
6498
+       r = mailbox_open_header(mailboxname, imapd_authstate, &mailbox);
 
6499
+    }
 
6500
+
 
6501
+    if (!r) {
 
6502
+       doclose = 1;
 
6503
+       if (!imapd_userisadmin && !(mailbox.myrights & ACL_READ)) {
 
6504
+           r = (mailbox.myrights & ACL_LOOKUP) ?
 
6505
+             IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
 
6506
+       }
 
6507
+    }
 
6508
+
 
6509
+    if (!r) {
 
6510
+       prot_printf(imapd_out, "* QUOTAROOT ");
 
6511
+       printastring(name);
 
6512
+       if (mailbox.quota.root) {
 
6513
+           (*imapd_namespace.mboxname_toexternal)(&imapd_namespace,
 
6514
+                                                  mailbox.quota.root,
 
6515
+                                                  imapd_userid, mailboxname);
 
6516
+           prot_printf(imapd_out, " ");
 
6517
+           printastring(mailboxname);
 
6518
+           r = quota_read(&mailbox.quota, NULL, 0);
 
6519
+           if (!r) {
 
6520
+               prot_printf(imapd_out, "\r\n* QUOTA ");
 
6521
+               printastring(mailboxname);
 
6522
+               prot_printf(imapd_out, " (");
 
6523
+               if (mailbox.quota.limit >= 0) {
 
6524
+                   prot_printf(imapd_out, "STORAGE %lu %d",
 
6525
+                               mailbox.quota.used/QUOTA_UNITS,
 
6526
+                               mailbox.quota.limit);
 
6527
+               }
 
6528
+               prot_putc(')', imapd_out);
 
6529
+           }
 
6530
+       }
 
6531
+       prot_printf(imapd_out, "\r\n");
 
6532
+    }
 
6533
+
 
6534
+    if (doclose) mailbox_close(&mailbox);
 
6535
+
 
6536
+    if (r) {
 
6537
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
6538
+       return;
 
6539
+    }
 
6540
+    
 
6541
+    prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
6542
+               error_message(IMAP_OK_COMPLETED));
 
6543
+}
 
6544
+
 
6545
+/*
 
6546
+ * Parse and perform a SETQUOTA command
 
6547
+ * The command has been parsed up to the resource list
 
6548
+ */
 
6549
+void
 
6550
+cmd_setquota(const char *tag, const char *quotaroot)
 
6551
+{
 
6552
+    int newquota = -1;
 
6553
+    int badresource = 0;
 
6554
+    int c;
 
6555
+    int force = 0;
 
6556
+    static struct buf arg;
 
6557
+    char *p;
 
6558
+    int r;
 
6559
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
6560
+
 
6561
+    c = prot_getc(imapd_in);
 
6562
+    if (c != '(') goto badlist;
 
6563
+
 
6564
+    c = getword(imapd_in, &arg);
 
6565
+    if (c != ')' || arg.s[0] != '\0') {
 
6566
+       for (;;) {
 
6567
+           if (c != ' ') goto badlist;
 
6568
+           if (strcasecmp(arg.s, "storage") != 0) badresource = 1;
 
6569
+           c = getword(imapd_in, &arg);
 
6570
+           if (c != ' ' && c != ')') goto badlist;
 
6571
+           if (arg.s[0] == '\0') goto badlist;
 
6572
+           newquota = 0;
 
6573
+           for (p = arg.s; *p; p++) {
 
6574
+               if (!isdigit((int) *p)) goto badlist;
 
6575
+               newquota = newquota * 10 + *p - '0';
 
6576
+                if (newquota < 0) goto badlist; /* overflow */
 
6577
+           }
 
6578
+           if (c == ')') break;
 
6579
+       }
 
6580
+    }
 
6581
+    c = prot_getc(imapd_in);
 
6582
+    if (c == '\r') c = prot_getc(imapd_in);
 
6583
+    if (c != '\n') {
 
6584
+       prot_printf(imapd_out, "%s BAD Unexpected extra arguments to SETQUOTA\r\n", tag);
 
6585
+       eatline(imapd_in, c);
 
6586
+       return;
 
6587
+    }
 
6588
+
 
6589
+    if (badresource) r = IMAP_UNSUPPORTED_QUOTA;
 
6590
+    else if (!imapd_userisadmin && !imapd_userisproxyadmin) {
 
6591
+       /* need to allow proxies so that mailbox moves can set initial quota
 
6592
+        * roots */
 
6593
+       r = IMAP_PERMISSION_DENIED;
 
6594
+    } else {
 
6595
+       /* are we forcing the creation of a quotaroot by having a leading +? */
 
6596
+       if(quotaroot[0] == '+') {
 
6597
+           force = 1;
 
6598
+           quotaroot++;
 
6599
+       }
 
6600
+       
 
6601
+       r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, quotaroot,
 
6602
+                                                  imapd_userid, mailboxname);
 
6603
+
 
6604
+       if (!r) {
 
6605
+           r = mboxlist_setquota(mailboxname, newquota, force);
 
6606
+       }
 
6607
+    }
 
6608
+
 
6609
+    if (r) {
 
6610
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
6611
+       return;
 
6612
+    }
 
6613
+    
 
6614
+    prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
6615
+               error_message(IMAP_OK_COMPLETED));
 
6616
+    return;
 
6617
+
 
6618
+ badlist:
 
6619
+    prot_printf(imapd_out, "%s BAD Invalid quota list in Setquota\r\n", tag);
 
6620
+    eatline(imapd_in, c);
 
6621
+}
 
6622
+
 
6623
+#ifdef HAVE_SSL
 
6624
+/*
 
6625
+ * this implements the STARTTLS command, as described in RFC 2595.
 
6626
+ * one caveat: it assumes that no external layer is currently present.
 
6627
+ * if a client executes this command, information about the external
 
6628
+ * layer that was passed on the command line is disgarded. this should
 
6629
+ * be fixed.
 
6630
+ */
 
6631
+/* imaps - whether this is an imaps transaction or not */
 
6632
+void cmd_starttls(char *tag, int imaps)
 
6633
+{
 
6634
+    int result;
 
6635
+    int *layerp;
 
6636
+
 
6637
+    char *auth_id;
 
6638
+    sasl_ssf_t ssf;
 
6639
+
 
6640
+    /* SASL and openssl have different ideas about whether ssf is signed */
 
6641
+    layerp = (int *) &ssf;
 
6642
+
 
6643
+    if (imapd_starttls_done == 1)
 
6644
+    {
 
6645
+       prot_printf(imapd_out, "%s NO TLS already active\r\n", tag);
 
6646
+       return;
 
6647
+    }
 
6648
+
 
6649
+    result=tls_init_serverengine("imap",
 
6650
+                                5,        /* depth to verify */
 
6651
+                                !imaps,   /* can client auth? */
 
6652
+                                !imaps);  /* TLS only? */
 
6653
+
 
6654
+    if (result == -1) {
 
6655
+
 
6656
+       syslog(LOG_ERR, "error initializing TLS");
 
6657
+
 
6658
+       if (imaps == 0) {
 
6659
+           prot_printf(imapd_out, "%s NO Error initializing TLS\r\n", tag);
 
6660
+       } else {
 
6661
+           fatal("tls_init() failed", EC_CONFIG);
 
6662
+       }
 
6663
+
 
6664
+       return;
 
6665
+    }
 
6666
+
 
6667
+    if (imaps == 0)
 
6668
+    {
 
6669
+       prot_printf(imapd_out, "%s OK Begin TLS negotiation now\r\n", tag);
 
6670
+       /* must flush our buffers before starting tls */
 
6671
+       prot_flush(imapd_out);
 
6672
+    }
 
6673
+  
 
6674
+    result=tls_start_servertls(0, /* read */
 
6675
+                              1, /* write */
 
6676
+                              layerp,
 
6677
+                              &auth_id,
 
6678
+                              &tls_conn);
 
6679
+
 
6680
+    /* if error */
 
6681
+    if (result==-1) {
 
6682
+       if (imaps == 0) {
 
6683
+           prot_printf(imapd_out, "%s NO Starttls negotiation failed\r\n", 
 
6684
+                       tag);
 
6685
+           syslog(LOG_NOTICE, "STARTTLS negotiation failed: %s", 
 
6686
+                  imapd_clienthost);
 
6687
+           return;
 
6688
+       } else {
 
6689
+           syslog(LOG_NOTICE, "imaps TLS negotiation failed: %s", 
 
6690
+                  imapd_clienthost);
 
6691
+           fatal("tls_start_servertls() failed", EC_TEMPFAIL);
 
6692
+           return;
 
6693
+       }
 
6694
+    }
 
6695
+
 
6696
+    /* tell SASL about the negotiated layer */
 
6697
+    result = sasl_setprop(imapd_saslconn, SASL_SSF_EXTERNAL, &ssf);
 
6698
+    if (result != SASL_OK) {
 
6699
+       fatal("sasl_setprop() failed: cmd_starttls()", EC_TEMPFAIL);
 
6700
+    }
 
6701
+    saslprops.ssf = ssf;
 
6702
+
 
6703
+    result = sasl_setprop(imapd_saslconn, SASL_AUTH_EXTERNAL, auth_id);
 
6704
+    if (result != SASL_OK) {
 
6705
+       fatal("sasl_setprop() failed: cmd_starttls()", EC_TEMPFAIL);
 
6706
+    }
 
6707
+    if(saslprops.authid) {
 
6708
+       free(saslprops.authid);
 
6709
+       saslprops.authid = NULL;
 
6710
+    }
 
6711
+    if(auth_id)
 
6712
+        saslprops.authid = xstrdup(auth_id);
 
6713
+
 
6714
+    /* tell the prot layer about our new layers */
 
6715
+    prot_settls(imapd_in, tls_conn);
 
6716
+    prot_settls(imapd_out, tls_conn);
 
6717
+
 
6718
+    imapd_starttls_done = 1;
 
6719
+}
 
6720
+#else
 
6721
+void cmd_starttls(char *tag, int imaps)
 
6722
+{
 
6723
+    fatal("cmd_starttls() executed, but starttls isn't implemented!",
 
6724
+         EC_SOFTWARE);
 
6725
+}
 
6726
+#endif /* HAVE_SSL */
 
6727
+
 
6728
+/*
 
6729
+ * Parse and perform a STATUS command
 
6730
+ * The command has been parsed up to the attribute list
 
6731
+ */
 
6732
+void
 
6733
+cmd_status(tag, name)
 
6734
+char *tag;
 
6735
+char *name;
 
6736
+{
 
6737
+    int c;
 
6738
+    int statusitems = 0;
 
6739
+    static struct buf arg;
 
6740
+    struct mailbox mailbox;
 
6741
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
6742
+    int r = 0;
 
6743
+    int doclose = 0;
 
6744
+
 
6745
+    c = prot_getc(imapd_in);
 
6746
+    if (c != '(') goto badlist;
 
6747
+
 
6748
+    c = getword(imapd_in, &arg);
 
6749
+    if (arg.s[0] == '\0') goto badlist;
 
6750
+    for (;;) {
 
6751
+       lcase(arg.s);
 
6752
+       if (!strcmp(arg.s, "messages")) {
 
6753
+           statusitems |= STATUS_MESSAGES;
 
6754
+       }
 
6755
+       else if (!strcmp(arg.s, "recent")) {
 
6756
+           statusitems |= STATUS_RECENT;
 
6757
+       }
 
6758
+       else if (!strcmp(arg.s, "uidnext")) {
 
6759
+           statusitems |= STATUS_UIDNEXT;
 
6760
+       }
 
6761
+       else if (!strcmp(arg.s, "uidvalidity")) {
 
6762
+           statusitems |= STATUS_UIDVALIDITY;
 
6763
+       }
 
6764
+       else if (!strcmp(arg.s, "unseen")) {
 
6765
+           statusitems |= STATUS_UNSEEN;
 
6766
+       }
 
6767
+       else {
 
6768
+           prot_printf(imapd_out, "%s BAD Invalid Status attribute %s\r\n",
 
6769
+                       tag, arg.s);
 
6770
+           eatline(imapd_in, c);
 
6771
+           return;
 
6772
+       }
 
6773
+           
 
6774
+       if (c == ' ') c = getword(imapd_in, &arg);
 
6775
+       else break;
 
6776
+    }
 
6777
+
 
6778
+    if (c != ')') {
 
6779
+       prot_printf(imapd_out,
 
6780
+                   "%s BAD Missing close parenthesis in Status\r\n", tag);
 
6781
+       eatline(imapd_in, c);
 
6782
+       return;
 
6783
+    }
 
6784
+
 
6785
+    c = prot_getc(imapd_in);
 
6786
+    if (c == '\r') c = prot_getc(imapd_in);
 
6787
+    if (c != '\n') {
 
6788
+       prot_printf(imapd_out,
 
6789
+                   "%s BAD Unexpected extra arguments to Status\r\n", tag);
 
6790
+       eatline(imapd_in, c);
 
6791
+       return;
 
6792
+    }
 
6793
+
 
6794
+    /*
 
6795
+     * Perform a full checkpoint of any open mailbox, in case we're
 
6796
+     * doing a STATUS check of the current mailbox.
 
6797
+     */
 
6798
+    if (imapd_mailbox) {
 
6799
+       index_check(imapd_mailbox, 0, 1);
 
6800
+    }
 
6801
+
 
6802
+    r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
6803
+                                              imapd_userid, mailboxname);
 
6804
+
 
6805
+    if (!r) {
 
6806
+       r = mlookup(tag, name, mailboxname, NULL, NULL, NULL, NULL, NULL);
 
6807
+    }
 
6808
+    if (r == IMAP_MAILBOX_MOVED) return;
 
6809
+
 
6810
+    if (!r) {
 
6811
+       r = mailbox_open_header(mailboxname, imapd_authstate, &mailbox);
 
6812
+    }
 
6813
+
 
6814
+    if (!r) {
 
6815
+       doclose = 1;
 
6816
+       r = mailbox_open_index(&mailbox);
 
6817
+    }
 
6818
+    if (!r && !(mailbox.myrights & ACL_READ)) {
 
6819
+       r = (imapd_userisadmin || (mailbox.myrights & ACL_LOOKUP)) ?
 
6820
+         IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
 
6821
+    }
 
6822
+
 
6823
+    if (!r) {
 
6824
+       r = index_status(&mailbox, name, statusitems);
 
6825
+    }
 
6826
+
 
6827
+    if (doclose) mailbox_close(&mailbox);
 
6828
+    
 
6829
+    if (r) {
 
6830
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
6831
+       return;
 
6832
+    }
 
6833
+    
 
6834
+    prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
6835
+               error_message(IMAP_OK_COMPLETED));
 
6836
+    return;
 
6837
+
 
6838
+ badlist:
 
6839
+    prot_printf(imapd_out, "%s BAD Invalid status list in Status\r\n", tag);
 
6840
+    eatline(imapd_in, c);
 
6841
+}
 
6842
+
 
6843
+#ifdef ENABLE_X_NETSCAPE_HACK
 
6844
+/*
 
6845
+ * Reply to Netscape's crock with a crock of my own
 
6846
+ */
 
6847
+void cmd_netscrape(char *tag)
 
6848
+{
 
6849
+    const char *url;
 
6850
+
 
6851
+    url = config_getstring(IMAPOPT_NETSCAPEURL);
 
6852
+
 
6853
+    /* I only know of three things to reply with: */
 
6854
+    prot_printf(imapd_out,
 
6855
+               "* OK [NETSCAPE] Carnegie Mellon Cyrus IMAP\r\n"
 
6856
+               "* VERSION %s\r\n",
 
6857
+               CYRUS_VERSION);
 
6858
+    if (url) prot_printf(imapd_out, "* ACCOUNT-URL %s\r\n", url);
 
6859
+    prot_printf(imapd_out, "%s OK %s\r\n",
 
6860
+               tag, error_message(IMAP_OK_COMPLETED));
 
6861
+}
 
6862
+#endif /* ENABLE_X_NETSCAPE_HACK */
 
6863
+
 
6864
+/* Callback for cmd_namespace to be passed to mboxlist_findall.
 
6865
+ * For each top-level mailbox found, print a bit of the response
 
6866
+ * if it is a shared namespace.  The rock is used as an integer in
 
6867
+ * order to ensure the namespace response is correct on a server with
 
6868
+ * no shared namespace.
 
6869
+ */
 
6870
+static int namespacedata(char *name,
 
6871
+                        int matchlen __attribute__((unused)),
 
6872
+                        int maycreate __attribute__((unused)),
 
6873
+                        void *rock)
 
6874
+{
 
6875
+    int* sawone = (int*) rock;
 
6876
+
 
6877
+    if (!name) {
 
6878
+       return 0;
 
6879
+    }
 
6880
+    
 
6881
+    if (!(strncmp(name, "INBOX.", 6))) {
 
6882
+       /* The user has a "personal" namespace. */
 
6883
+       sawone[NAMESPACE_INBOX] = 1;
 
6884
+    } else if (mboxname_isusermailbox(name, 0)) {
 
6885
+       /* The user can see the "other users" namespace. */
 
6886
+       sawone[NAMESPACE_USER] = 1;
 
6887
+    } else {
 
6888
+       /* The user can see the "shared" namespace. */
 
6889
+       sawone[NAMESPACE_SHARED] = 1;
 
6890
+    }
 
6891
+
 
6892
+    return 0;
 
6893
+}
 
6894
+
 
6895
+/*
 
6896
+ * Print out a response to the NAMESPACE command defined by
 
6897
+ * RFC 2342.
 
6898
+ */
 
6899
+void cmd_namespace(tag)
 
6900
+    char* tag;
 
6901
+{
 
6902
+    int sawone[3] = {0, 0, 0};
 
6903
+    char* pattern;
 
6904
+
 
6905
+    if (SLEEZY_NAMESPACE) {
 
6906
+       char inboxname[MAX_MAILBOX_NAME+1];
 
6907
+
 
6908
+       if (strlen(imapd_userid) + 5 > MAX_MAILBOX_NAME)
 
6909
+           sawone[NAMESPACE_INBOX] = 0;
 
6910
+       else {
 
6911
+           (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, "INBOX",
 
6912
+                                                  imapd_userid, inboxname);
 
6913
+           sawone[NAMESPACE_INBOX] = 
 
6914
+               !mboxlist_lookup(inboxname, NULL, NULL, NULL);
 
6915
+       }
 
6916
+       sawone[NAMESPACE_USER] = 1;
 
6917
+       sawone[NAMESPACE_SHARED] = 1;
 
6918
+    } else {
 
6919
+       pattern = xstrdup("%");
 
6920
+       /* now find all the exciting toplevel namespaces -
 
6921
+        * we're using internal names here
 
6922
+        */
 
6923
+       mboxlist_findall(NULL, pattern, imapd_userisadmin, imapd_userid,
 
6924
+                        imapd_authstate, namespacedata, (void*) sawone);
 
6925
+       free(pattern);
 
6926
+    }
 
6927
+
 
6928
+    prot_printf(imapd_out, "* NAMESPACE");
 
6929
+    if (sawone[NAMESPACE_INBOX]) {
 
6930
+       prot_printf(imapd_out, " ((\"%s\" \"%c\"))",
 
6931
+                   imapd_namespace.prefix[NAMESPACE_INBOX],
 
6932
+                   imapd_namespace.hier_sep);
 
6933
+    } else {
 
6934
+       prot_printf(imapd_out, " NIL");
 
6935
+    }
 
6936
+    if (sawone[NAMESPACE_USER]) {
 
6937
+       prot_printf(imapd_out, " ((\"%s\" \"%c\"))",
 
6938
+                   imapd_namespace.prefix[NAMESPACE_USER],
 
6939
+                   imapd_namespace.hier_sep);
 
6940
+    } else {
 
6941
+       prot_printf(imapd_out, " NIL");
 
6942
+    }
 
6943
+    if (sawone[NAMESPACE_SHARED]) {
 
6944
+       prot_printf(imapd_out, " ((\"%s\" \"%c\"))",
 
6945
+                   imapd_namespace.prefix[NAMESPACE_SHARED],
 
6946
+                   imapd_namespace.hier_sep);
 
6947
+    } else {
 
6948
+       prot_printf(imapd_out, " NIL");
 
6949
+    }
 
6950
+    prot_printf(imapd_out, "\r\n");
 
6951
+
 
6952
+    prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
6953
+               error_message(IMAP_OK_COMPLETED));
 
6954
+}
 
6955
+
 
6956
+/*
 
6957
+ * Parse annotate fetch data.
 
6958
+ *
 
6959
+ * This is a generic routine which parses just the annotation data.
 
6960
+ * Any surrounding command text must be parsed elsewhere, ie,
 
6961
+ * GETANNOTATION, FETCH.
 
6962
+ */
 
6963
+
 
6964
+int getannotatefetchdata(char *tag,
 
6965
+                        struct strlist **entries, struct strlist **attribs)
 
6966
+{
 
6967
+    int c;
 
6968
+    static struct buf arg;
 
6969
+
 
6970
+    *entries = *attribs = NULL;
 
6971
+
 
6972
+    c = prot_getc(imapd_in);
 
6973
+    if (c == EOF) {
 
6974
+       prot_printf(imapd_out,
 
6975
+                   "%s BAD Missing annotation entry\r\n", tag);
 
6976
+       goto baddata;
 
6977
+    }
 
6978
+    else if (c == '(') {
 
6979
+       /* entry list */
 
6980
+       do {
 
6981
+           c = getqstring(imapd_in, imapd_out, &arg);
 
6982
+           if (c == EOF) {
 
6983
+               prot_printf(imapd_out,
 
6984
+                           "%s BAD Missing annotation entry\r\n", tag);
 
6985
+               goto baddata;
 
6986
+           }
 
6987
+
 
6988
+           /* add the entry to the list */
 
6989
+           appendstrlist(entries, arg.s);
 
6990
+
 
6991
+       } while (c == ' ');
 
6992
+
 
6993
+       if (c != ')') {
 
6994
+           prot_printf(imapd_out,
 
6995
+                       "%s BAD Missing close paren in annotation entry list \r\n",
 
6996
+                       tag);
 
6997
+           goto baddata;
 
6998
+       }
 
6999
+
 
7000
+       c = prot_getc(imapd_in);
 
7001
+    }
 
7002
+    else {
 
7003
+       /* single entry -- add it to the list */
 
7004
+       prot_ungetc(c, imapd_in);
 
7005
+       c = getqstring(imapd_in, imapd_out, &arg);
 
7006
+       if (c == EOF) {
 
7007
+           prot_printf(imapd_out,
 
7008
+                       "%s BAD Missing annotation entry\r\n", tag);
 
7009
+           goto baddata;
 
7010
+       }
 
7011
+
 
7012
+       appendstrlist(entries, arg.s);
 
7013
+    }
 
7014
+
 
7015
+    if (c != ' ' || (c = prot_getc(imapd_in)) == EOF) {
 
7016
+       prot_printf(imapd_out,
 
7017
+                   "%s BAD Missing annotation attribute(s)\r\n", tag);
 
7018
+       goto baddata;
 
7019
+    }
 
7020
+
 
7021
+    if (c == '(') {
 
7022
+       /* attrib list */
 
7023
+       do {
 
7024
+           c = getnstring(imapd_in, imapd_out, &arg);
 
7025
+           if (c == EOF) {
 
7026
+               prot_printf(imapd_out,
 
7027
+                           "%s BAD Missing annotation attribute(s)\r\n", tag);
 
7028
+               goto baddata;
 
7029
+           }
 
7030
+
 
7031
+           /* add the attrib to the list */
 
7032
+           appendstrlist(attribs, arg.s);
 
7033
+
 
7034
+       } while (c == ' ');
 
7035
+
 
7036
+       if (c != ')') {
 
7037
+           prot_printf(imapd_out,
 
7038
+                       "%s BAD Missing close paren in "
 
7039
+                       "annotation attribute list\r\n", tag);
 
7040
+           goto baddata;
 
7041
+       }
 
7042
+
 
7043
+       c = prot_getc(imapd_in);
 
7044
+    }
 
7045
+    else {
 
7046
+       /* single attrib */
 
7047
+       prot_ungetc(c, imapd_in);
 
7048
+       c = getqstring(imapd_in, imapd_out, &arg);
 
7049
+           if (c == EOF) {
 
7050
+               prot_printf(imapd_out,
 
7051
+                           "%s BAD Missing annotation attribute\r\n", tag);
 
7052
+               goto baddata;
 
7053
+           }
 
7054
+
 
7055
+       appendstrlist(attribs, arg.s);
 
7056
+   }
 
7057
+
 
7058
+    return c;
 
7059
+
 
7060
+  baddata:
 
7061
+    if (c != EOF) prot_ungetc(c, imapd_in);
 
7062
+    return EOF;
 
7063
+}
 
7064
+
 
7065
+/*
 
7066
+ * Parse annotate store data.
 
7067
+ *
 
7068
+ * This is a generic routine which parses just the annotation data.
 
7069
+ * Any surrounding command text must be parsed elsewhere, ie,
 
7070
+ * SETANNOTATION, STORE, APPEND.
 
7071
+ */
 
7072
+
 
7073
+int getannotatestoredata(char *tag, struct entryattlist **entryatts)
 
7074
+{
 
7075
+    int c, islist = 0;
 
7076
+    static struct buf entry, attrib, value;
 
7077
+    struct attvaluelist *attvalues = NULL;
 
7078
+
 
7079
+    *entryatts = NULL;
 
7080
+
 
7081
+    c = prot_getc(imapd_in);
 
7082
+    if (c == EOF) {
 
7083
+       prot_printf(imapd_out,
 
7084
+                   "%s BAD Missing annotation entry\r\n", tag);
 
7085
+       goto baddata;
 
7086
+    }
 
7087
+    else if (c == '(') {
 
7088
+       /* entry list */
 
7089
+       islist = 1;
 
7090
+    }
 
7091
+    else {
 
7092
+       /* single entry -- put the char back */
 
7093
+       prot_ungetc(c, imapd_in);
 
7094
+    }
 
7095
+
 
7096
+    do {
 
7097
+       /* get entry */
 
7098
+       c = getqstring(imapd_in, imapd_out, &entry);
 
7099
+       if (c == EOF) {
 
7100
+           prot_printf(imapd_out,
 
7101
+                       "%s BAD Missing annotation entry\r\n", tag);
 
7102
+           goto baddata;
 
7103
+       }
 
7104
+
 
7105
+       /* parse att-value list */
 
7106
+       if (c != ' ' || (c = prot_getc(imapd_in)) != '(') {
 
7107
+           prot_printf(imapd_out,
 
7108
+                       "%s BAD Missing annotation attribute-values list\r\n",
 
7109
+                       tag);
 
7110
+           goto baddata;
 
7111
+       }
 
7112
+
 
7113
+       do {
 
7114
+           /* get attrib */
 
7115
+           c = getqstring(imapd_in, imapd_out, &attrib);
 
7116
+           if (c == EOF) {
 
7117
+               prot_printf(imapd_out,
 
7118
+                           "%s BAD Missing annotation attribute\r\n", tag);
 
7119
+               goto baddata;
 
7120
+           }
 
7121
+
 
7122
+           /* get value */
 
7123
+           if (c != ' ' ||
 
7124
+               (c = getnstring(imapd_in, imapd_out, &value)) == EOF) {
 
7125
+               prot_printf(imapd_out,
 
7126
+                           "%s BAD Missing annotation value\r\n", tag);
 
7127
+               goto baddata;
 
7128
+           }
 
7129
+
 
7130
+           /* add the attrib-value pair to the list */
 
7131
+           appendattvalue(&attvalues, attrib.s, value.s);
 
7132
+
 
7133
+       } while (c == ' ');
 
7134
+
 
7135
+       if (c != ')') {
 
7136
+           prot_printf(imapd_out,
 
7137
+                       "%s BAD Missing close paren in annotation "
 
7138
+                       "attribute-values list\r\n", tag);
 
7139
+           goto baddata;
 
7140
+       }
 
7141
+
 
7142
+       /* add the entry to the list */
 
7143
+       appendentryatt(entryatts, entry.s, attvalues);
 
7144
+       attvalues = NULL;
 
7145
+
 
7146
+       c = prot_getc(imapd_in);
 
7147
+
 
7148
+    } while (c == ' ');
 
7149
+
 
7150
+    if (islist) {
 
7151
+       if (c != ')') {
 
7152
+           prot_printf(imapd_out,
 
7153
+                       "%s BAD Missing close paren in annotation entry list \r\n",
 
7154
+                       tag);
 
7155
+           goto baddata;
 
7156
+       }
 
7157
+
 
7158
+       c = prot_getc(imapd_in);
 
7159
+    }
 
7160
+
 
7161
+    return c;
 
7162
+
 
7163
+  baddata:
 
7164
+    if (attvalues) freeattvalues(attvalues);
 
7165
+    if (c != EOF) prot_ungetc(c, imapd_in);
 
7166
+    return EOF;
 
7167
+}
 
7168
+
 
7169
+/*
 
7170
+ * Output an entry/attribute-value list response.
 
7171
+ *
 
7172
+ * This is a generic routine which outputs just the annotation data.
 
7173
+ * Any surrounding response text must be output elsewhere, ie,
 
7174
+ * GETANNOTATION, FETCH. 
 
7175
+ */
 
7176
+void annotate_response(struct entryattlist *l)
 
7177
+{
 
7178
+    int islist; /* do we have more than one entry? */
 
7179
+
 
7180
+    if (!l) return;
 
7181
+
 
7182
+    islist = (l->next != NULL);
 
7183
+
 
7184
+    if (islist) prot_printf(imapd_out, "(");
 
7185
+
 
7186
+    while (l) {
 
7187
+       prot_printf(imapd_out, "\"%s\"", l->entry);
 
7188
+
 
7189
+       /* do we have attributes?  solicited vs. unsolicited */
 
7190
+       if (l->attvalues) {
 
7191
+           struct attvaluelist *av = l->attvalues;
 
7192
+
 
7193
+           prot_printf(imapd_out, " (");
 
7194
+           while (av) {
 
7195
+               prot_printf(imapd_out, "\"%s\" ", av->attrib);
 
7196
+               if (!strcasecmp(av->value, "NIL"))
 
7197
+                   prot_printf(imapd_out, "NIL");
 
7198
+               else
 
7199
+                   prot_printf(imapd_out, "\"%s\"", av->value);
 
7200
+
 
7201
+               if ((av = av->next) == NULL)
 
7202
+                   prot_printf(imapd_out, ")");
 
7203
+               else
 
7204
+                   prot_printf(imapd_out, " ");
 
7205
+           }
 
7206
+       }
 
7207
+
 
7208
+       if ((l = l->next) != NULL)
 
7209
+           prot_printf(imapd_out, " ");
 
7210
+    }
 
7211
+
 
7212
+    if (islist) prot_printf(imapd_out, ")");
 
7213
+}
 
7214
+
 
7215
+/*
 
7216
+ * Perform a GETANNOTATION command
 
7217
+ *
 
7218
+ * The command has been parsed up to the entries
 
7219
+ */    
 
7220
+void cmd_getannotation(char *tag, char *mboxpat)
 
7221
+{
 
7222
+    int c, r = 0;
 
7223
+    struct strlist *entries = NULL, *attribs = NULL;
 
7224
+
 
7225
+    c = getannotatefetchdata(tag, &entries, &attribs);
 
7226
+    if (c == EOF) {
 
7227
+       eatline(imapd_in, c);
 
7228
+       return;
 
7229
+    }
 
7230
+
 
7231
+    /* check for CRLF */
 
7232
+    if (c == '\r') c = prot_getc(imapd_in);
 
7233
+    if (c != '\n') {
 
7234
+       prot_printf(imapd_out,
 
7235
+                   "%s BAD Unexpected extra arguments to Getannotation\r\n",
 
7236
+                   tag);
 
7237
+       eatline(imapd_in, c);
 
7238
+       goto freeargs;
 
7239
+    }
 
7240
+
 
7241
+    r = annotatemore_fetch(mboxpat, entries, attribs, &imapd_namespace,
 
7242
+                          imapd_userisadmin || imapd_userisproxyadmin,
 
7243
+                          imapd_userid, imapd_authstate, imapd_out);
 
7244
+
 
7245
+    if (r) {
 
7246
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
7247
+    } else {
 
7248
+       prot_printf(imapd_out, "%s OK %s\r\n",
 
7249
+                   tag, error_message(IMAP_OK_COMPLETED));
 
7250
+    }
 
7251
+
 
7252
+  freeargs:
 
7253
+    if (entries) freestrlist(entries);
 
7254
+    if (attribs) freestrlist(attribs);
 
7255
+
 
7256
+    return;
 
7257
+}
 
7258
+
 
7259
+/*
 
7260
+ * Perform a SETANNOTATION command
 
7261
+ *
 
7262
+ * The command has been parsed up to the entry-att list
 
7263
+ */    
 
7264
+void cmd_setannotation(char *tag, char *mboxpat)
 
7265
+{
 
7266
+    int c, r = 0;
 
7267
+    struct entryattlist *entryatts = NULL;
 
7268
+
 
7269
+    c = getannotatestoredata(tag, &entryatts);
 
7270
+    if (c == EOF) {
 
7271
+       eatline(imapd_in, c);
 
7272
+       return;
 
7273
+    }
 
7274
+
 
7275
+    /* check for CRLF */
 
7276
+    if (c == '\r') c = prot_getc(imapd_in);
 
7277
+    if (c != '\n') {
 
7278
+       prot_printf(imapd_out,
 
7279
+                   "%s BAD Unexpected extra arguments to Setannotation\r\n",
 
7280
+                   tag);
 
7281
+       eatline(imapd_in, c);
 
7282
+       goto freeargs;
 
7283
+    }
 
7284
+
 
7285
+    r = annotatemore_store(mboxpat,
 
7286
+                          entryatts, &imapd_namespace, imapd_userisadmin,
 
7287
+                          imapd_userid, imapd_authstate);
 
7288
+
 
7289
+    if (r) {
 
7290
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
7291
+    } else {
 
7292
+       prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
7293
+                   error_message(IMAP_OK_COMPLETED));
 
7294
+    }
 
7295
+
 
7296
+  freeargs:
 
7297
+    if (entryatts) freeentryatts(entryatts);
 
7298
+    return;
 
7299
+}
 
7300
+
 
7301
+/*
 
7302
+ * Parse a search program
 
7303
+ */
 
7304
+int getsearchprogram(tag, searchargs, charset, parsecharset)
 
7305
+char *tag;
 
7306
+struct searchargs *searchargs;
 
7307
+int *charset;
 
7308
+int parsecharset;
 
7309
+{
 
7310
+    int c;
 
7311
+
 
7312
+    do {
 
7313
+       c = getsearchcriteria(tag, searchargs, charset, parsecharset);
 
7314
+       parsecharset = 0;
 
7315
+    } while (c == ' ');
 
7316
+    return c;
 
7317
+}
 
7318
+
 
7319
+/*
 
7320
+ * Parse a search criteria
 
7321
+ */
 
7322
+int getsearchcriteria(tag, searchargs, charset, parsecharset)
 
7323
+char *tag;
 
7324
+struct searchargs *searchargs;
 
7325
+int *charset;
 
7326
+int parsecharset;
 
7327
+{
 
7328
+    static struct buf criteria, arg;
 
7329
+    struct searchargs *sub1, *sub2;
 
7330
+    char *p, *str;
 
7331
+    int c, flag;
 
7332
+    unsigned size;
 
7333
+    time_t start, end;
 
7334
+
 
7335
+    c = getword(imapd_in, &criteria);
 
7336
+    lcase(criteria.s);
 
7337
+    switch (criteria.s[0]) {
 
7338
+    case '\0':
 
7339
+       if (c != '(') goto badcri;
 
7340
+       c = getsearchprogram(tag, searchargs, charset, 0);
 
7341
+       if (c == EOF) return EOF;
 
7342
+       if (c != ')') {
 
7343
+           prot_printf(imapd_out, "%s BAD Missing required close paren in Search command\r\n",
 
7344
+                  tag);
 
7345
+           if (c != EOF) prot_ungetc(c, imapd_in);
 
7346
+           return EOF;
 
7347
+       }
 
7348
+       c = prot_getc(imapd_in);
 
7349
+       break;
 
7350
+
 
7351
+    case '0': case '1': case '2': case '3': case '4':
 
7352
+    case '5': case '6': case '7': case '8': case '9':
 
7353
+    case '*':
 
7354
+       if (imparse_issequence(criteria.s)) {
 
7355
+           appendstrlist(&searchargs->sequence, criteria.s);
 
7356
+       }
 
7357
+       else goto badcri;
 
7358
+       break;
 
7359
+
 
7360
+    case 'a':
 
7361
+       if (!strcmp(criteria.s, "answered")) {
 
7362
+           searchargs->system_flags_set |= FLAG_ANSWERED;
 
7363
+       }
 
7364
+       else if (!strcmp(criteria.s, "all")) {
 
7365
+           break;
 
7366
+       }
 
7367
+       else goto badcri;
 
7368
+       break;
 
7369
+
 
7370
+    case 'b':
 
7371
+       if (!strcmp(criteria.s, "before")) {
 
7372
+           if (c != ' ') goto missingarg;              
 
7373
+           c = getsearchdate(&start, &end);
 
7374
+           if (c == EOF) goto baddate;
 
7375
+           if (!searchargs->before || searchargs->before > start) {
 
7376
+               searchargs->before = start;
 
7377
+           }
 
7378
+       }
 
7379
+       else if (!strcmp(criteria.s, "bcc")) {
 
7380
+           if (c != ' ') goto missingarg;              
 
7381
+           c = getastring(imapd_in, imapd_out, &arg);
 
7382
+           if (c == EOF) goto missingarg;
 
7383
+           str = charset_convert(arg.s, *charset, NULL, 0);
 
7384
+           if (strchr(str, EMPTY)) {
 
7385
+               /* Force failure */
 
7386
+               searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
 
7387
+           }
 
7388
+           else {
 
7389
+               appendstrlistpat(&searchargs->bcc, str);
 
7390
+           }
 
7391
+       }
 
7392
+       else if (!strcmp(criteria.s, "body")) {
 
7393
+           if (c != ' ') goto missingarg;              
 
7394
+           c = getastring(imapd_in, imapd_out, &arg);
 
7395
+           if (c == EOF) goto missingarg;
 
7396
+           str = charset_convert(arg.s, *charset, NULL, 0);
 
7397
+           if (strchr(str, EMPTY)) {
 
7398
+               /* Force failure */
 
7399
+               searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
 
7400
+           }
 
7401
+           else {
 
7402
+               appendstrlistpat(&searchargs->body, str);
 
7403
+           }
 
7404
+       }
 
7405
+       else goto badcri;
 
7406
+       break;
 
7407
+
 
7408
+    case 'c':
 
7409
+       if (!strcmp(criteria.s, "cc")) {
 
7410
+           if (c != ' ') goto missingarg;              
 
7411
+           c = getastring(imapd_in, imapd_out, &arg);
 
7412
+           if (c == EOF) goto missingarg;
 
7413
+           str = charset_convert(arg.s, *charset, NULL, 0);
 
7414
+           if (strchr(str, EMPTY)) {
 
7415
+               /* Force failure */
 
7416
+               searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
 
7417
+           }
 
7418
+           else {
 
7419
+               appendstrlistpat(&searchargs->cc, str);
 
7420
+           }
 
7421
+       }
 
7422
+       else if (parsecharset && !strcmp(criteria.s, "charset")) {
 
7423
+           if (c != ' ') goto missingarg;              
 
7424
+           c = getastring(imapd_in, imapd_out, &arg);
 
7425
+           if (c != ' ') goto missingarg;
 
7426
+           lcase(arg.s);
 
7427
+           *charset = charset_lookupname(arg.s);
 
7428
+       }
 
7429
+       else goto badcri;
 
7430
+       break;
 
7431
+
 
7432
+    case 'd':
 
7433
+       if (!strcmp(criteria.s, "deleted")) {
 
7434
+           searchargs->system_flags_set |= FLAG_DELETED;
 
7435
+       }
 
7436
+       else if (!strcmp(criteria.s, "draft")) {
 
7437
+           searchargs->system_flags_set |= FLAG_DRAFT;
 
7438
+       }
 
7439
+       else goto badcri;
 
7440
+       break;
 
7441
+
 
7442
+    case 'f':
 
7443
+       if (!strcmp(criteria.s, "flagged")) {
 
7444
+           searchargs->system_flags_set |= FLAG_FLAGGED;
 
7445
+       }
 
7446
+       else if (!strcmp(criteria.s, "from")) {
 
7447
+           if (c != ' ') goto missingarg;              
 
7448
+           c = getastring(imapd_in, imapd_out, &arg);
 
7449
+           if (c == EOF) goto missingarg;
 
7450
+           str = charset_convert(arg.s, *charset, NULL, 0);
 
7451
+           if (strchr(str, EMPTY)) {
 
7452
+               /* Force failure */
 
7453
+               searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
 
7454
+           }
 
7455
+           else {
 
7456
+               appendstrlistpat(&searchargs->from, str);
 
7457
+           }
 
7458
+       }
 
7459
+       else goto badcri;
 
7460
+       break;
 
7461
+
 
7462
+    case 'h':
 
7463
+       if (!strcmp(criteria.s, "header")) {
 
7464
+           struct strlist **patlist;
 
7465
+
 
7466
+           if (c != ' ') goto missingarg;              
 
7467
+           c = getastring(imapd_in, imapd_out, &arg);
 
7468
+           if (c != ' ') goto missingarg;
 
7469
+           lcase(arg.s);
 
7470
+
 
7471
+           /* some headers can be reduced to search terms */
 
7472
+            if (!strcmp(arg.s, "bcc")) {
 
7473
+                patlist = &searchargs->bcc;
 
7474
+            }
 
7475
+            else if (!strcmp(arg.s, "cc")) {
 
7476
+               patlist = &searchargs->cc;
 
7477
+            }
 
7478
+           else if (!strcmp(arg.s, "to")) {
 
7479
+               patlist = &searchargs->to;
 
7480
+            }
 
7481
+           else if (!strcmp(arg.s, "from")) {
 
7482
+               patlist = &searchargs->from;
 
7483
+            }
 
7484
+           else if (!strcmp(arg.s, "subject")) {
 
7485
+               patlist = &searchargs->subject;
 
7486
+            }
 
7487
+
 
7488
+           /* we look message-id up in the envelope */
 
7489
+           else if (!strcmp(arg.s, "message-id")) {
 
7490
+               patlist = &searchargs->messageid;
 
7491
+           }
 
7492
+
 
7493
+           /* all other headers we handle normally */
 
7494
+           else {
 
7495
+               if (searchargs->cache_atleast < BIT32_MAX) {
 
7496
+                   bit32 this_ver =
 
7497
+                       mailbox_cached_header(arg.s);
 
7498
+                   if(this_ver > searchargs->cache_atleast)
 
7499
+                       searchargs->cache_atleast = this_ver;
 
7500
+               }
 
7501
+               appendstrlist(&searchargs->header_name, arg.s);
 
7502
+               patlist = &searchargs->header;
 
7503
+           }
 
7504
+
 
7505
+           c = getastring(imapd_in, imapd_out, &arg);
 
7506
+           if (c == EOF) goto missingarg;
 
7507
+           str = charset_convert(arg.s, *charset, NULL, 0);
 
7508
+           if (strchr(str, EMPTY)) {
 
7509
+               /* Force failure */
 
7510
+               searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
 
7511
+           }
 
7512
+           else {
 
7513
+               appendstrlistpat(patlist, str);
 
7514
+           }
 
7515
+       }
 
7516
+       else goto badcri;
 
7517
+       break;
 
7518
+
 
7519
+    case 'k':
 
7520
+       if (!strcmp(criteria.s, "keyword")) {
 
7521
+           if (c != ' ') goto missingarg;              
 
7522
+           c = getword(imapd_in, &arg);
 
7523
+           if (!imparse_isatom(arg.s)) goto badflag;
 
7524
+           lcase(arg.s);
 
7525
+           for (flag=0; flag < MAX_USER_FLAGS; flag++) {
 
7526
+               if (imapd_mailbox->flagname[flag] &&
 
7527
+                   !strcasecmp(imapd_mailbox->flagname[flag], arg.s)) break;
 
7528
+           }
 
7529
+           if (flag == MAX_USER_FLAGS) {
 
7530
+               /* Force failure */
 
7531
+               searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
 
7532
+               break;
 
7533
+           }
 
7534
+           searchargs->user_flags_set[flag/32] |= 1<<(flag&31);
 
7535
+       }
 
7536
+       else goto badcri;
 
7537
+       break;
 
7538
+
 
7539
+    case 'l':
 
7540
+       if (!strcmp(criteria.s, "larger")) {
 
7541
+           if (c != ' ') goto missingarg;              
 
7542
+           c = getword(imapd_in, &arg);
 
7543
+           size = 0;
 
7544
+           for (p = arg.s; *p && isdigit((int) *p); p++) {
 
7545
+               size = size * 10 + *p - '0';
 
7546
+                /* if (size < 0) goto badnumber; */
 
7547
+           }
 
7548
+           if (!arg.s || *p) goto badnumber;
 
7549
+           if (size > searchargs->larger) searchargs->larger = size;
 
7550
+       }
 
7551
+       else goto badcri;
 
7552
+       break;
 
7553
+
 
7554
+    case 'n':
 
7555
+       if (!strcmp(criteria.s, "not")) {
 
7556
+           if (c != ' ') goto missingarg;              
 
7557
+           sub1 = (struct searchargs *)xzmalloc(sizeof(struct searchargs));
 
7558
+           c = getsearchcriteria(tag, sub1, charset, 0);
 
7559
+           if (c == EOF) {
 
7560
+               freesearchargs(sub1);
 
7561
+               return EOF;
 
7562
+           }
 
7563
+
 
7564
+           appendsearchargs(searchargs, sub1, (struct searchargs *)0);
 
7565
+       }
 
7566
+       else if (!strcmp(criteria.s, "new")) {
 
7567
+           searchargs->flags |= (SEARCH_SEEN_UNSET|SEARCH_RECENT_SET);
 
7568
+       }
 
7569
+       else goto badcri;
 
7570
+       break;
 
7571
+
 
7572
+    case 'o':
 
7573
+       if (!strcmp(criteria.s, "or")) {
 
7574
+           if (c != ' ') goto missingarg;              
 
7575
+           sub1 = (struct searchargs *)xzmalloc(sizeof(struct searchargs));
 
7576
+           c = getsearchcriteria(tag, sub1, charset, 0);
 
7577
+           if (c == EOF) {
 
7578
+               freesearchargs(sub1);
 
7579
+               return EOF;
 
7580
+           }
 
7581
+           if (c != ' ') goto missingarg;              
 
7582
+           sub2 = (struct searchargs *)xzmalloc(sizeof(struct searchargs));
 
7583
+           c = getsearchcriteria(tag, sub2, charset, 0);
 
7584
+           if (c == EOF) {
 
7585
+               freesearchargs(sub1);
 
7586
+               freesearchargs(sub2);
 
7587
+               return EOF;
 
7588
+           }
 
7589
+           appendsearchargs(searchargs, sub1, sub2);
 
7590
+       }
 
7591
+       else if (!strcmp(criteria.s, "old")) {
 
7592
+           searchargs->flags |= SEARCH_RECENT_UNSET;
 
7593
+       }
 
7594
+       else if (!strcmp(criteria.s, "on")) {
 
7595
+           if (c != ' ') goto missingarg;              
 
7596
+           c = getsearchdate(&start, &end);
 
7597
+           if (c == EOF) goto baddate;
 
7598
+           if (!searchargs->before || searchargs->before > end) {
 
7599
+               searchargs->before = end;
 
7600
+           }
 
7601
+           if (!searchargs->after || searchargs->after < start) {
 
7602
+               searchargs->after = start;
 
7603
+           }
 
7604
+       }
 
7605
+       else goto badcri;
 
7606
+       break;
 
7607
+
 
7608
+    case 'r':
 
7609
+       if (!strcmp(criteria.s, "recent")) {
 
7610
+           searchargs->flags |= SEARCH_RECENT_SET;
 
7611
+       }
 
7612
+       else goto badcri;
 
7613
+       break;
 
7614
+
 
7615
+    case 's':
 
7616
+       if (!strcmp(criteria.s, "seen")) {
 
7617
+           searchargs->flags |= SEARCH_SEEN_SET;
 
7618
+       }
 
7619
+       else if (!strcmp(criteria.s, "sentbefore")) {
 
7620
+           if (c != ' ') goto missingarg;              
 
7621
+           c = getsearchdate(&start, &end);
 
7622
+           if (c == EOF) goto baddate;
 
7623
+           if (!searchargs->sentbefore || searchargs->sentbefore > start) {
 
7624
+               searchargs->sentbefore = start;
 
7625
+           }
 
7626
+       }
 
7627
+       else if (!strcmp(criteria.s, "senton")) {
 
7628
+           if (c != ' ') goto missingarg;              
 
7629
+           c = getsearchdate(&start, &end);
 
7630
+           if (c == EOF) goto baddate;
 
7631
+           if (!searchargs->sentbefore || searchargs->sentbefore > end) {
 
7632
+               searchargs->sentbefore = end;
 
7633
+           }
 
7634
+           if (!searchargs->sentafter || searchargs->sentafter < start) {
 
7635
+               searchargs->sentafter = start;
 
7636
+           }
 
7637
+       }
 
7638
+       else if (!strcmp(criteria.s, "sentsince")) {
 
7639
+           if (c != ' ') goto missingarg;              
 
7640
+           c = getsearchdate(&start, &end);
 
7641
+           if (c == EOF) goto baddate;
 
7642
+           if (!searchargs->sentafter || searchargs->sentafter < start) {
 
7643
+               searchargs->sentafter = start;
 
7644
+           }
 
7645
+       }
 
7646
+       else if (!strcmp(criteria.s, "since")) {
 
7647
+           if (c != ' ') goto missingarg;              
 
7648
+           c = getsearchdate(&start, &end);
 
7649
+           if (c == EOF) goto baddate;
 
7650
+           if (!searchargs->after || searchargs->after < start) {
 
7651
+               searchargs->after = start;
 
7652
+           }
 
7653
+       }
 
7654
+       else if (!strcmp(criteria.s, "smaller")) {
 
7655
+           if (c != ' ') goto missingarg;              
 
7656
+           c = getword(imapd_in, &arg);
 
7657
+           size = 0;
 
7658
+           for (p = arg.s; *p && isdigit((int) *p); p++) {
 
7659
+               size = size * 10 + *p - '0';
 
7660
+                /* if (size < 0) goto badnumber; */
 
7661
+           }
 
7662
+           if (!arg.s || *p) goto badnumber;
 
7663
+           if (size == 0) size = 1;
 
7664
+           if (!searchargs->smaller || size < searchargs->smaller)
 
7665
+             searchargs->smaller = size;
 
7666
+       }
 
7667
+       else if (!strcmp(criteria.s, "subject")) {
 
7668
+           if (c != ' ') goto missingarg;              
 
7669
+           c = getastring(imapd_in, imapd_out, &arg);
 
7670
+           if (c == EOF) goto missingarg;
 
7671
+           str = charset_convert(arg.s, *charset, NULL, 0);
 
7672
+           if (strchr(str, EMPTY)) {
 
7673
+               /* Force failure */
 
7674
+               searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
 
7675
+           }
 
7676
+           else {
 
7677
+               appendstrlistpat(&searchargs->subject, str);
 
7678
+           }
 
7679
+       }
 
7680
+       else goto badcri;
 
7681
+       break;
 
7682
+
 
7683
+    case 't':
 
7684
+       if (!strcmp(criteria.s, "to")) {
 
7685
+           if (c != ' ') goto missingarg;              
 
7686
+           c = getastring(imapd_in, imapd_out, &arg);
 
7687
+           if (c == EOF) goto missingarg;
 
7688
+           str = charset_convert(arg.s, *charset, NULL, 0);
 
7689
+           if (strchr(str, EMPTY)) {
 
7690
+               /* Force failure */
 
7691
+               searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
 
7692
+           }
 
7693
+           else {
 
7694
+               appendstrlistpat(&searchargs->to, str);
 
7695
+           }
 
7696
+       }
 
7697
+       else if (!strcmp(criteria.s, "text")) {
 
7698
+           if (c != ' ') goto missingarg;              
 
7699
+           c = getastring(imapd_in, imapd_out, &arg);
 
7700
+           if (c == EOF) goto missingarg;
 
7701
+           str = charset_convert(arg.s, *charset, NULL, 0);
 
7702
+           if (strchr(str, EMPTY)) {
 
7703
+               /* Force failure */
 
7704
+               searchargs->flags = (SEARCH_RECENT_SET|SEARCH_RECENT_UNSET);
 
7705
+           }
 
7706
+           else {
 
7707
+               appendstrlistpat(&searchargs->text, str);
 
7708
+           }
 
7709
+       }
 
7710
+       else goto badcri;
 
7711
+       break;
 
7712
+
 
7713
+    case 'u':
 
7714
+       if (!strcmp(criteria.s, "uid")) {
 
7715
+           if (c != ' ') goto missingarg;
 
7716
+           c = getword(imapd_in, &arg);
 
7717
+           if (!imparse_issequence(arg.s)) goto badcri;
 
7718
+           appendstrlist(&searchargs->uidsequence, arg.s);
 
7719
+       }
 
7720
+       else if (!strcmp(criteria.s, "unseen")) {
 
7721
+           searchargs->flags |= SEARCH_SEEN_UNSET;
 
7722
+       }
 
7723
+       else if (!strcmp(criteria.s, "unanswered")) {
 
7724
+           searchargs->system_flags_unset |= FLAG_ANSWERED;
 
7725
+       }
 
7726
+       else if (!strcmp(criteria.s, "undeleted")) {
 
7727
+           searchargs->system_flags_unset |= FLAG_DELETED;
 
7728
+       }
 
7729
+       else if (!strcmp(criteria.s, "undraft")) {
 
7730
+           searchargs->system_flags_unset |= FLAG_DRAFT;
 
7731
+       }
 
7732
+       else if (!strcmp(criteria.s, "unflagged")) {
 
7733
+           searchargs->system_flags_unset |= FLAG_FLAGGED;
 
7734
+       }
 
7735
+       else if (!strcmp(criteria.s, "unkeyword")) {
 
7736
+           if (c != ' ') goto missingarg;              
 
7737
+           c = getword(imapd_in, &arg);
 
7738
+           if (!imparse_isatom(arg.s)) goto badflag;
 
7739
+           lcase(arg.s);
 
7740
+           for (flag=0; flag < MAX_USER_FLAGS; flag++) {
 
7741
+               if (imapd_mailbox->flagname[flag] &&
 
7742
+                   !strcasecmp(imapd_mailbox->flagname[flag], arg.s)) break;
 
7743
+           }
 
7744
+           if (flag != MAX_USER_FLAGS) {
 
7745
+               searchargs->user_flags_unset[flag/32] |= 1<<(flag&31);
 
7746
+           }
 
7747
+       }
 
7748
+       else goto badcri;
 
7749
+       break;
 
7750
+
 
7751
+    default:
 
7752
+    badcri:
 
7753
+       prot_printf(imapd_out, "%s BAD Invalid Search criteria\r\n", tag);
 
7754
+       if (c != EOF) prot_ungetc(c, imapd_in);
 
7755
+       return EOF;
 
7756
+    }
 
7757
+
 
7758
+    return c;
 
7759
+
 
7760
+ missingarg:
 
7761
+    prot_printf(imapd_out, "%s BAD Missing required argument to Search %s\r\n",
 
7762
+          tag, criteria.s);
 
7763
+    if (c != EOF) prot_ungetc(c, imapd_in);
 
7764
+    return EOF;
 
7765
+
 
7766
+ badflag:
 
7767
+    prot_printf(imapd_out, "%s BAD Invalid flag name %s in Search command\r\n",
 
7768
+          tag, arg.s);
 
7769
+    if (c != EOF) prot_ungetc(c, imapd_in);
 
7770
+    return EOF;
 
7771
+
 
7772
+ baddate:
 
7773
+    prot_printf(imapd_out, "%s BAD Invalid date in Search command\r\n", tag);
 
7774
+    if (c != EOF) prot_ungetc(c, imapd_in);
 
7775
+    return EOF;
 
7776
+
 
7777
+ badnumber:
 
7778
+    prot_printf(imapd_out, "%s BAD Invalid number in Search command\r\n", tag);
 
7779
+    if (c != EOF) prot_ungetc(c, imapd_in);
 
7780
+    return EOF;
 
7781
+}
 
7782
+
 
7783
+void cmd_dump(char *tag, char *name, int uid_start) 
 
7784
+{
 
7785
+    int r = 0;
 
7786
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
7787
+    char *path, *acl;
 
7788
+
 
7789
+    /* administrators only please */
 
7790
+    if (!imapd_userisadmin) {
 
7791
+       r = IMAP_PERMISSION_DENIED;
 
7792
+    }
 
7793
+
 
7794
+    if (!r) {
 
7795
+       r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
7796
+                                                  imapd_userid, mailboxname);
 
7797
+    }
 
7798
+    
 
7799
+    if (!r) {
 
7800
+       r = mlookup(tag, name, mailboxname, NULL, &path, NULL, &acl, NULL);
 
7801
+    }
 
7802
+    if (r == IMAP_MAILBOX_MOVED) return;
 
7803
+
 
7804
+    if(!r) {
 
7805
+       r = dump_mailbox(tag, mailboxname, path, acl, uid_start, imapd_in,
 
7806
+                        imapd_out, imapd_authstate);
 
7807
+    }
 
7808
+
 
7809
+    if (r) {
 
7810
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
7811
+    } else {
 
7812
+       prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
7813
+                   error_message(IMAP_OK_COMPLETED));
 
7814
+    }
 
7815
+}
 
7816
+
 
7817
+void cmd_undump(char *tag, char *name) 
 
7818
+{
 
7819
+    int r = 0;
 
7820
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
7821
+    char *path, *acl;
 
7822
+
 
7823
+    /* administrators only please */
 
7824
+    if (!imapd_userisadmin) {
 
7825
+       r = IMAP_PERMISSION_DENIED;
 
7826
+    }
 
7827
+
 
7828
+    if (!r) {
 
7829
+       r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
7830
+                                                  imapd_userid, mailboxname);
 
7831
+    }
 
7832
+    
 
7833
+    if (!r) {
 
7834
+       r = mlookup(tag, name, mailboxname, NULL, &path, NULL, &acl, NULL);
 
7835
+    }
 
7836
+    if (r == IMAP_MAILBOX_MOVED) return;
 
7837
+
 
7838
+    if(!r) {
 
7839
+       /* save this stuff from additional mlookups */
 
7840
+       char *safe_path = xstrdup(path);
 
7841
+       char *safe_acl = xstrdup(acl);
 
7842
+       r = undump_mailbox(mailboxname, safe_path, safe_acl,
 
7843
+                          imapd_in, imapd_out,
 
7844
+                          imapd_authstate);
 
7845
+       free(safe_path);
 
7846
+       free(safe_acl);
 
7847
+    }
 
7848
+
 
7849
+    if (r) {
 
7850
+       prot_printf(imapd_out, "%s NO %s%s\r\n",
 
7851
+                   tag,
 
7852
+                   (r == IMAP_MAILBOX_NONEXISTENT &&
 
7853
+                    mboxlist_createmailboxcheck(mailboxname, 0, 0,
 
7854
+                                                imapd_userisadmin,
 
7855
+                                                imapd_userid, imapd_authstate,
 
7856
+                                                NULL, NULL) == 0)
 
7857
+                   ? "[TRYCREATE] " : "", error_message(r));
 
7858
+    } else {
 
7859
+       prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
7860
+                   error_message(IMAP_OK_COMPLETED));
 
7861
+    }
 
7862
+}
 
7863
+
 
7864
+static int getresult(struct protstream *p, char *tag) 
 
7865
+{
 
7866
+    char buf[4096];
 
7867
+    char *str = (char *) buf;
 
7868
+    
 
7869
+    while(1) {
 
7870
+       if (!prot_fgets(str, sizeof(buf), p)) {
 
7871
+           return IMAP_SERVER_UNAVAILABLE;
 
7872
+       }
 
7873
+       if (!strncmp(str, tag, strlen(tag))) {
 
7874
+           str += strlen(tag);
 
7875
+           if(!*str) {
 
7876
+               /* We got a tag, but no response */
 
7877
+               return IMAP_SERVER_UNAVAILABLE;
 
7878
+           }
 
7879
+           str++;
 
7880
+           if (!strncasecmp(str, "OK ", 3)) { return 0; }
 
7881
+           if (!strncasecmp(str, "NO ", 3)) { return IMAP_REMOTE_DENIED; }
 
7882
+           return IMAP_SERVER_UNAVAILABLE; /* huh? */
 
7883
+       }
 
7884
+       /* skip this line, we don't really care */
 
7885
+    }
 
7886
+}
 
7887
+
 
7888
+/* given 2 protstreams and a mailbox, gets the acl and then wipes it */
 
7889
+static int trashacl(struct protstream *pin, struct protstream *pout,
 
7890
+                   char *mailbox) 
 
7891
+{
 
7892
+    int i=0, j=0;
 
7893
+    char tagbuf[128];
 
7894
+    int c;             /* getword() returns an int */
 
7895
+    struct buf tag, cmd, tmp, user;
 
7896
+    int r = 0;
 
7897
+
 
7898
+    memset(&tag, 0, sizeof(struct buf));
 
7899
+    memset(&cmd, 0, sizeof(struct buf));
 
7900
+    memset(&tmp, 0, sizeof(struct buf));
 
7901
+    memset(&user, 0, sizeof(struct buf));
 
7902
+
 
7903
+    prot_printf(pout, "ACL0 GETACL {%lu+}\r\n%s\r\n",
 
7904
+               (unsigned long) strlen(mailbox), mailbox);
 
7905
+
 
7906
+    while(1) {
 
7907
+       c = getword(pin, &tag);
 
7908
+       if (c == EOF) {
 
7909
+           r = IMAP_SERVER_UNAVAILABLE;
 
7910
+           break;
 
7911
+       }
 
7912
+
 
7913
+       c = getword(pin, &cmd);
 
7914
+       if (c == EOF) {
 
7915
+           r = IMAP_SERVER_UNAVAILABLE;
 
7916
+           break;
 
7917
+       }
 
7918
+       
 
7919
+       if(c == '\r') {
 
7920
+           c = prot_getc(pin);
 
7921
+           if(c != '\n') {
 
7922
+               r = IMAP_SERVER_UNAVAILABLE;
 
7923
+               goto cleanup;
 
7924
+           }
 
7925
+       }
 
7926
+       if(c == '\n') goto cleanup;     
 
7927
+
 
7928
+       if (tag.s[0] == '*' && !strncmp(cmd.s, "ACL", 3)) {
 
7929
+           while(c != '\n') {
 
7930
+               /* An ACL response, we should send a DELETEACL command */
 
7931
+               c = getastring(pin, pout, &tmp);
 
7932
+               if (c == EOF) {
 
7933
+                   r = IMAP_SERVER_UNAVAILABLE;
 
7934
+                   goto cleanup;
 
7935
+               }
 
7936
+
 
7937
+               if(c == '\r') {
 
7938
+                   c = prot_getc(pin);
 
7939
+                   if(c != '\n') {
 
7940
+                       r = IMAP_SERVER_UNAVAILABLE;
 
7941
+                       goto cleanup;
 
7942
+                   }
 
7943
+               }
 
7944
+               if(c == '\n') goto cleanup;
 
7945
+               
 
7946
+               c = getastring(pin, pout, &user);
 
7947
+               if (c == EOF) {
 
7948
+                   r = IMAP_SERVER_UNAVAILABLE;
 
7949
+                   goto cleanup;
 
7950
+               }
 
7951
+
 
7952
+               snprintf(tagbuf, sizeof(tagbuf), "ACL%d", ++i);
 
7953
+               
 
7954
+               prot_printf(pout, "%s DELETEACL {%lu+}\r\n%s {%lu+}\r\n%s\r\n",
 
7955
+                           tagbuf, (unsigned long) strlen(mailbox), mailbox,
 
7956
+                           (unsigned long) strlen(user.s), user.s);
 
7957
+               if(c == '\r') {
 
7958
+                   c = prot_getc(pin);
 
7959
+                   if(c != '\n') {
 
7960
+                       r = IMAP_SERVER_UNAVAILABLE;
 
7961
+                       goto cleanup;
 
7962
+                   }
 
7963
+               }
 
7964
+               /* if the next character is \n, we'll exit the loop */
 
7965
+           }
 
7966
+           continue;
 
7967
+       } else if (!strncmp(tag.s, "ACL0", 4)) {
 
7968
+           /* end of this command */
 
7969
+           if (!strcasecmp(cmd.s, "OK")) { break; }
 
7970
+           if (!strcasecmp(cmd.s, "NO")) { r = IMAP_REMOTE_DENIED; break; }
 
7971
+           r = IMAP_SERVER_UNAVAILABLE;
 
7972
+           break;
 
7973
+       }
 
7974
+    }
 
7975
+
 
7976
+    cleanup:
 
7977
+
 
7978
+    /* Now cleanup after all the DELETEACL commands */
 
7979
+    if(!r) {
 
7980
+       while(j < i) {
 
7981
+           c = getword(pin, &tag);
 
7982
+           if (c == EOF) {
 
7983
+               r = IMAP_SERVER_UNAVAILABLE;
 
7984
+               break;
 
7985
+           }
 
7986
+           
 
7987
+           eatline(pin, c);
 
7988
+           
 
7989
+           if(!strncmp("ACL", tag.s, 3)) {
 
7990
+               j++;
 
7991
+           }
 
7992
+       }
 
7993
+    }
 
7994
+
 
7995
+    if(r) eatline(pin, c);
 
7996
+
 
7997
+    freebuf(&user);
 
7998
+    freebuf(&tmp);
 
7999
+    freebuf(&cmd);
 
8000
+    freebuf(&tag);
 
8001
+
 
8002
+    return r;
 
8003
+}
 
8004
+
 
8005
+static int dumpacl(struct protstream *pin, struct protstream *pout,
 
8006
+                  char *mailbox, char *acl_in) 
 
8007
+{
 
8008
+    int r = 0;
 
8009
+    int c;             /* getword() returns an int */
 
8010
+    char tag[128];
 
8011
+    int tagnum = 1;
 
8012
+    char *rights, *nextid;
 
8013
+    int mailboxlen = strlen(mailbox);
 
8014
+    char *acl_safe = acl_in ? xstrdup(acl_in) : NULL;
 
8015
+    char *acl = acl_safe;
 
8016
+    struct buf inbuf;
 
8017
+    
 
8018
+    memset(&inbuf, 0, sizeof(struct buf));
 
8019
+
 
8020
+    while (acl) {
 
8021
+       rights = strchr(acl, '\t');
 
8022
+       if (!rights) break;
 
8023
+       *rights++ = '\0';
 
8024
+       
 
8025
+       nextid = strchr(rights, '\t');
 
8026
+       if (!nextid) break;
 
8027
+       *nextid++ = '\0';
 
8028
+
 
8029
+       snprintf(tag, sizeof(tag), "SACL%d", tagnum++);
 
8030
+       
 
8031
+       prot_printf(pout, "%s SETACL {%d+}\r\n%s {%lu+}\r\n%s {%lu+}\r\n%s\r\n",
 
8032
+                   tag,
 
8033
+                   mailboxlen, mailbox,
 
8034
+                   (unsigned long) strlen(acl), acl,
 
8035
+                   (unsigned long) strlen(rights), rights);
 
8036
+
 
8037
+       while(1) {
 
8038
+           c = getword(pin, &inbuf);
 
8039
+           if (c == EOF) {
 
8040
+               r = IMAP_SERVER_UNAVAILABLE;
 
8041
+               break;
 
8042
+           }
 
8043
+           if(strncmp(tag, inbuf.s, strlen(tag))) {
 
8044
+               eatline(pin, c);
 
8045
+               continue;
 
8046
+           } else {
 
8047
+               /* this is our line */
 
8048
+               break;
 
8049
+           }
 
8050
+       }
 
8051
+
 
8052
+       /* Are we OK? */
 
8053
+
 
8054
+       c = getword(pin, &inbuf);
 
8055
+       if (c == EOF) {
 
8056
+           r = IMAP_SERVER_UNAVAILABLE;
 
8057
+           break;
 
8058
+       }
 
8059
+
 
8060
+       if(strncmp("OK", inbuf.s, 2)) {
 
8061
+           r = IMAP_REMOTE_DENIED;
 
8062
+           break;
 
8063
+       }
 
8064
+
 
8065
+       /* Eat the line and get the next one */
 
8066
+       eatline(pin, c);
 
8067
+       acl = nextid;
 
8068
+    }
 
8069
+
 
8070
+    freebuf(&inbuf);
 
8071
+    if(acl_safe) free(acl_safe);
 
8072
+
 
8073
+    return r;
 
8074
+}
 
8075
+
 
8076
+static int do_xfer_single(char *toserver, char *topart,
 
8077
+                         char *name, char *mailboxname,
 
8078
+                         int mbflags, 
 
8079
+                         char *path, char *part, char *acl,
 
8080
+                         int prereserved,
 
8081
+                         mupdate_handle *h_in,
 
8082
+                         struct backend *be_in) 
 
8083
+{
 
8084
+    int r = 0, rerr = 0;
 
8085
+    char buf[MAX_PARTITION_LEN+HOSTNAME_SIZE+2];
 
8086
+    struct backend *be = NULL;
 
8087
+    mupdate_handle *mupdate_h = NULL;
 
8088
+    int backout_mupdate = 0;
 
8089
+    int backout_remotebox = 0;
 
8090
+    int backout_remoteflag = 0;
 
8091
+
 
8092
+    /* Make sure we're given a sane value */
 
8093
+    if(topart && !imparse_isatom(topart)) {
 
8094
+       return IMAP_PARTITION_UNKNOWN;
 
8095
+    }
 
8096
+
 
8097
+    if(!strcmp(toserver, config_servername)) {
 
8098
+       return IMAP_BAD_SERVER;
 
8099
+    }
 
8100
+    
 
8101
+    /* Okay, we have the mailbox, now the order of steps is:
 
8102
+     *
 
8103
+     * 1) Connect to remote server.
 
8104
+     * 2) LOCALCREATE on remote server
 
8105
+     * 2.5) Set mailbox as REMOTE on local server
 
8106
+     * 3) mupdate.DEACTIVATE(mailbox, remoteserver) xxx what partition?
 
8107
+     * 4) undump mailbox from local to remote
 
8108
+     * 5) Sync remote acl
 
8109
+     * 6) mupdate.ACTIVATE(mailbox, remoteserver)
 
8110
+     * ** MAILBOX NOW LIVING ON REMOTE SERVER
 
8111
+     * 6.5) force remote server to push the final mupdate entry to ensure
 
8112
+     *      that the state of the world is correct (required if we do not
 
8113
+     *      know the remote partition, but worst case it will be caught
 
8114
+     *      when they next sync)
 
8115
+     * 7) local delete of mailbox
 
8116
+     * 8) remove local remote mailbox entry??????
 
8117
+     */
 
8118
+
 
8119
+    /* Step 1: Connect to remote server */
 
8120
+    if(!r && !be_in) {
 
8121
+       /* Just authorize as the IMAP server, so pass "" as our authzid */
 
8122
+       be = backend_connect(NULL, toserver, &protocol[PROTOCOL_IMAP], "", NULL);
 
8123
+       if(!be) r = IMAP_SERVER_UNAVAILABLE;
 
8124
+       if(r) syslog(LOG_ERR,
 
8125
+                    "Could not move mailbox: %s, Backend connect failed",
 
8126
+                    mailboxname);
 
8127
+    } else if(!r) {
 
8128
+       be = be_in;
 
8129
+    }
 
8130
+
 
8131
+    /* Step 1a: Connect to mupdate (as needed) */
 
8132
+    if(h_in) {
 
8133
+       mupdate_h = h_in;
 
8134
+    } else if (config_mupdate_server) {
 
8135
+       r = mupdate_connect(config_mupdate_server, NULL, &mupdate_h, NULL);
 
8136
+       if(r) {
 
8137
+           syslog(LOG_ERR,
 
8138
+                  "Could not move mailbox: %s, MUPDATE connect failed",
 
8139
+                  mailboxname);
 
8140
+           goto done;
 
8141
+       }
 
8142
+
 
8143
+    }
 
8144
+
 
8145
+    /* Step 2: LOCALCREATE on remote server */
 
8146
+    if(!r) {
 
8147
+       if(topart) {
 
8148
+           /* need to send partition as an atom */
 
8149
+           prot_printf(be->out, "LC1 LOCALCREATE {%lu+}\r\n%s %s\r\n",
 
8150
+                       (unsigned long) strlen(name), name, topart);
 
8151
+       } else {
 
8152
+           prot_printf(be->out, "LC1 LOCALCREATE {%lu+}\r\n%s\r\n",
 
8153
+                       (unsigned long) strlen(name), name);
 
8154
+       }
 
8155
+       r = getresult(be->in, "LC1");
 
8156
+       if(r) syslog(LOG_ERR, "Could not move mailbox: %s, LOCALCREATE failed",
 
8157
+                    mailboxname);
 
8158
+       else backout_remotebox = 1;
 
8159
+    }
 
8160
+
 
8161
+    /* Step 2.5: Set mailbox as REMOTE on local server */
 
8162
+    if(!r) {
 
8163
+       snprintf(buf, sizeof(buf), "%s!%s", toserver, part);
 
8164
+       r = mboxlist_update(mailboxname, mbflags|MBTYPE_MOVING, buf, acl, 1);
 
8165
+       if(r) syslog(LOG_ERR, "Could not move mailbox: %s, " \
 
8166
+                    "mboxlist_update failed", mailboxname);
 
8167
+    }
 
8168
+
 
8169
+    /* Step 3: mupdate.DEACTIVATE(mailbox, newserver) */
 
8170
+    /* (only if mailbox has not been already deactivated by our caller) */
 
8171
+    if(!r && mupdate_h && !prereserved) {
 
8172
+       backout_remoteflag = 1;
 
8173
+
 
8174
+       /* Note we are making the reservation on OUR host so that recovery
 
8175
+        * make sense */
 
8176
+       snprintf(buf, sizeof(buf), "%s!%s", config_servername, part);
 
8177
+       r = mupdate_deactivate(mupdate_h, mailboxname, buf);
 
8178
+       if(r) syslog(LOG_ERR,
 
8179
+                    "Could not move mailbox: %s, MUPDATE DEACTIVATE failed",
 
8180
+                    mailboxname);
 
8181
+    }
 
8182
+
 
8183
+    /* Step 4: Dump local -> remote */
 
8184
+    if(!r) {
 
8185
+       backout_mupdate = 1;
 
8186
+
 
8187
+       prot_printf(be->out, "D01 UNDUMP {%lu+}\r\n%s ",
 
8188
+                   (unsigned long) strlen(name), name);
 
8189
+
 
8190
+       r = dump_mailbox(NULL, mailboxname, path, acl, 0, be->in, be->out,
 
8191
+                        imapd_authstate);
 
8192
+
 
8193
+       if(r)
 
8194
+           syslog(LOG_ERR,
 
8195
+                  "Could not move mailbox: %s, dump_mailbox() failed",
 
8196
+                  mailboxname);
 
8197
+    }
 
8198
+
 
8199
+    if(!r) {
 
8200
+       r = getresult(be->in, "D01");
 
8201
+       if(r) syslog(LOG_ERR, "Could not move mailbox: %s, UNDUMP failed",
 
8202
+                    mailboxname);
 
8203
+    }
 
8204
+    
 
8205
+    /* Step 5: Set ACL on remote */
 
8206
+    if(!r) {
 
8207
+       r = trashacl(be->in, be->out, name);
 
8208
+       if(r) syslog(LOG_ERR, "Could not clear remote acl on %s",
 
8209
+                    mailboxname);
 
8210
+    }
 
8211
+    if(!r) {
 
8212
+       r = dumpacl(be->in, be->out, name, acl);
 
8213
+       if(r) syslog(LOG_ERR, "Could not set remote acl on %s",
 
8214
+                    mailboxname);
 
8215
+    }
 
8216
+
 
8217
+    /* Step 6: mupdate.activate(mailbox, remote) */
 
8218
+    /* We do this from the local server first so that recovery is easier */
 
8219
+    if(!r && mupdate_h) {
 
8220
+       /* Note the flag that we don't have a valid partiton at the moment */
 
8221
+       snprintf(buf, sizeof(buf), "%s!MOVED", toserver);
 
8222
+       r = mupdate_activate(mupdate_h, mailboxname, buf, acl);
 
8223
+    }
 
8224
+    
 
8225
+    /* MAILBOX NOW LIVES ON REMOTE */
 
8226
+    if(!r) {
 
8227
+       backout_remotebox = 0;
 
8228
+       backout_mupdate = 0;
 
8229
+       backout_remoteflag = 0;
 
8230
+
 
8231
+       /* 6.5) Kick remote server to correct mupdate entry */
 
8232
+       /* Note that we don't really care if this succeeds or not */
 
8233
+       if (mupdate_h) {
 
8234
+           prot_printf(be->out, "MP1 MUPDATEPUSH {%lu+}\r\n%s\r\n",
 
8235
+                       (unsigned long) strlen(name), name);
 
8236
+           rerr = getresult(be->in, "MP1");
 
8237
+           if(rerr) {
 
8238
+               syslog(LOG_ERR,
 
8239
+                      "Could not trigger remote push to mupdate server" \
 
8240
+                      "during move of %s",
 
8241
+                      mailboxname);
 
8242
+           }
 
8243
+       }
 
8244
+    }
 
8245
+
 
8246
+    /* 7) local delete of mailbox
 
8247
+     * & remove local "remote" mailboxlist entry */
 
8248
+    if(!r) {
 
8249
+       /* Note that we do not check the ACL, and we don't update MUPDATE */
 
8250
+       /* note also that we need to remember to let proxyadmins do this */
 
8251
+       r = mboxlist_deletemailbox(mailboxname,
 
8252
+                                  imapd_userisadmin || imapd_userisproxyadmin,
 
8253
+                                  imapd_userid, imapd_authstate, 0, 1, 0);
 
8254
+       if(r) syslog(LOG_ERR,
 
8255
+                    "Could not delete local mailbox during move of %s",
 
8256
+                    mailboxname);
 
8257
+     }
 
8258
+
 
8259
+done:
 
8260
+    if(r && mupdate_h && backout_mupdate) {
 
8261
+       rerr = 0;
 
8262
+       /* xxx if the mupdate server is what failed, then this won't
 
8263
+          help any! */
 
8264
+       snprintf(buf, sizeof(buf), "%s!%s", config_servername, part);
 
8265
+       rerr = mupdate_activate(mupdate_h, mailboxname, buf, acl);
 
8266
+       if(rerr) {
 
8267
+           syslog(LOG_ERR,
 
8268
+                  "Could not back out mupdate during move of %s (%s)",
 
8269
+                  mailboxname, error_message(rerr));
 
8270
+       }
 
8271
+    }
 
8272
+    if(r && backout_remotebox) {
 
8273
+       rerr = 0;
 
8274
+       prot_printf(be->out, "LD1 LOCALDELETE {%lu+}\r\n%s\r\n",
 
8275
+                   (unsigned long) strlen(name), name);
 
8276
+       rerr = getresult(be->in, "LD1");
 
8277
+       if(rerr) {
 
8278
+           syslog(LOG_ERR,
 
8279
+                  "Could not back out remote mailbox during move of %s (%s)",
 
8280
+                  name, error_message(rerr));
 
8281
+       }   
 
8282
+    }
 
8283
+    if(r && backout_remoteflag) {
 
8284
+       rerr = 0;
 
8285
+
 
8286
+       rerr = mboxlist_update(mailboxname, mbflags, part, acl, 1);
 
8287
+       if(rerr) syslog(LOG_ERR, "Could not unset remote flag on mailbox: %s",
 
8288
+                       mailboxname);
 
8289
+    }
 
8290
+
 
8291
+    /* release the handles we got locally if necessary */
 
8292
+    if(mupdate_h && !h_in)
 
8293
+       mupdate_disconnect(&mupdate_h);
 
8294
+    if(be && !be_in)
 
8295
+       backend_disconnect(be, &protocol[PROTOCOL_IMAP]);
 
8296
+
 
8297
+    return r;
 
8298
+}
 
8299
+
 
8300
+struct xfer_user_rock 
 
8301
+{
 
8302
+    char *toserver;
 
8303
+    char *topart;
 
8304
+    mupdate_handle *h;
 
8305
+    struct backend *be;
 
8306
+};
 
8307
+
 
8308
+static int xfer_user_cb(char *name,
 
8309
+                       int matchlen __attribute__((unused)),
 
8310
+                       int maycreate __attribute__((unused)),
 
8311
+                       void *rock) 
 
8312
+{
 
8313
+    mupdate_handle *mupdate_h = ((struct xfer_user_rock *)rock)->h;
 
8314
+    char *toserver = ((struct xfer_user_rock *)rock)->toserver;
 
8315
+    char *topart = ((struct xfer_user_rock *)rock)->topart;
 
8316
+    struct backend *be = ((struct xfer_user_rock *)rock)->be;
 
8317
+    char externalname[MAX_MAILBOX_NAME+1];
 
8318
+    int mbflags;
 
8319
+    int r = 0;
 
8320
+    char *inpath, *inpart, *inacl;
 
8321
+    char *path = NULL, *part = NULL, *acl = NULL;
 
8322
+
 
8323
+    if (!r) {
 
8324
+       /* NOTE: NOT mlookup() because we don't want to issue a referral */
 
8325
+       /* xxx but what happens if they are remote
 
8326
+        * mailboxes? */
 
8327
+       r = mboxlist_detail(name, &mbflags,
 
8328
+                           &inpath, &inpart, &inacl, NULL);
 
8329
+    }
 
8330
+    
 
8331
+    if (!r) {
 
8332
+       path = xstrdup(inpath);
 
8333
+       part = xstrdup(inpart);
 
8334
+       acl = xstrdup(inacl);
 
8335
+    }
 
8336
+
 
8337
+    if (!r) {
 
8338
+       r = (*imapd_namespace.mboxname_toexternal)(&imapd_namespace,
 
8339
+                                                  name,
 
8340
+                                                  imapd_userid,
 
8341
+                                                  externalname);
 
8342
+    }
 
8343
+
 
8344
+    if(!r) {
 
8345
+       r = do_xfer_single(toserver, topart, externalname, name, mbflags,
 
8346
+                          path, part, acl, 0, mupdate_h, be);
 
8347
+    }
 
8348
+
 
8349
+    if(path) free(path);
 
8350
+    if(part) free(part);
 
8351
+    if(acl) free(acl);
 
8352
+
 
8353
+    return r;
 
8354
+}
 
8355
+
 
8356
+
 
8357
+void cmd_xfer(char *tag, char *name, char *toserver, char *topart)
 
8358
+{
 
8359
+    int r = 0;
 
8360
+    char buf[MAX_PARTITION_LEN+HOSTNAME_SIZE+2];
 
8361
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
8362
+    int mbflags;
 
8363
+    int moving_user = 0;
 
8364
+    int backout_mupdate = 0;
 
8365
+    mupdate_handle *mupdate_h = NULL;
 
8366
+    char *inpath, *inpart, *inacl;
 
8367
+    char *path = NULL, *part = NULL, *acl = NULL;
 
8368
+    char *p, *mbox = mailboxname;
 
8369
+    
 
8370
+    /* administrators only please */
 
8371
+    /* however, proxys can do this, if their authzid is an admin */
 
8372
+    if (!imapd_userisadmin && !imapd_userisproxyadmin) {
 
8373
+       r = IMAP_PERMISSION_DENIED;
 
8374
+    }
 
8375
+
 
8376
+    if (!r) {
 
8377
+       r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace,
 
8378
+                                                  name,
 
8379
+                                                  imapd_userid,
 
8380
+                                                  mailboxname);
 
8381
+    }
 
8382
+
 
8383
+    /* NOTE: Since XFER can only be used by an admin, and we always connect
 
8384
+     * to the destination backend as an admin, we take advantage of the fact
 
8385
+     * that admins *always* use a consistent mailbox naming scheme.
 
8386
+     * So, 'name' should be used in any command we send to a backend, and
 
8387
+     * 'mailboxname' is the internal name to be used for mupdate and findall.
 
8388
+     */
 
8389
+
 
8390
+    if (config_virtdomains && (p = strchr(mailboxname, '!'))) {
 
8391
+       /* pointer to mailbox w/o domain prefix */
 
8392
+       mbox = p + 1;
 
8393
+    }
 
8394
+
 
8395
+    if(!strncmp(mbox, "user.", 5) && !strchr(mbox+5, '.')) {
 
8396
+       if ((strlen(mbox+5) == (strlen(imapd_userid) - (mbox - mailboxname))) &&
 
8397
+           !strncmp(mbox+5, imapd_userid, strlen(mbox+5))) {
 
8398
+           /* don't move your own inbox, that could be troublesome */
 
8399
+           r = IMAP_MAILBOX_NOTSUPPORTED;
 
8400
+       } else if (!config_getswitch(IMAPOPT_ALLOWUSERMOVES)) {
 
8401
+           /* not configured to allow user moves */
 
8402
+           r = IMAP_MAILBOX_NOTSUPPORTED;
 
8403
+       } else {
 
8404
+           moving_user = 1;
 
8405
+       }
 
8406
+    }
 
8407
+    
 
8408
+    if (!r) {
 
8409
+       r = mlookup(tag, name, mailboxname, &mbflags,
 
8410
+                   &inpath, &inpart, &inacl, NULL);
 
8411
+    }
 
8412
+    if (r == IMAP_MAILBOX_MOVED) return;
 
8413
+    
 
8414
+    if (!r) {
 
8415
+       path = xstrdup(inpath);
 
8416
+       part = xstrdup(inpart);
 
8417
+       acl = xstrdup(inacl);
 
8418
+    }
 
8419
+
 
8420
+    /* if we are not moving a user, just move the one mailbox */
 
8421
+    if(!r && !moving_user) {
 
8422
+       r = do_xfer_single(toserver, topart, name, mailboxname, mbflags,
 
8423
+                          path, part, acl, 0, NULL, NULL);
 
8424
+    } else if (!r) {
 
8425
+       struct backend *be = NULL;
 
8426
+       
 
8427
+       /* we need to reserve the users inbox - connect to mupdate */
 
8428
+       if(!r && config_mupdate_server) {
 
8429
+           r = mupdate_connect(config_mupdate_server, NULL, &mupdate_h, NULL);
 
8430
+           if(r) {
 
8431
+               syslog(LOG_ERR,
 
8432
+                      "Could not move mailbox: %s, MUPDATE connect failed",
 
8433
+                      mailboxname);
 
8434
+               goto done;
 
8435
+           }
 
8436
+       }
 
8437
+
 
8438
+       /* Get a single connection to the remote backend */
 
8439
+       be = backend_connect(NULL, toserver, &protocol[PROTOCOL_IMAP], "", NULL);
 
8440
+       if(!be) {
 
8441
+           r = IMAP_SERVER_UNAVAILABLE;
 
8442
+           syslog(LOG_ERR,
 
8443
+                  "Could not move mailbox: %s, " \
 
8444
+                  "Initial backend connect failed",
 
8445
+                  mailboxname);
 
8446
+       }
 
8447
+
 
8448
+       /* deactivate their inbox */
 
8449
+       if(!r && mupdate_h) {
 
8450
+           /* Note we are making the reservation on OUR host so that recovery
 
8451
+            * make sense */
 
8452
+           snprintf(buf, sizeof(buf), "%s!%s", config_servername, part);
 
8453
+           r = mupdate_deactivate(mupdate_h, mailboxname, buf);
 
8454
+           if(r) syslog(LOG_ERR,
 
8455
+                        "Could deactivate mailbox: %s, during move",
 
8456
+                        mailboxname);
 
8457
+           else backout_mupdate = 1;
 
8458
+       }
 
8459
+
 
8460
+       /* If needed, set an uppermost quota root */
 
8461
+       if(!r) {
 
8462
+           struct quota quota;
 
8463
+           
 
8464
+           quota.root = mailboxname;
 
8465
+           r = quota_read(&quota, NULL, 0);
 
8466
+           
 
8467
+           if(!r) {
 
8468
+               /* note use of + to force the setting of a nonexistant
 
8469
+                * quotaroot */
 
8470
+               prot_printf(be->out, "Q01 SETQUOTA {%lu+}\r\n" \
 
8471
+                           "+%s (STORAGE %d)\r\n",
 
8472
+                           (unsigned long) strlen(name)+1,
 
8473
+                           name, quota.limit);
 
8474
+               r = getresult(be->in, "Q01");
 
8475
+               if(r) syslog(LOG_ERR,
 
8476
+                            "Could not move mailbox: %s, " \
 
8477
+                            "failed setting initial quota root\r\n",
 
8478
+                            mailboxname);
 
8479
+           }
 
8480
+           else if (r == IMAP_QUOTAROOT_NONEXISTENT) r = 0;
 
8481
+       }
 
8482
+
 
8483
+
 
8484
+       /* recursively move all sub-mailboxes, using internal names */
 
8485
+       if(!r) {
 
8486
+           struct xfer_user_rock rock;
 
8487
+
 
8488
+           rock.toserver = toserver;
 
8489
+           rock.topart = topart;
 
8490
+           rock.h = mupdate_h;
 
8491
+           rock.be = be;
 
8492
+
 
8493
+           snprintf(buf, sizeof(buf), "%s.*", mailboxname);
 
8494
+           r = mboxlist_findall(NULL, buf, 1, imapd_userid,
 
8495
+                                imapd_authstate, xfer_user_cb,
 
8496
+                                &rock);
 
8497
+       }
 
8498
+
 
8499
+       /* xxx how do you back out if one of the above moves fails? */
 
8500
+           
 
8501
+       /* move this mailbox */
 
8502
+       /* ...and seen file, and subs file, and sieve scripts... */
 
8503
+       if(!r) {
 
8504
+           r = do_xfer_single(toserver, topart, name, mailboxname, mbflags,
 
8505
+                              path, part, acl, 1, mupdate_h, be);
 
8506
+       }
 
8507
+
 
8508
+       if(be) {
 
8509
+           backend_disconnect(be, &protocol[PROTOCOL_IMAP]);
 
8510
+           free(be);
 
8511
+       }
 
8512
+
 
8513
+       if(r && mupdate_h && backout_mupdate) {
 
8514
+           int rerr = 0;
 
8515
+           /* xxx if the mupdate server is what failed, then this won't
 
8516
+              help any! */
 
8517
+           snprintf(buf, sizeof(buf), "%s!%s", config_servername, part);
 
8518
+           rerr = mupdate_activate(mupdate_h, mailboxname, buf, acl);
 
8519
+           if(rerr) {
 
8520
+               syslog(LOG_ERR,
 
8521
+                      "Could not back out mupdate during move of %s (%s)",
 
8522
+                      mailboxname, error_message(rerr));
 
8523
+           }
 
8524
+       } else if(!r) {
 
8525
+           /* this was a successful user delete, and we need to delete
 
8526
+              certain user meta-data (but not seen state!) */
 
8527
+           user_deletedata(mailboxname+5, imapd_userid, imapd_authstate, 0);
 
8528
+       }
 
8529
+       
 
8530
+       if(!r && mupdate_h) {
 
8531
+           mupdate_disconnect(&mupdate_h);
 
8532
+       }
 
8533
+    }
 
8534
+
 
8535
+ done:
 
8536
+    if(part) free(part);
 
8537
+    if(path) free(path);
 
8538
+    if(acl) free(acl);
 
8539
+
 
8540
+    if (r) {
 
8541
+       prot_printf(imapd_out, "%s NO %s\r\n",
 
8542
+                   tag,
 
8543
+                   error_message(r));
 
8544
+    } else {
 
8545
+       prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
8546
+                   error_message(IMAP_OK_COMPLETED));
 
8547
+    }
 
8548
+
 
8549
+    return;
 
8550
+}
 
8551
+
 
8552
+/*
 
8553
+ * Parse a "date", for SEARCH criteria
 
8554
+ * The time_t's pointed to by 'start' and 'end' are set to the
 
8555
+ * times of the start and end of the parsed date.
 
8556
+ */
 
8557
+int getsearchdate(start, end)
 
8558
+time_t *start, *end;
 
8559
+{
 
8560
+    int c;
 
8561
+    struct tm tm;
 
8562
+    int quoted = 0;
 
8563
+    char month[4];
 
8564
+
 
8565
+    memset(&tm, 0, sizeof tm);
 
8566
+
 
8567
+    c = prot_getc(imapd_in);
 
8568
+    if (c == '\"') {
 
8569
+       quoted++;
 
8570
+       c = prot_getc(imapd_in);
 
8571
+    }
 
8572
+
 
8573
+    /* Day of month */
 
8574
+    if (!isdigit(c)) goto baddate;
 
8575
+    tm.tm_mday = c - '0';
 
8576
+    c = prot_getc(imapd_in);
 
8577
+    if (isdigit(c)) {
 
8578
+       tm.tm_mday = tm.tm_mday * 10 + c - '0';
 
8579
+       c = prot_getc(imapd_in);
 
8580
+    }
 
8581
+    
 
8582
+    if (c != '-') goto baddate;
 
8583
+    c = prot_getc(imapd_in);
 
8584
+
 
8585
+    /* Month name */
 
8586
+    if (!isalpha(c)) goto baddate;
 
8587
+    month[0] = c;
 
8588
+    c = prot_getc(imapd_in);
 
8589
+    if (!isalpha(c)) goto baddate;
 
8590
+    month[1] = c;
 
8591
+    c = prot_getc(imapd_in);
 
8592
+    if (!isalpha(c)) goto baddate;
 
8593
+    month[2] = c;
 
8594
+    c = prot_getc(imapd_in);
 
8595
+    month[3] = '\0';
 
8596
+    lcase(month);
 
8597
+
 
8598
+    for (tm.tm_mon = 0; tm.tm_mon < 12; tm.tm_mon++) {
 
8599
+       if (!strcmp(month, monthname[tm.tm_mon])) break;
 
8600
+    }
 
8601
+    if (tm.tm_mon == 12) goto baddate;
 
8602
+
 
8603
+    if (c != '-') goto baddate;
 
8604
+    c = prot_getc(imapd_in);
 
8605
+
 
8606
+    /* Year */
 
8607
+    if (!isdigit(c)) goto baddate;
 
8608
+    tm.tm_year = c - '0';
 
8609
+    c = prot_getc(imapd_in);
 
8610
+    if (!isdigit(c)) goto baddate;
 
8611
+    tm.tm_year = tm.tm_year * 10 + c - '0';
 
8612
+    c = prot_getc(imapd_in);
 
8613
+    if (isdigit(c)) {
 
8614
+       if (tm.tm_year < 19) goto baddate;
 
8615
+       tm.tm_year -= 19;
 
8616
+       tm.tm_year = tm.tm_year * 10 + c - '0';
 
8617
+       c = prot_getc(imapd_in);
 
8618
+       if (!isdigit(c)) goto baddate;
 
8619
+       tm.tm_year = tm.tm_year * 10 + c - '0';
 
8620
+       c = prot_getc(imapd_in);
 
8621
+    }
 
8622
+
 
8623
+    if (quoted) {
 
8624
+       if (c != '\"') goto baddate;
 
8625
+       c = prot_getc(imapd_in);
 
8626
+    }
 
8627
+
 
8628
+    tm.tm_isdst = -1;
 
8629
+    *start = mktime(&tm);
 
8630
+
 
8631
+    tm.tm_sec = tm.tm_min = 59;
 
8632
+    tm.tm_hour = 23;
 
8633
+    tm.tm_isdst = -1;
 
8634
+    *end = mktime(&tm);
 
8635
+
 
8636
+    return c;
 
8637
+
 
8638
+ baddate:
 
8639
+    prot_ungetc(c, imapd_in);
 
8640
+    return EOF;
 
8641
+}
 
8642
+
 
8643
+#define SORTGROWSIZE   10
 
8644
+
 
8645
+/*
 
8646
+ * Parse sort criteria
 
8647
+ */
 
8648
+int getsortcriteria(char *tag, struct sortcrit **sortcrit)
 
8649
+{
 
8650
+    int c;
 
8651
+    static struct buf criteria;
 
8652
+    int nsort, n;
 
8653
+
 
8654
+    *sortcrit = NULL;
 
8655
+
 
8656
+    c = prot_getc(imapd_in);
 
8657
+    if (c != '(') goto missingcrit;
 
8658
+
 
8659
+    c = getword(imapd_in, &criteria);
 
8660
+    if (criteria.s[0] == '\0') goto missingcrit;
 
8661
+
 
8662
+    nsort = 0;
 
8663
+    n = 0;
 
8664
+    for (;;) {
 
8665
+       if (n >= nsort - 1) {   /* leave room for implicit criterion */
 
8666
+           /* (Re)allocate an array for sort criteria */
 
8667
+           nsort += SORTGROWSIZE;
 
8668
+           *sortcrit =
 
8669
+               (struct sortcrit *) xrealloc(*sortcrit,
 
8670
+                                            nsort * sizeof(struct sortcrit));
 
8671
+           /* Zero out the newly added sortcrit */
 
8672
+           memset((*sortcrit)+n, 0, SORTGROWSIZE * sizeof(struct sortcrit));
 
8673
+       }
 
8674
+
 
8675
+       lcase(criteria.s);
 
8676
+       if (!strcmp(criteria.s, "reverse")) {
 
8677
+           (*sortcrit)[n].flags |= SORT_REVERSE;
 
8678
+           goto nextcrit;
 
8679
+       }
 
8680
+       else if (!strcmp(criteria.s, "arrival"))
 
8681
+           (*sortcrit)[n].key = SORT_ARRIVAL;
 
8682
+       else if (!strcmp(criteria.s, "cc"))
 
8683
+           (*sortcrit)[n].key = SORT_CC;
 
8684
+       else if (!strcmp(criteria.s, "date"))
 
8685
+           (*sortcrit)[n].key = SORT_DATE;
 
8686
+       else if (!strcmp(criteria.s, "from"))
 
8687
+           (*sortcrit)[n].key = SORT_FROM;
 
8688
+       else if (!strcmp(criteria.s, "size"))
 
8689
+           (*sortcrit)[n].key = SORT_SIZE;
 
8690
+       else if (!strcmp(criteria.s, "subject"))
 
8691
+           (*sortcrit)[n].key = SORT_SUBJECT;
 
8692
+       else if (!strcmp(criteria.s, "to"))
 
8693
+           (*sortcrit)[n].key = SORT_TO;
 
8694
+#if 0
 
8695
+       else if (!strcmp(criteria.s, "annotation")) {
 
8696
+           (*sortcrit)[n].key = SORT_ANNOTATION;
 
8697
+           if (c != ' ') goto missingarg;
 
8698
+           c = getstring(imapd_in, &arg);
 
8699
+           if (c != ' ') goto missingarg;
 
8700
+           (*sortcrit)[n].args.annot.entry = xstrdup(arg.s);
 
8701
+           c = getstring(imapd_in, &arg);
 
8702
+           if (c == EOF) goto missingarg;
 
8703
+           (*sortcrit)[n].args.annot.attrib = xstrdup(arg.s);
 
8704
+       }
 
8705
+#endif
 
8706
+       else {
 
8707
+           prot_printf(imapd_out, "%s BAD Invalid Sort criterion %s\r\n",
 
8708
+                       tag, criteria.s);
 
8709
+           if (c != EOF) prot_ungetc(c, imapd_in);
 
8710
+           return EOF;
 
8711
+       }
 
8712
+
 
8713
+       n++;
 
8714
+
 
8715
+ nextcrit:
 
8716
+       if (c == ' ') c = getword(imapd_in, &criteria);
 
8717
+       else break;
 
8718
+    }
 
8719
+
 
8720
+    if ((*sortcrit)[n].flags & SORT_REVERSE  && !(*sortcrit)[n].key) {
 
8721
+       prot_printf(imapd_out,
 
8722
+                   "%s BAD Missing Sort criterion to reverse\r\n", tag);
 
8723
+       if (c != EOF) prot_ungetc(c, imapd_in);
 
8724
+       return EOF;
 
8725
+    }
 
8726
+
 
8727
+    if (c != ')') {
 
8728
+       prot_printf(imapd_out,
 
8729
+                   "%s BAD Missing close parenthesis in Sort\r\n", tag);
 
8730
+       if (c != EOF) prot_ungetc(c, imapd_in);
 
8731
+       return EOF;
 
8732
+    }
 
8733
+
 
8734
+    /* Terminate the list with the implicit sort criterion */
 
8735
+    (*sortcrit)[n++].key = SORT_SEQUENCE;
 
8736
+
 
8737
+    c = prot_getc(imapd_in);
 
8738
+
 
8739
+    return c;
 
8740
+
 
8741
+ missingcrit:
 
8742
+    prot_printf(imapd_out, "%s BAD Missing Sort criteria\r\n", tag);
 
8743
+    if (c != EOF) prot_ungetc(c, imapd_in);
 
8744
+    return EOF;
 
8745
+#if 0 /* For annotations stuff above */
 
8746
+ missingarg:
 
8747
+    prot_printf(imapd_out, "%s BAD Missing argument to Sort criterion %s\r\n",
 
8748
+               tag, criteria.s);
 
8749
+    if (c != EOF) prot_ungetc(c, imapd_in);
 
8750
+    return EOF;
 
8751
+#endif
 
8752
+}
 
8753
+
 
8754
+#ifdef ENABLE_LISTEXT
 
8755
+/*
 
8756
+ * Parse LIST options.
 
8757
+ * The command has been parsed up to and including the opening '('.
 
8758
+ */
 
8759
+int getlistopts(char *tag, int *listopts)
 
8760
+{
 
8761
+    int c;
 
8762
+    static struct buf arg;
 
8763
+
 
8764
+    *listopts = LIST_EXT;
 
8765
+
 
8766
+    for (;;) {
 
8767
+       c = getword(imapd_in, &arg);
 
8768
+       if (!arg.s[0]) break;
 
8769
+
 
8770
+       lcase(arg.s);
 
8771
+       if (!strcmp(arg.s, "subscribed")) {
 
8772
+           *listopts |= LIST_SUBSCRIBED;
 
8773
+       }
 
8774
+       else if (!strcmp(arg.s, "children")) {
 
8775
+           *listopts |= LIST_CHILDREN;
 
8776
+       }
 
8777
+       else if (!strcmp(arg.s, "remote")) {
 
8778
+           *listopts |= LIST_REMOTE;
 
8779
+       }
 
8780
+       else {
 
8781
+           prot_printf(imapd_out, "%s BAD Invalid List option %s\r\n",
 
8782
+                       tag, arg.s);
 
8783
+           return EOF;
 
8784
+       }
 
8785
+
 
8786
+       if (c != ' ') break;
 
8787
+    }
 
8788
+
 
8789
+    if (c != ')') {
 
8790
+       prot_printf(imapd_out,
 
8791
+                   "%s BAD Missing close parenthesis in List\r\n", tag);
 
8792
+       return EOF;
 
8793
+    }
 
8794
+
 
8795
+    c = prot_getc(imapd_in);
 
8796
+
 
8797
+    return c;
 
8798
+}
 
8799
+#endif /* ENABLE_LISTEXT */
 
8800
+
 
8801
+/*
 
8802
+ * Parse a date_time, for the APPEND command
 
8803
+ */
 
8804
+int getdatetime(date)
 
8805
+time_t *date;
 
8806
+{
 
8807
+    int c;
 
8808
+    struct tm tm;
 
8809
+    int old_format = 0;
 
8810
+    char month[4], zone[4], *p;
 
8811
+    time_t tmp_gmtime;
 
8812
+    int zone_off;
 
8813
+
 
8814
+    memset(&tm, 0, sizeof tm);
 
8815
+
 
8816
+    c = prot_getc(imapd_in);
 
8817
+    if (c != '\"') goto baddate;
 
8818
+    
 
8819
+    /* Day of month */
 
8820
+    c = prot_getc(imapd_in);
 
8821
+    if (c == ' ') c = '0';
 
8822
+    if (!isdigit(c)) goto baddate;
 
8823
+    tm.tm_mday = c - '0';
 
8824
+    c = prot_getc(imapd_in);
 
8825
+    if (isdigit(c)) {
 
8826
+       tm.tm_mday = tm.tm_mday * 10 + c - '0';
 
8827
+       c = prot_getc(imapd_in);
 
8828
+       if(tm.tm_mday <= 0 || tm.tm_mday > 31)
 
8829
+           goto baddate;
 
8830
+    }
 
8831
+    
 
8832
+    if (c != '-') goto baddate;
 
8833
+    c = prot_getc(imapd_in);
 
8834
+
 
8835
+    /* Month name */
 
8836
+    if (!isalpha(c)) goto baddate;
 
8837
+    month[0] = c;
 
8838
+    c = prot_getc(imapd_in);
 
8839
+    if (!isalpha(c)) goto baddate;
 
8840
+    month[1] = c;
 
8841
+    c = prot_getc(imapd_in);
 
8842
+    if (!isalpha(c)) goto baddate;
 
8843
+    month[2] = c;
 
8844
+    c = prot_getc(imapd_in);
 
8845
+    month[3] = '\0';
 
8846
+    lcase(month);
 
8847
+
 
8848
+    for (tm.tm_mon = 0; tm.tm_mon < 12; tm.tm_mon++) {
 
8849
+       if (!strcmp(month, monthname[tm.tm_mon])) break;
 
8850
+    }
 
8851
+    if (tm.tm_mon == 12) goto baddate;
 
8852
+    /* xxx this doesn't quite work in leap years */
 
8853
+    if (tm.tm_mday > max_monthdays[tm.tm_mon]) goto baddate;
 
8854
+
 
8855
+    if (c != '-') goto baddate;
 
8856
+    c = prot_getc(imapd_in);
 
8857
+
 
8858
+    /* Year */
 
8859
+    if (!isdigit(c)) goto baddate;
 
8860
+    tm.tm_year = c - '0';
 
8861
+    c = prot_getc(imapd_in);
 
8862
+    if (!isdigit(c)) goto baddate;
 
8863
+    tm.tm_year = tm.tm_year * 10 + c - '0';
 
8864
+    c = prot_getc(imapd_in);
 
8865
+    if (isdigit(c)) {
 
8866
+       if (tm.tm_year < 19) goto baddate;
 
8867
+       tm.tm_year -= 19;
 
8868
+       tm.tm_year = tm.tm_year * 10 + c - '0';
 
8869
+       c = prot_getc(imapd_in);
 
8870
+       if (!isdigit(c)) goto baddate;
 
8871
+       tm.tm_year = tm.tm_year * 10 + c - '0';
 
8872
+       c = prot_getc(imapd_in);
 
8873
+    }
 
8874
+    else old_format++;
 
8875
+
 
8876
+    /* Hour */
 
8877
+    if (c != ' ') goto baddate;
 
8878
+    c = prot_getc(imapd_in);
 
8879
+    if (!isdigit(c)) goto baddate;
 
8880
+    tm.tm_hour = c - '0';
 
8881
+    c = prot_getc(imapd_in);
 
8882
+    if (!isdigit(c)) goto baddate;
 
8883
+    tm.tm_hour = tm.tm_hour * 10 + c - '0';
 
8884
+    c = prot_getc(imapd_in);
 
8885
+    if (tm.tm_hour > 23) goto baddate;
 
8886
+
 
8887
+    /* Minute */
 
8888
+    if (c != ':') goto baddate;
 
8889
+    c = prot_getc(imapd_in);
 
8890
+    if (!isdigit(c)) goto baddate;
 
8891
+    tm.tm_min = c - '0';
 
8892
+    c = prot_getc(imapd_in);
 
8893
+    if (!isdigit(c)) goto baddate;
 
8894
+    tm.tm_min = tm.tm_min * 10 + c - '0';
 
8895
+    c = prot_getc(imapd_in);
 
8896
+    if (tm.tm_min > 59) goto baddate;
 
8897
+
 
8898
+    /* Second */
 
8899
+    if (c != ':') goto baddate;
 
8900
+    c = prot_getc(imapd_in);
 
8901
+    if (!isdigit(c)) goto baddate;
 
8902
+    tm.tm_sec = c - '0';
 
8903
+    c = prot_getc(imapd_in);
 
8904
+    if (!isdigit(c)) goto baddate;
 
8905
+    tm.tm_sec = tm.tm_sec * 10 + c - '0';
 
8906
+    c = prot_getc(imapd_in);
 
8907
+    if (tm.tm_min > 60) goto baddate;
 
8908
+
 
8909
+    /* Time zone */
 
8910
+    if (old_format) {
 
8911
+       if (c != '-') goto baddate;
 
8912
+       c = prot_getc(imapd_in);
 
8913
+
 
8914
+       if (!isalpha(c)) goto baddate;
 
8915
+       zone[0] = c;
 
8916
+       c = prot_getc(imapd_in);
 
8917
+
 
8918
+       if (c == '\"') {
 
8919
+           /* Military (single-char) zones */
 
8920
+           zone[1] = '\0';
 
8921
+           lcase(zone);
 
8922
+           if (zone[0] <= 'm') {
 
8923
+               zone_off = (zone[0] - 'a' + 1)*60;
 
8924
+           }
 
8925
+           else if (zone[0] < 'z') {
 
8926
+               zone_off = ('m' - zone[0])*60;
 
8927
+           }
 
8928
+           else zone_off = 0;
 
8929
+       }
 
8930
+       else {
 
8931
+           /* UT (universal time) */
 
8932
+           zone[1] = c;
 
8933
+           c = prot_getc(imapd_in);
 
8934
+           if (c == '\"') {
 
8935
+               zone[2] = '\0';
 
8936
+               lcase(zone);
 
8937
+               if (!strcmp(zone, "ut")) goto baddate;
 
8938
+               zone_off = 0;
 
8939
+           }
 
8940
+           else {
 
8941
+               /* 3-char time zone */
 
8942
+               zone[2] = c;
 
8943
+               c = prot_getc(imapd_in);
 
8944
+               if (c != '\"') goto baddate;
 
8945
+               zone[3] = '\0';
 
8946
+               lcase(zone);
 
8947
+               p = strchr("aecmpyhb", zone[0]);
 
8948
+               if (c != '\"' || zone[2] != 't' || !p) goto baddate;
 
8949
+               zone_off = (strlen(p) - 12)*60;
 
8950
+               if (zone[1] == 'd') zone_off -= 60;
 
8951
+               else if (zone[1] != 's') goto baddate;
 
8952
+           }
 
8953
+       }
 
8954
+    }
 
8955
+    else {
 
8956
+       if (c != ' ') goto baddate;
 
8957
+       c = prot_getc(imapd_in);
 
8958
+
 
8959
+       if (c != '+' && c != '-') goto baddate;
 
8960
+       zone[0] = c;
 
8961
+
 
8962
+       c = prot_getc(imapd_in);
 
8963
+       if (!isdigit(c)) goto baddate;
 
8964
+       zone_off = c - '0';
 
8965
+       c = prot_getc(imapd_in);
 
8966
+       if (!isdigit(c)) goto baddate;
 
8967
+       zone_off = zone_off * 10 + c - '0';
 
8968
+       c = prot_getc(imapd_in);
 
8969
+       if (!isdigit(c)) goto baddate;
 
8970
+       zone_off = zone_off * 6 + c - '0';
 
8971
+       c = prot_getc(imapd_in);
 
8972
+       if (!isdigit(c)) goto baddate;
 
8973
+       zone_off = zone_off * 10 + c - '0';
 
8974
+
 
8975
+       if (zone[0] == '-') zone_off = -zone_off;
 
8976
+
 
8977
+       c = prot_getc(imapd_in);
 
8978
+       if (c != '\"') goto baddate;
 
8979
+
 
8980
+    }
 
8981
+
 
8982
+    c = prot_getc(imapd_in);
 
8983
+
 
8984
+    tm.tm_isdst = -1;
 
8985
+
 
8986
+    tmp_gmtime = mkgmtime(&tm);
 
8987
+    if(tmp_gmtime == -1) goto baddate;
 
8988
+
 
8989
+    *date = tmp_gmtime - zone_off*60;
 
8990
+
 
8991
+    return c;
 
8992
+
 
8993
+ baddate:
 
8994
+    prot_ungetc(c, imapd_in);
 
8995
+    return EOF;
 
8996
+}
 
8997
+
 
8998
+/*
 
8999
+ * Print 's' as a quoted-string or literal (but not an atom)
 
9000
+ */
 
9001
+void
 
9002
+printstring(s)
 
9003
+const char *s;
 
9004
+{
 
9005
+    const char *p;
 
9006
+    int len = 0;
 
9007
+
 
9008
+    /* Look for any non-QCHAR characters */
 
9009
+    for (p = s; *p && len < 1024; p++) {
 
9010
+       len++;
 
9011
+       if (*p & 0x80 || *p == '\r' || *p == '\n'
 
9012
+           || *p == '\"' || *p == '%' || *p == '\\') break;
 
9013
+    }
 
9014
+
 
9015
+    /* if it's too long, literal it */
 
9016
+    if (*p || len >= 1024) {
 
9017
+       prot_printf(imapd_out, "{%lu}\r\n%s", (unsigned long) strlen(s), s);
 
9018
+    } else {
 
9019
+       prot_printf(imapd_out, "\"%s\"", s);
 
9020
+    }
 
9021
+}
 
9022
+
 
9023
+/*
 
9024
+ * Print 's' as an atom, quoted-string, or literal
 
9025
+ */
 
9026
+void
 
9027
+printastring(s)
 
9028
+const char *s;
 
9029
+{
 
9030
+    const char *p;
 
9031
+    int len = 0;
 
9032
+
 
9033
+    if (imparse_isatom(s)) {
 
9034
+       prot_printf(imapd_out, "%s", s);
 
9035
+       return;
 
9036
+    }
 
9037
+
 
9038
+    /* Look for any non-QCHAR characters */
 
9039
+    for (p = s; *p && len < 1024; p++) {
 
9040
+       len++;
 
9041
+       if (*p & 0x80 || *p == '\r' || *p == '\n'
 
9042
+           || *p == '\"' || *p == '%' || *p == '\\') break;
 
9043
+    }
 
9044
+
 
9045
+    /* if it's too long, literal it */
 
9046
+    if (*p || len >= 1024) {
 
9047
+       prot_printf(imapd_out, "{%lu}\r\n%s", (unsigned long) strlen(s), s);
 
9048
+    } else {
 
9049
+       prot_printf(imapd_out, "\"%s\"", s);
 
9050
+    }
 
9051
+}
 
9052
+
 
9053
+/*
 
9054
+ * Append 'section', 'fields', 'trail' to the fieldlist 'l'.
 
9055
+ */
 
9056
+void
 
9057
+appendfieldlist(struct fieldlist **l, char *section,
 
9058
+               struct strlist *fields, char *trail,
 
9059
+               void *d, size_t size)
 
9060
+{
 
9061
+    struct fieldlist **tail = l;
 
9062
+
 
9063
+    while (*tail) tail = &(*tail)->next;
 
9064
+
 
9065
+    *tail = (struct fieldlist *)xmalloc(sizeof(struct fieldlist));
 
9066
+    (*tail)->section = xstrdup(section);
 
9067
+    (*tail)->fields = fields;
 
9068
+    (*tail)->trail = xstrdup(trail);
 
9069
+    if(d && size) {
 
9070
+       (*tail)->rock = xmalloc(size);
 
9071
+       memcpy((*tail)->rock, d, size);
 
9072
+    } else {
 
9073
+       (*tail)->rock = NULL;
 
9074
+    }
 
9075
+    (*tail)->next = 0;
 
9076
+}
 
9077
+
 
9078
+
 
9079
+/*
 
9080
+ * Free the fieldlist 'l'
 
9081
+ */
 
9082
+void freefieldlist(struct fieldlist *l)
 
9083
+{
 
9084
+    struct fieldlist *n;
 
9085
+
 
9086
+    while (l) {
 
9087
+       n = l->next;
 
9088
+       free(l->section);
 
9089
+       freestrlist(l->fields);
 
9090
+       free(l->trail);
 
9091
+       if (l->rock) free(l->rock);
 
9092
+       free((char *)l);
 
9093
+       l = n;
 
9094
+    }
 
9095
+}
 
9096
+
 
9097
+/*
 
9098
+ * Append the searchargs 's1' and 's2' to the sublist of 's'
 
9099
+ */
 
9100
+void
 
9101
+appendsearchargs(s, s1, s2)
 
9102
+struct searchargs *s, *s1, *s2;
 
9103
+{
 
9104
+    struct searchsub **tail = &s->sublist;
 
9105
+
 
9106
+    while (*tail) tail = &(*tail)->next;
 
9107
+
 
9108
+    *tail = (struct searchsub *)xmalloc(sizeof(struct searchsub));
 
9109
+    (*tail)->sub1 = s1;
 
9110
+    (*tail)->sub2 = s2;
 
9111
+    (*tail)->next = 0;
 
9112
+}
 
9113
+
 
9114
+
 
9115
+/*
 
9116
+ * Free the searchargs 's'
 
9117
+ */
 
9118
+void
 
9119
+freesearchargs(s)
 
9120
+struct searchargs *s;
 
9121
+{
 
9122
+    struct searchsub *sub, *n;
 
9123
+
 
9124
+    if (!s) return;
 
9125
+
 
9126
+    freestrlist(s->sequence);
 
9127
+    freestrlist(s->uidsequence);
 
9128
+    freestrlist(s->from);
 
9129
+    freestrlist(s->to);
 
9130
+    freestrlist(s->cc);
 
9131
+    freestrlist(s->bcc);
 
9132
+    freestrlist(s->subject);
 
9133
+    freestrlist(s->body);
 
9134
+    freestrlist(s->text);
 
9135
+    freestrlist(s->header_name);
 
9136
+    freestrlist(s->header);
 
9137
+
 
9138
+    for (sub = s->sublist; sub; sub = n) {
 
9139
+       n = sub->next;
 
9140
+       freesearchargs(sub->sub1);
 
9141
+       freesearchargs(sub->sub2);
 
9142
+       free(sub);
 
9143
+    }
 
9144
+    free(s);
 
9145
+}
 
9146
+
 
9147
+/*
 
9148
+ * Free an array of sortcrit
 
9149
+ */
 
9150
+static void freesortcrit(struct sortcrit *s)
 
9151
+{
 
9152
+    int i = 0;
 
9153
+
 
9154
+    if (!s) return;
 
9155
+    do {
 
9156
+       switch (s[i].key) {
 
9157
+       case SORT_ANNOTATION:
 
9158
+           free(s[i].args.annot.entry);
 
9159
+           free(s[i].args.annot.attrib);
 
9160
+           break;
 
9161
+       }
 
9162
+       i++;
 
9163
+    } while (s[i].key != SORT_SEQUENCE);
 
9164
+    free(s);
 
9165
+}
 
9166
+
 
9167
+/*
 
9168
+ * Issue a MAILBOX untagged response
 
9169
+ */
 
9170
+static int mailboxdata(char *name,
 
9171
+                      int matchlen __attribute__((unused)),
 
9172
+                      int maycreate __attribute__((unused)),
 
9173
+                      void *rock __attribute__((unused)))
 
9174
+{
 
9175
+    char mboxname[MAX_MAILBOX_PATH+1];
 
9176
+
 
9177
+    (*imapd_namespace.mboxname_toexternal)(&imapd_namespace, name,
 
9178
+                                          imapd_userid, mboxname);
 
9179
+    prot_printf(imapd_out, "* MAILBOX %s\r\n", mboxname);
 
9180
+    return 0;
 
9181
+}
 
9182
+
 
9183
+/*
 
9184
+ * Issue a LIST or LSUB untagged response
 
9185
+ */
 
9186
+static void mstringdata(char *cmd, char *name, int matchlen, int maycreate,
 
9187
+                       int listopts)
 
9188
+{
 
9189
+    static char lastname[MAX_MAILBOX_PATH+1];
 
9190
+    static int lastnamedelayed = 0;
 
9191
+    static int lastnamenoinferiors = 0;
 
9192
+    static int nonexistent = 0;
 
9193
+    static int sawuser = 0;
 
9194
+    int lastnamehassub = 0;
 
9195
+    int c, mbtype;
 
9196
+    char mboxname[MAX_MAILBOX_PATH+1];
 
9197
+
 
9198
+    /* We have to reset the sawuser flag before each list command.
 
9199
+     * Handle it as a dirty hack.
 
9200
+     */
 
9201
+    if (cmd == NULL) {
 
9202
+       sawuser = 0;
 
9203
+       mstringdatacalls = 0;
 
9204
+       return;
 
9205
+    }
 
9206
+    mstringdatacalls++;
 
9207
+
 
9208
+    if (lastnamedelayed) {
 
9209
+       /* Check if lastname has children */
 
9210
+       if (name && strncmp(lastname, name, strlen(lastname)) == 0 &&
 
9211
+           name[strlen(lastname)] == '.') {
 
9212
+           lastnamehassub = 1;
 
9213
+       }
 
9214
+       prot_printf(imapd_out, "* %s (", cmd);
 
9215
+       if (nonexistent == IMAP_MAILBOX_RESERVED) {
 
9216
+           /* LISTEXT wants \\PlaceHolder instead of \\Noselect */
 
9217
+           if (listopts & LIST_EXT)
 
9218
+               prot_printf(imapd_out, "\\PlaceHolder");
 
9219
+           else
 
9220
+               prot_printf(imapd_out, "\\Noselect");
 
9221
+       } else if (nonexistent) {
 
9222
+           prot_printf(imapd_out, "\\NonExistent");
 
9223
+       }
 
9224
+       if (lastnamenoinferiors) {
 
9225
+           prot_printf(imapd_out, "%s\\Noinferiors", nonexistent ? " " : "");
 
9226
+       }
 
9227
+       else if ((listopts & LIST_CHILDREN) &&
 
9228
+                /* we can't determine \HasNoChildren for subscriptions */
 
9229
+                (lastnamehassub ||
 
9230
+                 !(listopts & (LIST_LSUB | LIST_SUBSCRIBED)))) {
 
9231
+           prot_printf(imapd_out, "%s%s", nonexistent ? " " : "",
 
9232
+                       lastnamehassub ? "\\HasChildren" : "\\HasNoChildren");
 
9233
+       }
 
9234
+       prot_printf(imapd_out, ") \"%c\" ", imapd_namespace.hier_sep);
 
9235
+                   
 
9236
+       (*imapd_namespace.mboxname_toexternal)(&imapd_namespace, lastname,
 
9237
+                                              imapd_userid, mboxname);
 
9238
+       printstring(mboxname);
 
9239
+       prot_printf(imapd_out, "\r\n");
 
9240
+       lastnamedelayed = lastnamenoinferiors = nonexistent = 0;
 
9241
+    }
 
9242
+
 
9243
+    /* Special-case to flush any final state */
 
9244
+    if (!name) {
 
9245
+       lastname[0] = '\0';
 
9246
+       return;
 
9247
+    }
 
9248
+
 
9249
+    /* Suppress any output of a partial match */
 
9250
+    if ((name[matchlen]
 
9251
+        && strncmp(lastname, name, matchlen) == 0
 
9252
+        && (lastname[matchlen] == '\0' || lastname[matchlen] == '.'))) {
 
9253
+       return;
 
9254
+    }
 
9255
+       
 
9256
+    /*
 
9257
+     * We can get a partial match for "user" multiple times with
 
9258
+     * other matches inbetween.  Handle it as a special case
 
9259
+     */
 
9260
+    if (matchlen == 4 && strncasecmp(name, "user", 4) == 0) {
 
9261
+       if (sawuser) return;
 
9262
+       sawuser = 1;
 
9263
+    }
 
9264
+
 
9265
+    strlcpy(lastname, name, sizeof(lastname));
 
9266
+    lastname[matchlen] = '\0';
 
9267
+    nonexistent = 0;
 
9268
+
 
9269
+    /* Now we need to see if this mailbox exists */
 
9270
+    /* first convert "INBOX" to "user.<userid>" */
 
9271
+    if (!strncasecmp(lastname, "inbox", 5)) {
 
9272
+       (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, "INBOX",
 
9273
+                                              imapd_userid, mboxname);
 
9274
+       strlcat(mboxname, lastname+5, sizeof(mboxname));
 
9275
+    }
 
9276
+    else
 
9277
+       strlcpy(mboxname, lastname, sizeof(mboxname));
 
9278
+
 
9279
+    /* Look it up */
 
9280
+    nonexistent = mboxlist_detail(mboxname, &mbtype,
 
9281
+                                 NULL, NULL, NULL, NULL);
 
9282
+    if(!nonexistent && (mbtype & MBTYPE_RESERVE))
 
9283
+       nonexistent = IMAP_MAILBOX_RESERVED;
 
9284
+
 
9285
+    if (!name[matchlen]) {
 
9286
+       lastnamedelayed = 1;
 
9287
+       if (!maycreate) lastnamenoinferiors = 1;
 
9288
+       return;
 
9289
+    }
 
9290
+
 
9291
+    c = name[matchlen];
 
9292
+    if (c) name[matchlen] = '\0';
 
9293
+    prot_printf(imapd_out, "* %s (", cmd);
 
9294
+    if (c) {
 
9295
+       /* Handle namespace prefix as a special case */ 
 
9296
+       if (!strcmp(name, "user") ||
 
9297
+           !strcmp(name, imapd_namespace.prefix[NAMESPACE_SHARED])) {
 
9298
+           prot_printf(imapd_out, "\\Noselect");
 
9299
+           if (listopts & LIST_EXT)
 
9300
+               prot_printf(imapd_out, " \\PlaceHolder");
 
9301
+       }
 
9302
+       else {
 
9303
+           if (nonexistent)
 
9304
+               prot_printf(imapd_out, "\\NonExistent");
 
9305
+           /* LISTEXT uses \PlaceHolder instead of \Noselect */
 
9306
+           if (listopts & LIST_EXT)
 
9307
+               prot_printf(imapd_out, "%s\\PlaceHolder", nonexistent ? " " : "");
 
9308
+           else
 
9309
+               prot_printf(imapd_out, "%s\\Noselect", nonexistent ? " " : "");
 
9310
+       }
 
9311
+       if (listopts & LIST_CHILDREN)
 
9312
+           prot_printf(imapd_out, " \\HasChildren");
 
9313
+    }
 
9314
+    prot_printf(imapd_out, ") \"%c\" ", imapd_namespace.hier_sep);
 
9315
+
 
9316
+    (*imapd_namespace.mboxname_toexternal)(&imapd_namespace, name,
 
9317
+                                          imapd_userid, mboxname);
 
9318
+    printstring(mboxname);
 
9319
+    prot_printf(imapd_out, "\r\n");
 
9320
+    if (c) name[matchlen] = c;
 
9321
+    return;
 
9322
+}
 
9323
+
 
9324
+/*
 
9325
+ * Issue a LIST untagged response
 
9326
+ */
 
9327
+static int listdata(char *name, int matchlen, int maycreate, void *rock)
 
9328
+{
 
9329
+    int listopts = *((int *)rock);
 
9330
+    
 
9331
+    mstringdata(((listopts & LIST_LSUB) ? "LSUB" : "LIST"),
 
9332
+       name, matchlen, maycreate, listopts);
 
9333
+
 
9334
+    return 0;
 
9335
+}
 
9336
+
 
9337
+/* Reset the given sasl_conn_t to a sane state */
 
9338
+static int reset_saslconn(sasl_conn_t **conn) 
 
9339
+{
 
9340
+    int ret;
 
9341
+    sasl_security_properties_t *secprops = NULL;
 
9342
+
 
9343
+    sasl_dispose(conn);
 
9344
+    /* do initialization typical of service_main */
 
9345
+    ret = sasl_server_new("imap", config_servername,
 
9346
+                         NULL, NULL, NULL,
 
9347
+                         NULL, 0, conn);
 
9348
+    if(ret != SASL_OK) return ret;
 
9349
+
 
9350
+    if(saslprops.ipremoteport)
 
9351
+       ret = sasl_setprop(*conn, SASL_IPREMOTEPORT,
 
9352
+                          saslprops.ipremoteport);
 
9353
+    if(ret != SASL_OK) return ret;
 
9354
+    
 
9355
+    if(saslprops.iplocalport)
 
9356
+       ret = sasl_setprop(*conn, SASL_IPLOCALPORT,
 
9357
+                          saslprops.iplocalport);
 
9358
+    if(ret != SASL_OK) return ret;
 
9359
+    
 
9360
+    secprops = mysasl_secprops(SASL_SEC_NOPLAINTEXT);
 
9361
+    ret = sasl_setprop(*conn, SASL_SEC_PROPS, secprops);
 
9362
+    if(ret != SASL_OK) return ret;
 
9363
+    /* end of service_main initialization excepting SSF */
 
9364
+
 
9365
+    /* If we have TLS/SSL info, set it */
 
9366
+    if(saslprops.ssf) {
 
9367
+       ret = sasl_setprop(*conn, SASL_SSF_EXTERNAL, &saslprops.ssf);
 
9368
+    } else {
 
9369
+       ret = sasl_setprop(*conn, SASL_SSF_EXTERNAL, &extprops_ssf);
 
9370
+    }
 
9371
+    if(ret != SASL_OK) return ret;
 
9372
+
 
9373
+    if(saslprops.authid) {
 
9374
+       ret = sasl_setprop(*conn, SASL_AUTH_EXTERNAL, saslprops.authid);
 
9375
+       if(ret != SASL_OK) return ret;
 
9376
+    }
 
9377
+    /* End TLS/SSL Info */
 
9378
+
 
9379
+    return SASL_OK;
 
9380
+}
 
9381
+
 
9382
+void cmd_mupdatepush(char *tag, char *name)
 
9383
+{
 
9384
+    int r = 0;
 
9385
+    char mailboxname[MAX_MAILBOX_NAME+1];
 
9386
+    char *part, *acl;
 
9387
+    mupdate_handle *mupdate_h = NULL;
 
9388
+    char buf[MAX_PARTITION_LEN + HOSTNAME_SIZE + 2];
 
9389
+
 
9390
+    if (!imapd_userisadmin) {
 
9391
+       r = IMAP_PERMISSION_DENIED;
 
9392
+    }
 
9393
+    if (!config_mupdate_server) {
 
9394
+       r = IMAP_SERVER_UNAVAILABLE;
 
9395
+    }
 
9396
+
 
9397
+    if (!r) {
 
9398
+       r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 
9399
+                                                  imapd_userid, mailboxname);
 
9400
+    }
 
9401
+
 
9402
+    if (!r) {
 
9403
+       r = mlookup(tag, name, mailboxname, NULL, NULL, &part, &acl, NULL);
 
9404
+    }
 
9405
+    if (r == IMAP_MAILBOX_MOVED) return;
 
9406
+
 
9407
+    /* Push mailbox to mupdate server */
 
9408
+    if (!r) {
 
9409
+       r = mupdate_connect(config_mupdate_server, NULL, &mupdate_h, NULL);
 
9410
+    }
 
9411
+
 
9412
+    if (!r) {
 
9413
+       snprintf(buf, sizeof(buf), "%s!%s", config_servername, part);
 
9414
+
 
9415
+       r = mupdate_activate(mupdate_h, mailboxname, buf, acl);
 
9416
+    }
 
9417
+
 
9418
+    if(mupdate_h) {
 
9419
+       mupdate_disconnect(&mupdate_h);
 
9420
+    }
 
9421
+
 
9422
+    if (r) {
 
9423
+       prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r));
 
9424
+    }
 
9425
+    else {
 
9426
+       prot_printf(imapd_out, "%s OK %s\r\n", tag,
 
9427
+                   error_message(IMAP_OK_COMPLETED));
 
9428
+    }
 
9429
+}
 
9430
diff -urNad cyrus-imapd-2.2.13/imap/pop3d.c /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/imap/pop3d.c
 
9431
--- cyrus-imapd-2.2.13/imap/pop3d.c     2006-04-18 20:39:34.000000000 +0200
 
9432
+++ /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/imap/pop3d.c    2006-04-18 20:39:35.702094974 +0200
 
9433
@@ -100,6 +100,10 @@
 
9434
 extern int opterr;
 
9435
 
223
9436
 
224
9437
+#ifdef DRAC_AUTH
225
9438
+static int drac_enabled;
226
9439
+extern int dracauth(char *server, unsigned long userip, char **errmsg);
227
9440
+#endif /* DRAC_AUTH */
228
9441
 
229
 
 #ifdef HAVE_UNISTD_H
230
 
 #include <unistd.h>
 
9442
 #ifdef HAVE_SSL
 
9443
 static SSL *tls_conn;
231
9444
@@ -408,6 +412,10 @@
232
9445
     prot_settimeout(popd_in, timeout*60);
233
9446
     prot_setflushonread(popd_in, popd_out);
239
9452
     if (kflag) kpop();
240
9453
 
241
9454
     /* we were connected on pop3s port so we should do 
242
 
@@ -1439,6 +1447,21 @@
 
9455
@@ -1450,6 +1458,21 @@
243
9456
        popd_mailbox = &mboxstruct;
244
9457
        proc_register("pop3d", popd_clienthost, popd_userid,
245
9458
                      popd_mailbox->name);
261
9474
     }
262
9475
 
263
9476
     /* Create telemetry log */
264
 
diff -urNad cyrus-imapd-2.2.12/imap/version.c /tmp/dpep.FoExSn/cyrus-imapd-2.2.12/imap/version.c
265
 
--- cyrus-imapd-2.2.12/imap/version.c   2006-02-11 23:57:19.000000000 +0100
266
 
+++ /tmp/dpep.FoExSn/cyrus-imapd-2.2.12/imap/version.c  2006-02-14 17:13:44.662437947 +0100
 
9477
diff -urNad cyrus-imapd-2.2.13/imap/pop3d.c.orig /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/imap/pop3d.c.orig
 
9478
--- cyrus-imapd-2.2.13/imap/pop3d.c.orig        1970-01-01 01:00:00.000000000 +0100
 
9479
+++ /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/imap/pop3d.c.orig       2006-04-18 20:39:35.704094779 +0200
 
9480
@@ -0,0 +1,1676 @@
 
9481
+/* pop3d.c -- POP3 server protocol parsing
 
9482
+ *
 
9483
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
 
9484
+ *
 
9485
+ * Redistribution and use in source and binary forms, with or without
 
9486
+ * modification, are permitted provided that the following conditions
 
9487
+ * are met:
 
9488
+ *
 
9489
+ * 1. Redistributions of source code must retain the above copyright
 
9490
+ *    notice, this list of conditions and the following disclaimer. 
 
9491
+ *
 
9492
+ * 2. Redistributions in binary form must reproduce the above copyright
 
9493
+ *    notice, this list of conditions and the following disclaimer in
 
9494
+ *    the documentation and/or other materials provided with the
 
9495
+ *    distribution.
 
9496
+ *
 
9497
+ * 3. The name "Carnegie Mellon University" must not be used to
 
9498
+ *    endorse or promote products derived from this software without
 
9499
+ *    prior written permission. For permission or any other legal
 
9500
+ *    details, please contact  
 
9501
+ *      Office of Technology Transfer
 
9502
+ *      Carnegie Mellon University
 
9503
+ *      5000 Forbes Avenue
 
9504
+ *      Pittsburgh, PA  15213-3890
 
9505
+ *      (412) 268-4387, fax: (412) 268-7395
 
9506
+ *      tech-transfer@andrew.cmu.edu
 
9507
+ *
 
9508
+ * 4. Redistributions of any form whatsoever must retain the following
 
9509
+ *    acknowledgment:
 
9510
+ *    "This product includes software developed by Computing Services
 
9511
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
 
9512
+ *
 
9513
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
9514
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 
9515
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
 
9516
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
9517
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 
9518
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 
9519
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
9520
+ */
 
9521
+
 
9522
+/*
 
9523
+ * $Id: pop3d.c,v 1.167 2005/04/11 06:57:35 shadow Exp $
 
9524
+ */
 
9525
+#include <config.h>
 
9526
+
 
9527
+
 
9528
+#ifdef HAVE_UNISTD_H
 
9529
+#include <unistd.h>
 
9530
+#endif
 
9531
+#include <stdio.h>
 
9532
+#include <errno.h>
 
9533
+#include <string.h>
 
9534
+#include <fcntl.h>
 
9535
+#include <signal.h>
 
9536
+#include <assert.h>
 
9537
+#include <sys/types.h>
 
9538
+#include <sys/param.h>
 
9539
+#include <syslog.h>
 
9540
+#include <netdb.h>
 
9541
+#include <sys/socket.h>
 
9542
+#include <netinet/in.h>
 
9543
+#include <arpa/inet.h>
 
9544
+#include <ctype.h>
 
9545
+#include "prot.h"
 
9546
+
 
9547
+#include <sasl/sasl.h>
 
9548
+#include <sasl/saslutil.h>
 
9549
+
 
9550
+#include "acl.h"
 
9551
+#include "util.h"
 
9552
+#include "auth.h"
 
9553
+#include "iptostring.h"
 
9554
+#include "global.h"
 
9555
+#include "tls.h"
 
9556
+
 
9557
+#include "exitcodes.h"
 
9558
+#include "imap_err.h"
 
9559
+#include "mailbox.h"
 
9560
+#include "version.h"
 
9561
+#include "xmalloc.h"
 
9562
+#include "mboxlist.h"
 
9563
+#include "idle.h"
 
9564
+#include "telemetry.h"
 
9565
+#include "backend.h"
 
9566
+
 
9567
+#ifdef HAVE_KRB
 
9568
+/* kerberos des is purported to conflict with OpenSSL DES */
 
9569
+#define DES_DEFS
 
9570
+#include <krb.h>
 
9571
+
 
9572
+/* MIT's kpop authentication kludge */
 
9573
+char klrealm[REALM_SZ];
 
9574
+AUTH_DAT kdata;
 
9575
+#endif /* HAVE_KRB */
 
9576
+static int kflag = 0;
 
9577
+
 
9578
+extern int optind;
 
9579
+extern char *optarg;
 
9580
+extern int opterr;
 
9581
+
 
9582
+
 
9583
+
 
9584
+#ifdef HAVE_SSL
 
9585
+static SSL *tls_conn;
 
9586
+#endif /* HAVE_SSL */
 
9587
+
 
9588
+sasl_conn_t *popd_saslconn; /* the sasl connection context */
 
9589
+
 
9590
+char *popd_userid = 0;
 
9591
+struct mailbox *popd_mailbox = 0;
 
9592
+struct auth_state *popd_authstate = 0;
 
9593
+int config_popuseacl;
 
9594
+struct sockaddr_storage popd_localaddr, popd_remoteaddr;
 
9595
+int popd_haveaddr = 0;
 
9596
+char popd_clienthost[NI_MAXHOST*2+1] = "[local]";
 
9597
+struct protstream *popd_out = NULL;
 
9598
+struct protstream *popd_in = NULL;
 
9599
+static int popd_logfd = -1;
 
9600
+unsigned popd_exists = 0;
 
9601
+unsigned popd_login_time;
 
9602
+struct msg {
 
9603
+    unsigned uid;
 
9604
+    unsigned size;
 
9605
+    int deleted;
 
9606
+} *popd_msg = NULL;
 
9607
+
 
9608
+static int pop3s = 0;
 
9609
+int popd_starttls_done = 0;
 
9610
+
 
9611
+static struct mailbox mboxstruct;
 
9612
+
 
9613
+static mailbox_decideproc_t expungedeleted;
 
9614
+
 
9615
+/* the sasl proxy policy context */
 
9616
+static struct proxy_context popd_proxyctx = {
 
9617
+    0, 1, &popd_authstate, NULL, NULL
 
9618
+};
 
9619
+
 
9620
+/* signal to config.c */
 
9621
+const int config_need_data = CONFIG_NEED_PARTITION_DATA;
 
9622
+
 
9623
+/* current namespace */
 
9624
+static struct namespace popd_namespace;
 
9625
+
 
9626
+/* PROXY stuff */
 
9627
+struct backend *backend = NULL;
 
9628
+
 
9629
+static void bitpipe(void);
 
9630
+/* end PROXY stuff */
 
9631
+
 
9632
+static char popd_apop_chal[45 + MAXHOSTNAMELEN + 1]; /* <rand.time@hostname> */
 
9633
+static void cmd_apop(char *response);
 
9634
+
 
9635
+static void cmd_auth(char *arg);
 
9636
+static void cmd_capa(void);
 
9637
+static void cmd_pass(char *pass);
 
9638
+static void cmd_user(char *user);
 
9639
+static void cmd_starttls(int pop3s);
 
9640
+static void blat(int msg,int lines);
 
9641
+static int openinbox(void);
 
9642
+static void cmdloop(void);
 
9643
+static void kpop(void);
 
9644
+static int parsenum(char **ptr);
 
9645
+void usage(void);
 
9646
+void shut_down(int code) __attribute__ ((noreturn));
 
9647
+
 
9648
+
 
9649
+extern void setproctitle_init(int argc, char **argv, char **envp);
 
9650
+extern int proc_register(const char *progname, const char *clienthost, 
 
9651
+                        const char *userid, const char *mailbox);
 
9652
+extern void proc_cleanup(void);
 
9653
+
 
9654
+extern int saslserver(sasl_conn_t *conn, const char *mech,
 
9655
+                     const char *init_resp, const char *resp_prefix,
 
9656
+                     const char *continuation, const char *empty_chal,
 
9657
+                     struct protstream *pin, struct protstream *pout,
 
9658
+                     int *sasl_result, char **success_data);
 
9659
+
 
9660
+/* Enable the resetting of a sasl_conn_t */
 
9661
+static int reset_saslconn(sasl_conn_t **conn);
 
9662
+
 
9663
+static struct 
 
9664
+{
 
9665
+    char *ipremoteport;
 
9666
+    char *iplocalport;
 
9667
+    sasl_ssf_t ssf;
 
9668
+    char *authid;
 
9669
+} saslprops = {NULL,NULL,0,NULL};
 
9670
+
 
9671
+static struct sasl_callback mysasl_cb[] = {
 
9672
+    { SASL_CB_GETOPT, &mysasl_config, NULL },
 
9673
+    { SASL_CB_PROXY_POLICY, &mysasl_proxy_policy, (void*) &popd_proxyctx },
 
9674
+    { SASL_CB_CANON_USER, &mysasl_canon_user, NULL },
 
9675
+    { SASL_CB_LIST_END, NULL, NULL }
 
9676
+};
 
9677
+
 
9678
+static void popd_reset(void)
 
9679
+{
 
9680
+    proc_cleanup();
 
9681
+
 
9682
+    /* close local mailbox */
 
9683
+    if (popd_mailbox) {
 
9684
+       mailbox_close(popd_mailbox);
 
9685
+       popd_mailbox = 0;
 
9686
+    }
 
9687
+
 
9688
+    /* close backend connection */
 
9689
+    if (backend) {
 
9690
+       backend_disconnect(backend, &protocol[PROTOCOL_POP3]);
 
9691
+       free(backend);
 
9692
+       backend = NULL;
 
9693
+    }
 
9694
+
 
9695
+    if (popd_in) {
 
9696
+       prot_NONBLOCK(popd_in);
 
9697
+       prot_fill(popd_in);
 
9698
+       
 
9699
+       prot_free(popd_in);
 
9700
+    }
 
9701
+
 
9702
+    if (popd_out) {
 
9703
+       prot_flush(popd_out);
 
9704
+       prot_free(popd_out);
 
9705
+    }
 
9706
+    
 
9707
+    popd_in = popd_out = NULL;
 
9708
+
 
9709
+#ifdef HAVE_SSL
 
9710
+    if (tls_conn) {
 
9711
+       tls_reset_servertls(&tls_conn);
 
9712
+       tls_conn = NULL;
 
9713
+    }
 
9714
+#endif
 
9715
+
 
9716
+    cyrus_reset_stdio(); 
 
9717
+
 
9718
+    strcpy(popd_clienthost, "[local]");
 
9719
+    if (popd_logfd != -1) {
 
9720
+       close(popd_logfd);
 
9721
+       popd_logfd = -1;
 
9722
+    }
 
9723
+    if (popd_userid != NULL) {
 
9724
+       free(popd_userid);
 
9725
+       popd_userid = NULL;
 
9726
+    }
 
9727
+    if (popd_authstate) {
 
9728
+       auth_freestate(popd_authstate);
 
9729
+       popd_authstate = NULL;
 
9730
+    }
 
9731
+    if (popd_saslconn) {
 
9732
+       sasl_dispose(&popd_saslconn);
 
9733
+       popd_saslconn = NULL;
 
9734
+    }
 
9735
+    popd_starttls_done = 0;
 
9736
+
 
9737
+    if(saslprops.iplocalport) {
 
9738
+       free(saslprops.iplocalport);
 
9739
+       saslprops.iplocalport = NULL;
 
9740
+    }
 
9741
+    if(saslprops.ipremoteport) {
 
9742
+       free(saslprops.ipremoteport);
 
9743
+       saslprops.ipremoteport = NULL;
 
9744
+    }
 
9745
+    if(saslprops.authid) {
 
9746
+       free(saslprops.authid);
 
9747
+       saslprops.authid = NULL;
 
9748
+    }
 
9749
+    saslprops.ssf = 0;
 
9750
+
 
9751
+    popd_exists = 0;
 
9752
+}
 
9753
+
 
9754
+/*
 
9755
+ * run once when process is forked;
 
9756
+ * MUST NOT exit directly; must return with non-zero error code
 
9757
+ */
 
9758
+int service_init(int argc __attribute__((unused)),
 
9759
+                char **argv __attribute__((unused)),
 
9760
+                char **envp __attribute__((unused)))
 
9761
+{
 
9762
+    int r;
 
9763
+    int opt;
 
9764
+
 
9765
+    if (geteuid() == 0) fatal("must run as the Cyrus user", EC_USAGE);
 
9766
+    setproctitle_init(argc, argv, envp);
 
9767
+
 
9768
+    /* set signal handlers */
 
9769
+    signals_set_shutdown(&shut_down);
 
9770
+    signal(SIGPIPE, SIG_IGN);
 
9771
+
 
9772
+    /* load the SASL plugins */
 
9773
+    global_sasl_init(1, 1, mysasl_cb);
 
9774
+
 
9775
+    /* open the mboxlist, we'll need it for real work */
 
9776
+    mboxlist_init(0);
 
9777
+    mboxlist_open(NULL);
 
9778
+
 
9779
+    /* open the quota db, we'll need it for expunge */
 
9780
+    quotadb_init(0);
 
9781
+    quotadb_open(NULL);
 
9782
+
 
9783
+    /* setup for sending IMAP IDLE notifications */
 
9784
+    idle_enabled();
 
9785
+
 
9786
+    /* Set namespace */
 
9787
+    if ((r = mboxname_init_namespace(&popd_namespace, 0)) != 0) {
 
9788
+       syslog(LOG_ERR, error_message(r));
 
9789
+       fatal(error_message(r), EC_CONFIG);
 
9790
+    }
 
9791
+
 
9792
+    while ((opt = getopt(argc, argv, "sk")) != EOF) {
 
9793
+       switch(opt) {
 
9794
+       case 's': /* pop3s (do starttls right away) */
 
9795
+           pop3s = 1;
 
9796
+           if (!tls_enabled()) {
 
9797
+               syslog(LOG_ERR, "pop3s: required OpenSSL options not present");
 
9798
+               fatal("pop3s: required OpenSSL options not present",
 
9799
+                     EC_CONFIG);
 
9800
+           }
 
9801
+           break;
 
9802
+
 
9803
+       case 'k':
 
9804
+           kflag++;
 
9805
+           break;
 
9806
+       default:
 
9807
+           usage();
 
9808
+       }
 
9809
+    }
 
9810
+
 
9811
+    return 0;
 
9812
+}
 
9813
+
 
9814
+/*
 
9815
+ * run for each accepted connection
 
9816
+ */
 
9817
+int service_main(int argc __attribute__((unused)),
 
9818
+                char **argv __attribute__((unused)),
 
9819
+                char **envp __attribute__((unused)))
 
9820
+{
 
9821
+    socklen_t salen;
 
9822
+    char hbuf[NI_MAXHOST];
 
9823
+    char localip[60], remoteip[60];
 
9824
+    int niflags;
 
9825
+    int timeout;
 
9826
+    sasl_security_properties_t *secprops=NULL;
 
9827
+
 
9828
+    signals_poll();
 
9829
+
 
9830
+    popd_in = prot_new(0, 0);
 
9831
+    popd_out = prot_new(1, 1);
 
9832
+
 
9833
+    /* Find out name of client host */
 
9834
+    salen = sizeof(popd_remoteaddr);
 
9835
+    if (getpeername(0, (struct sockaddr *)&popd_remoteaddr, &salen) == 0 &&
 
9836
+       (popd_remoteaddr.ss_family == AF_INET ||
 
9837
+        popd_remoteaddr.ss_family == AF_INET6)) {
 
9838
+       if (getnameinfo((struct sockaddr *)&popd_remoteaddr, salen,
 
9839
+                       hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD) == 0) {
 
9840
+           strncpy(popd_clienthost, hbuf, sizeof(hbuf));
 
9841
+           strlcat(popd_clienthost, " ", sizeof(popd_clienthost));
 
9842
+       } else {
 
9843
+           popd_clienthost[0] = '\0';
 
9844
+       }
 
9845
+       niflags = NI_NUMERICHOST;
 
9846
+#ifdef NI_WITHSCOPEID
 
9847
+       if (((struct sockaddr *)&popd_remoteaddr)->sa_family == AF_INET6)
 
9848
+           niflags |= NI_WITHSCOPEID;
 
9849
+#endif
 
9850
+       if (getnameinfo((struct sockaddr *)&popd_remoteaddr, salen, hbuf,
 
9851
+                       sizeof(hbuf), NULL, 0, niflags) != 0)
 
9852
+           strlcpy(hbuf, "unknown", sizeof(hbuf));
 
9853
+       strlcat(popd_clienthost, "[", sizeof(popd_clienthost));
 
9854
+       strlcat(popd_clienthost, hbuf, sizeof(popd_clienthost));
 
9855
+       strlcat(popd_clienthost, "]", sizeof(popd_clienthost));
 
9856
+       salen = sizeof(popd_localaddr);
 
9857
+       if (getsockname(0, (struct sockaddr *)&popd_localaddr, &salen) == 0) {
 
9858
+           popd_haveaddr = 1;
 
9859
+       }
 
9860
+    }
 
9861
+
 
9862
+    /* other params should be filled in */
 
9863
+    if (sasl_server_new("pop", config_servername, NULL, NULL, NULL,
 
9864
+                       NULL, 0, &popd_saslconn) != SASL_OK)
 
9865
+       fatal("SASL failed initializing: sasl_server_new()",EC_TEMPFAIL); 
 
9866
+
 
9867
+    /* will always return something valid */
 
9868
+    secprops = mysasl_secprops(SASL_SEC_NOPLAINTEXT);
 
9869
+    sasl_setprop(popd_saslconn, SASL_SEC_PROPS, secprops);
 
9870
+    
 
9871
+    if(iptostring((struct sockaddr *)&popd_localaddr,
 
9872
+                 salen, localip, 60) == 0) {
 
9873
+       sasl_setprop(popd_saslconn, SASL_IPLOCALPORT, localip);
 
9874
+       saslprops.iplocalport = xstrdup(localip);
 
9875
+    }
 
9876
+    
 
9877
+    if(iptostring((struct sockaddr *)&popd_remoteaddr,
 
9878
+                 salen, remoteip, 60) == 0) {
 
9879
+       sasl_setprop(popd_saslconn, SASL_IPREMOTEPORT, remoteip);  
 
9880
+       saslprops.ipremoteport = xstrdup(remoteip);
 
9881
+    }
 
9882
+
 
9883
+    proc_register("pop3d", popd_clienthost, NULL, NULL);
 
9884
+
 
9885
+    /* Set inactivity timer */
 
9886
+    timeout = config_getint(IMAPOPT_POPTIMEOUT);
 
9887
+    if (timeout < 10) timeout = 10;
 
9888
+    prot_settimeout(popd_in, timeout*60);
 
9889
+    prot_setflushonread(popd_in, popd_out);
 
9890
+
 
9891
+    if (kflag) kpop();
 
9892
+
 
9893
+    /* we were connected on pop3s port so we should do 
 
9894
+       TLS negotiation immediatly */
 
9895
+    if (pop3s == 1) cmd_starttls(1);
 
9896
+
 
9897
+    /* Create APOP challenge for banner */
 
9898
+    *popd_apop_chal = 0;
 
9899
+    if (config_getswitch(IMAPOPT_ALLOWAPOP) &&
 
9900
+       (sasl_checkapop(popd_saslconn, NULL, 0, NULL, 0) == SASL_OK) &&
 
9901
+       !sasl_mkchal(popd_saslconn,
 
9902
+                    popd_apop_chal, sizeof(popd_apop_chal), 1)) {
 
9903
+       syslog(LOG_WARNING, "APOP disabled: can't create challenge");
 
9904
+    }
 
9905
+
 
9906
+    prot_printf(popd_out, "+OK %s Cyrus POP3%s %s server ready %s\r\n",
 
9907
+               config_servername, config_mupdate_server ? " Murder" : "",
 
9908
+               CYRUS_VERSION, popd_apop_chal);
 
9909
+    cmdloop();
 
9910
+
 
9911
+    /* QUIT executed */
 
9912
+
 
9913
+    /* don't bother reusing KPOP connections */
 
9914
+    if (kflag) shut_down(0);
 
9915
+
 
9916
+    /* cleanup */
 
9917
+    popd_reset();
 
9918
+
 
9919
+    return 0;
 
9920
+}
 
9921
+
 
9922
+/* Called by service API to shut down the service */
 
9923
+void service_abort(int error)
 
9924
+{
 
9925
+    shut_down(error);
 
9926
+}
 
9927
+
 
9928
+void usage(void)
 
9929
+{
 
9930
+    prot_printf(popd_out, "-ERR usage: pop3d [-C <alt_config>] [-k] [-s]\r\n");
 
9931
+    prot_flush(popd_out);
 
9932
+    exit(EC_USAGE);
 
9933
+}
 
9934
+
 
9935
+/*
 
9936
+ * Cleanly shut down and exit
 
9937
+ */
 
9938
+void shut_down(int code)
 
9939
+{
 
9940
+    proc_cleanup();
 
9941
+
 
9942
+    /* close local mailbox */
 
9943
+    if (popd_mailbox) {
 
9944
+       mailbox_close(popd_mailbox);
 
9945
+    }
 
9946
+
 
9947
+    if (popd_msg) {
 
9948
+       free(popd_msg);
 
9949
+    }
 
9950
+
 
9951
+    /* close backend connection */
 
9952
+    if (backend) {
 
9953
+       backend_disconnect(backend, &protocol[PROTOCOL_POP3]);
 
9954
+       free(backend);
 
9955
+    }
 
9956
+
 
9957
+    mboxlist_close();
 
9958
+    mboxlist_done();
 
9959
+
 
9960
+    quotadb_close();
 
9961
+    quotadb_done();
 
9962
+
 
9963
+    if (popd_in) {
 
9964
+       prot_NONBLOCK(popd_in);
 
9965
+       prot_fill(popd_in);
 
9966
+       prot_free(popd_in);
 
9967
+    }
 
9968
+
 
9969
+    if (popd_out) {
 
9970
+       prot_flush(popd_out);
 
9971
+       prot_free(popd_out);
 
9972
+    }
 
9973
+
 
9974
+#ifdef HAVE_SSL
 
9975
+    tls_shutdown_serverengine();
 
9976
+#endif
 
9977
+
 
9978
+    cyrus_done();
 
9979
+    cyrus_close_sock(0);
 
9980
+    cyrus_close_sock(1);
 
9981
+    cyrus_close_sock(2);
 
9982
+
 
9983
+    exit(code);
 
9984
+}
 
9985
+
 
9986
+void fatal(const char* s, int code)
 
9987
+{
 
9988
+    static int recurse_code = 0;
 
9989
+
 
9990
+    if (recurse_code) {
 
9991
+       /* We were called recursively. Just give up */
 
9992
+       proc_cleanup();
 
9993
+       exit(recurse_code);
 
9994
+    }
 
9995
+    recurse_code = code;
 
9996
+    if (popd_out) {
 
9997
+       prot_printf(popd_out, "-ERR [SYS/PERM] Fatal error: %s\r\n", s);
 
9998
+       prot_flush(popd_out);
 
9999
+    }
 
10000
+    syslog(LOG_ERR, "Fatal error: %s", s);
 
10001
+    shut_down(code);
 
10002
+}
 
10003
+
 
10004
+#ifdef HAVE_KRB
 
10005
+/*
 
10006
+ * MIT's kludge of a kpop protocol
 
10007
+ * Client does a krb_sendauth() first thing
 
10008
+ */
 
10009
+void kpop(void)
 
10010
+{
 
10011
+    Key_schedule schedule;
 
10012
+    KTEXT_ST ticket;
 
10013
+    char instance[INST_SZ];  
 
10014
+    char version[9];
 
10015
+    const char *srvtab;
 
10016
+    int r;
 
10017
+    socklen_t len;
 
10018
+    
 
10019
+    if (!popd_haveaddr) {
 
10020
+       fatal("Cannot get client's IP address", EC_OSERR);
 
10021
+    }
 
10022
+
 
10023
+    srvtab = config_getstring(IMAPOPT_SRVTAB);
 
10024
+
 
10025
+    sockaddr_unmapped((struct sockaddr *)&popd_remoteaddr, &len);
 
10026
+    if (popd_remoteaddr.ss_family != AF_INET) {
 
10027
+       prot_printf(popd_out,
 
10028
+                   "-ERR [AUTH] Kerberos authentication failure: %s\r\n",
 
10029
+                   "not an IPv4 connection");
 
10030
+       shut_down(0);
 
10031
+    }
 
10032
+
 
10033
+    strcpy(instance, "*");
 
10034
+    r = krb_recvauth(0L, 0, &ticket, "pop", instance,
 
10035
+                    (struct sockaddr_in *) &popd_remoteaddr,
 
10036
+                    (struct sockaddr_in *) NULL,
 
10037
+                    &kdata, (char*) srvtab, schedule, version);
 
10038
+    
 
10039
+    if (r) {
 
10040
+       prot_printf(popd_out, "-ERR [AUTH] Kerberos authentication failure: %s\r\n",
 
10041
+                   krb_err_txt[r]);
 
10042
+       syslog(LOG_NOTICE,
 
10043
+              "badlogin: %s kpop ? %s%s%s@%s %s",
 
10044
+              popd_clienthost, kdata.pname,
 
10045
+              kdata.pinst[0] ? "." : "", kdata.pinst,
 
10046
+              kdata.prealm, krb_err_txt[r]);
 
10047
+       shut_down(0);
 
10048
+    }
 
10049
+    
 
10050
+    r = krb_get_lrealm(klrealm,1);
 
10051
+    if (r) {
 
10052
+       prot_printf(popd_out, "-ERR [AUTH] Kerberos failure: %s\r\n",
 
10053
+                   krb_err_txt[r]);
 
10054
+       syslog(LOG_NOTICE,
 
10055
+              "badlogin: %s kpop ? %s%s%s@%s krb_get_lrealm: %s",
 
10056
+              popd_clienthost, kdata.pname,
 
10057
+              kdata.pinst[0] ? "." : "", kdata.pinst,
 
10058
+              kdata.prealm, krb_err_txt[r]);
 
10059
+       shut_down(0);
 
10060
+    }
 
10061
+}
 
10062
+#else
 
10063
+void kpop(void)
 
10064
+{
 
10065
+    usage();
 
10066
+}
 
10067
+#endif
 
10068
+
 
10069
+/*
 
10070
+ * Top-level command loop parsing
 
10071
+ */
 
10072
+static void cmdloop(void)
 
10073
+{
 
10074
+    char inputbuf[8192];
 
10075
+    char *p, *arg;
 
10076
+    unsigned msg = 0;
 
10077
+
 
10078
+    for (;;) {
 
10079
+       signals_poll();
 
10080
+
 
10081
+       if (backend) {
 
10082
+           /* create a pipe from client to backend */
 
10083
+           bitpipe();
 
10084
+
 
10085
+           /* pipe has been closed */
 
10086
+           return;
 
10087
+       }
 
10088
+
 
10089
+       /* check for shutdown file */
 
10090
+       if (shutdown_file(inputbuf, sizeof(inputbuf))) {
 
10091
+           for (p = inputbuf; *p == '['; p++); /* can't have [ be first char */
 
10092
+           prot_printf(popd_out, "-ERR [SYS/TEMP] %s\r\n", p);
 
10093
+           shut_down(0);
 
10094
+       }
 
10095
+
 
10096
+       if (!prot_fgets(inputbuf, sizeof(inputbuf), popd_in)) {
 
10097
+           shut_down(0);
 
10098
+       }
 
10099
+
 
10100
+       p = inputbuf + strlen(inputbuf);
 
10101
+       if (p > inputbuf && p[-1] == '\n') *--p = '\0';
 
10102
+       if (p > inputbuf && p[-1] == '\r') *--p = '\0';
 
10103
+
 
10104
+       /* Parse into keword and argument */
 
10105
+       for (p = inputbuf; *p && !isspace((int) *p); p++);
 
10106
+       if (*p) {
 
10107
+           *p++ = '\0';
 
10108
+           arg = p;
 
10109
+           if (strcasecmp(inputbuf, "pass") != 0) {
 
10110
+               while (*arg && isspace((int) *arg)) {
 
10111
+                   arg++;
 
10112
+               }
 
10113
+           }
 
10114
+           if (!*arg) {
 
10115
+               if (strcasecmp(inputbuf, "auth") == 0) {
 
10116
+                   /* HACK for MS Outlook's incorrect use of the old-style
 
10117
+                    * SASL discovery method.
 
10118
+                    * Outlook uses "AUTH \r\n" instead if "AUTH\r\n"
 
10119
+                    */
 
10120
+                   arg = 0;
 
10121
+               }
 
10122
+               else {
 
10123
+                   prot_printf(popd_out, "-ERR Syntax error\r\n");
 
10124
+                   continue;
 
10125
+               }
 
10126
+           }
 
10127
+       }
 
10128
+       else {
 
10129
+           arg = 0;
 
10130
+       }
 
10131
+       lcase(inputbuf);
 
10132
+
 
10133
+       if (!strcmp(inputbuf, "quit")) {
 
10134
+           if (!arg) {
 
10135
+               if (popd_mailbox) {
 
10136
+                   if (!mailbox_lock_index(popd_mailbox)) {
 
10137
+                       int pollpadding =config_getint(IMAPOPT_POPPOLLPADDING);
 
10138
+                       int minpollsec = config_getint(IMAPOPT_POPMINPOLL)*60;
 
10139
+                       if ((minpollsec > 0) && (pollpadding > 1)) { 
 
10140
+                           int mintime = popd_login_time - (minpollsec*(pollpadding));
 
10141
+                           if (popd_mailbox->pop3_last_login < mintime) {
 
10142
+                               popd_mailbox->pop3_last_login = mintime + minpollsec; 
 
10143
+                           } else {
 
10144
+                               popd_mailbox->pop3_last_login += minpollsec;
 
10145
+                           }
 
10146
+                       } else { 
 
10147
+                           popd_mailbox->pop3_last_login = popd_login_time;
 
10148
+                       }
 
10149
+                       mailbox_write_index_header(popd_mailbox);
 
10150
+                       mailbox_unlock_index(popd_mailbox);
 
10151
+                   }
 
10152
+
 
10153
+                   for (msg = 1; msg <= popd_exists; msg++) {
 
10154
+                       if (popd_msg[msg].deleted) break;
 
10155
+                   }
 
10156
+
 
10157
+                   if (msg <= popd_exists) {
 
10158
+                       (void) mailbox_expunge(popd_mailbox, 1, expungedeleted, 0);
 
10159
+                   }
 
10160
+               }
 
10161
+               prot_printf(popd_out, "+OK\r\n");
 
10162
+               return;
 
10163
+           }
 
10164
+           else prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
 
10165
+       }
 
10166
+       else if (!strcmp(inputbuf, "capa")) {
 
10167
+           if (arg) {
 
10168
+               prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
 
10169
+           } else {
 
10170
+               cmd_capa();
 
10171
+           }
 
10172
+       }
 
10173
+       else if (!strcmp(inputbuf, "stls") && tls_enabled()) {
 
10174
+           if (arg) {
 
10175
+               prot_printf(popd_out,
 
10176
+                           "-ERR STLS doesn't take any arguments\r\n");
 
10177
+           } else {
 
10178
+               cmd_starttls(0);
 
10179
+           }
 
10180
+       }
 
10181
+       else if (!popd_mailbox) {
 
10182
+           if (!strcmp(inputbuf, "user")) {
 
10183
+               if (!arg) {
 
10184
+                   prot_printf(popd_out, "-ERR Missing argument\r\n");
 
10185
+               }
 
10186
+               else {
 
10187
+                   cmd_user(arg);
 
10188
+               }
 
10189
+           }
 
10190
+           else if (!strcmp(inputbuf, "pass")) {
 
10191
+               if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
 
10192
+               else cmd_pass(arg);
 
10193
+           }
 
10194
+           else if (!strcmp(inputbuf, "apop") && *popd_apop_chal) {
 
10195
+               if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
 
10196
+               else cmd_apop(arg);
 
10197
+           }
 
10198
+           else if (!strcmp(inputbuf, "auth")) {
 
10199
+               cmd_auth(arg);
 
10200
+           }
 
10201
+           else {
 
10202
+               prot_printf(popd_out, "-ERR Unrecognized command\r\n");
 
10203
+           }
 
10204
+       }
 
10205
+       else if (!strcmp(inputbuf, "stat")) {
 
10206
+           unsigned nmsgs = 0, totsize = 0;
 
10207
+           if (arg) {
 
10208
+               prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
 
10209
+           }
 
10210
+           else {
 
10211
+               for (msg = 1; msg <= popd_exists; msg++) {
 
10212
+                   if (!popd_msg[msg].deleted) {
 
10213
+                       nmsgs++;
 
10214
+                       totsize += popd_msg[msg].size;
 
10215
+                   }
 
10216
+               }
 
10217
+               prot_printf(popd_out, "+OK %u %u\r\n", nmsgs, totsize);
 
10218
+           }
 
10219
+       }
 
10220
+       else if (!strcmp(inputbuf, "list")) {
 
10221
+           if (arg) {
 
10222
+               msg = parsenum(&arg);
 
10223
+               if (arg) {
 
10224
+                   prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
 
10225
+               }
 
10226
+               else if (msg < 1 || msg > popd_exists ||
 
10227
+                        popd_msg[msg].deleted) {
 
10228
+                   prot_printf(popd_out, "-ERR No such message\r\n");
 
10229
+               }
 
10230
+               else {
 
10231
+                   prot_printf(popd_out, "+OK %u %u\r\n", msg, popd_msg[msg].size);
 
10232
+               }
 
10233
+           }
 
10234
+           else {
 
10235
+               prot_printf(popd_out, "+OK scan listing follows\r\n");
 
10236
+               for (msg = 1; msg <= popd_exists; msg++) {
 
10237
+                   if (!popd_msg[msg].deleted) {
 
10238
+                       prot_printf(popd_out, "%u %u\r\n", msg, popd_msg[msg].size);
 
10239
+                   }
 
10240
+               }
 
10241
+               prot_printf(popd_out, ".\r\n");
 
10242
+           }
 
10243
+       }
 
10244
+       else if (!strcmp(inputbuf, "retr")) {
 
10245
+           if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
 
10246
+           else {
 
10247
+               msg = parsenum(&arg);
 
10248
+               if (arg) {
 
10249
+                   prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
 
10250
+               }
 
10251
+               else if (msg < 1 || msg > popd_exists ||
 
10252
+                        popd_msg[msg].deleted) {
 
10253
+                   prot_printf(popd_out, "-ERR No such message\r\n");
 
10254
+               }
 
10255
+               else {
 
10256
+                   blat(msg, -1);
 
10257
+               }
 
10258
+           }
 
10259
+       }
 
10260
+       else if (!strcmp(inputbuf, "dele")) {
 
10261
+           if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
 
10262
+           else if (config_popuseacl && !(mboxstruct.myrights & ACL_DELETE)) {
 
10263
+               prot_printf(popd_out, "-ERR [SYS/PERM] %s\r\n",
 
10264
+                           error_message(IMAP_PERMISSION_DENIED));
 
10265
+           }
 
10266
+           else {
 
10267
+               msg = parsenum(&arg);
 
10268
+               if (arg) {
 
10269
+                   prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
 
10270
+               }
 
10271
+               else if (msg < 1 || msg > popd_exists ||
 
10272
+                        popd_msg[msg].deleted) {
 
10273
+                   prot_printf(popd_out, "-ERR No such message\r\n");
 
10274
+               }
 
10275
+               else {
 
10276
+                   popd_msg[msg].deleted = 1;
 
10277
+                   prot_printf(popd_out, "+OK message deleted\r\n");
 
10278
+               }
 
10279
+           }
 
10280
+       }
 
10281
+       else if (!strcmp(inputbuf, "noop")) {
 
10282
+           if (arg) {
 
10283
+               prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
 
10284
+           }
 
10285
+           else {
 
10286
+               prot_printf(popd_out, "+OK\r\n");
 
10287
+           }
 
10288
+       }
 
10289
+       else if (!strcmp(inputbuf, "rset")) {
 
10290
+           if (arg) {
 
10291
+               prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
 
10292
+           }
 
10293
+           else {
 
10294
+               for (msg = 1; msg <= popd_exists; msg++) {
 
10295
+                   popd_msg[msg].deleted = 0;
 
10296
+               }
 
10297
+               prot_printf(popd_out, "+OK\r\n");
 
10298
+           }
 
10299
+       }
 
10300
+       else if (!strcmp(inputbuf, "top")) {
 
10301
+           int lines;
 
10302
+
 
10303
+           if (arg) msg = parsenum(&arg);
 
10304
+           if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
 
10305
+           else {
 
10306
+               lines = parsenum(&arg);
 
10307
+               if (arg) {
 
10308
+                   prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
 
10309
+               }
 
10310
+               else if (msg < 1 || msg > popd_exists ||
 
10311
+                        popd_msg[msg].deleted) {
 
10312
+                   prot_printf(popd_out, "-ERR No such message\r\n");
 
10313
+               }
 
10314
+               else if (lines < 0) {
 
10315
+                   prot_printf(popd_out, "-ERR Invalid number of lines\r\n");
 
10316
+               }
 
10317
+               else {
 
10318
+                   blat(msg, lines);
 
10319
+               }
 
10320
+           }
 
10321
+       }
 
10322
+       else if (!strcmp(inputbuf, "uidl")) {
 
10323
+           if (arg) {
 
10324
+               msg = parsenum(&arg);
 
10325
+               if (arg) {
 
10326
+                   prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
 
10327
+               }
 
10328
+               else if (msg < 1 || msg > popd_exists ||
 
10329
+                        popd_msg[msg].deleted) {
 
10330
+                   prot_printf(popd_out, "-ERR No such message\r\n");
 
10331
+               }
 
10332
+               else if (mboxstruct.pop3_new_uidl) {
 
10333
+                           prot_printf(popd_out, "+OK %u %lu.%u\r\n", msg, 
 
10334
+                                       mboxstruct.uidvalidity,
 
10335
+                                       popd_msg[msg].uid);
 
10336
+               }
 
10337
+               else {
 
10338
+                   /* old uidl format */
 
10339
+                   prot_printf(popd_out, "+OK %u %u\r\n", 
 
10340
+                               msg, popd_msg[msg].uid);
 
10341
+               }
 
10342
+           }
 
10343
+           else {
 
10344
+               prot_printf(popd_out, "+OK unique-id listing follows\r\n");
 
10345
+               for (msg = 1; msg <= popd_exists; msg++) {
 
10346
+                   if (!popd_msg[msg].deleted) {
 
10347
+                       if (mboxstruct.pop3_new_uidl) {
 
10348
+                           prot_printf(popd_out, "%u %lu.%u\r\n", msg, 
 
10349
+                                       mboxstruct.uidvalidity,
 
10350
+                                       popd_msg[msg].uid);
 
10351
+                       } else {
 
10352
+                           prot_printf(popd_out, "%u %u\r\n", msg, 
 
10353
+                                       popd_msg[msg].uid);
 
10354
+                       }
 
10355
+                   }
 
10356
+               }
 
10357
+               prot_printf(popd_out, ".\r\n");
 
10358
+           }
 
10359
+       }
 
10360
+       else {
 
10361
+           prot_printf(popd_out, "-ERR Unrecognized command\r\n");
 
10362
+       }
 
10363
+    }          
 
10364
+}
 
10365
+
 
10366
+#ifdef HAVE_SSL
 
10367
+static void cmd_starttls(int pop3s)
 
10368
+{
 
10369
+    int result;
 
10370
+    int *layerp;
 
10371
+    sasl_ssf_t ssf;
 
10372
+    char *auth_id;
 
10373
+
 
10374
+    /* SASL and openssl have different ideas about whether ssf is signed */
 
10375
+    layerp = (int *) &ssf;
 
10376
+
 
10377
+    if (popd_starttls_done == 1)
 
10378
+    {
 
10379
+       prot_printf(popd_out, "-ERR %s\r\n", 
 
10380
+                   "Already successfully executed STLS");
 
10381
+       return;
 
10382
+    }
 
10383
+
 
10384
+    result=tls_init_serverengine("pop3",
 
10385
+                                5,        /* depth to verify */
 
10386
+                                !pop3s,   /* can client auth? */
 
10387
+                                !pop3s);  /* TLS only? */
 
10388
+
 
10389
+    if (result == -1) {
 
10390
+
 
10391
+       syslog(LOG_ERR, "[pop3d] error initializing TLS");
 
10392
+
 
10393
+       if (pop3s == 0)
 
10394
+           prot_printf(popd_out, "-ERR [SYS/PERM] %s\r\n", "Error initializing TLS");
 
10395
+       else
 
10396
+           fatal("tls_init() failed",EC_TEMPFAIL);
 
10397
+
 
10398
+       return;
 
10399
+    }
 
10400
+
 
10401
+    if (pop3s == 0)
 
10402
+    {
 
10403
+       prot_printf(popd_out, "+OK %s\r\n", "Begin TLS negotiation now");
 
10404
+       /* must flush our buffers before starting tls */
 
10405
+       prot_flush(popd_out);
 
10406
+    }
 
10407
+  
 
10408
+    result=tls_start_servertls(0, /* read */
 
10409
+                              1, /* write */
 
10410
+                              layerp,
 
10411
+                              &auth_id,
 
10412
+                              &tls_conn);
 
10413
+
 
10414
+    /* if error */
 
10415
+    if (result==-1) {
 
10416
+       if (pop3s == 0) {
 
10417
+           prot_printf(popd_out, "-ERR [SYS/PERM] Starttls failed\r\n");
 
10418
+           syslog(LOG_NOTICE, "[pop3d] STARTTLS failed: %s", popd_clienthost);
 
10419
+       } else {
 
10420
+           syslog(LOG_NOTICE, "pop3s failed: %s", popd_clienthost);
 
10421
+           fatal("tls_start_servertls() failed", EC_TEMPFAIL);
 
10422
+       }
 
10423
+       return;
 
10424
+    }
 
10425
+
 
10426
+    /* tell SASL about the negotiated layer */
 
10427
+    result = sasl_setprop(popd_saslconn, SASL_SSF_EXTERNAL, &ssf);
 
10428
+    if (result != SASL_OK) {
 
10429
+       fatal("sasl_setprop() failed: cmd_starttls()", EC_TEMPFAIL);
 
10430
+    }
 
10431
+    saslprops.ssf = ssf;
 
10432
+
 
10433
+    result = sasl_setprop(popd_saslconn, SASL_AUTH_EXTERNAL, auth_id);
 
10434
+    if (result != SASL_OK) {
 
10435
+        fatal("sasl_setprop() failed: cmd_starttls()", EC_TEMPFAIL);
 
10436
+    }
 
10437
+    if(saslprops.authid) {
 
10438
+       free(saslprops.authid);
 
10439
+       saslprops.authid = NULL;
 
10440
+    }
 
10441
+    if(auth_id)
 
10442
+       saslprops.authid = xstrdup(auth_id);
 
10443
+
 
10444
+    /* tell the prot layer about our new layers */
 
10445
+    prot_settls(popd_in, tls_conn);
 
10446
+    prot_settls(popd_out, tls_conn);
 
10447
+
 
10448
+    popd_starttls_done = 1;
 
10449
+}
 
10450
+#else
 
10451
+static void cmd_starttls(int pop3s __attribute__((unused)))
 
10452
+{
 
10453
+    fatal("cmd_starttls() called, but no OpenSSL", EC_SOFTWARE);
 
10454
+}
 
10455
+#endif /* HAVE_SSL */
 
10456
+
 
10457
+static void cmd_apop(char *response)
 
10458
+{
 
10459
+    int sasl_result;
 
10460
+    char *canon_user;
 
10461
+
 
10462
+    assert(response != NULL);
 
10463
+
 
10464
+    if (popd_userid) {
 
10465
+       prot_printf(popd_out, "-ERR [AUTH] Must give PASS command\r\n");
 
10466
+       return;
 
10467
+    }
 
10468
+
 
10469
+    sasl_result = sasl_checkapop(popd_saslconn,
 
10470
+                                popd_apop_chal,
 
10471
+                                strlen(popd_apop_chal),
 
10472
+                                response,
 
10473
+                                strlen(response));
 
10474
+    
 
10475
+    /* failed authentication */
 
10476
+    if (sasl_result != SASL_OK)
 
10477
+    {
 
10478
+       sleep(3);      
 
10479
+               
 
10480
+       prot_printf(popd_out, "-ERR [AUTH] authenticating: %s\r\n",
 
10481
+                   sasl_errstring(sasl_result, NULL, NULL));
 
10482
+
 
10483
+       syslog(LOG_NOTICE, "badlogin: %s APOP (%s) %s",
 
10484
+              popd_clienthost, popd_apop_chal,
 
10485
+              sasl_errdetail(popd_saslconn));
 
10486
+       
 
10487
+       return;
 
10488
+    }
 
10489
+
 
10490
+    /* successful authentication */
 
10491
+
 
10492
+    /*
 
10493
+     * get the userid from SASL --- already canonicalized from
 
10494
+     * mysasl_proxy_policy()
 
10495
+     */
 
10496
+    sasl_result = sasl_getprop(popd_saslconn, SASL_USERNAME,
 
10497
+                              (const void **) &canon_user);
 
10498
+    popd_userid = xstrdup(canon_user);
 
10499
+    if (sasl_result != SASL_OK) {
 
10500
+       prot_printf(popd_out, 
 
10501
+                   "-ERR [AUTH] weird SASL error %d getting SASL_USERNAME\r\n", 
 
10502
+                   sasl_result);
 
10503
+       return;
 
10504
+    }
 
10505
+    
 
10506
+    syslog(LOG_NOTICE, "login: %s %s APOP%s %s", popd_clienthost,
 
10507
+          popd_userid, popd_starttls_done ? "+TLS" : "", "User logged in");
 
10508
+
 
10509
+    popd_authstate = auth_newstate(popd_userid);
 
10510
+
 
10511
+    openinbox();
 
10512
+}
 
10513
+
 
10514
+void cmd_user(char *user)
 
10515
+{
 
10516
+    char *p, *dot, *domain;
 
10517
+
 
10518
+    /* possibly disallow USER */
 
10519
+    if (!(kflag || popd_starttls_done ||
 
10520
+         config_getswitch(IMAPOPT_ALLOWPLAINTEXT))) {
 
10521
+       prot_printf(popd_out,
 
10522
+                   "-ERR [AUTH] USER command only available under a layer\r\n");
 
10523
+       return;
 
10524
+    }
 
10525
+
 
10526
+    if (popd_userid) {
 
10527
+       prot_printf(popd_out, "-ERR [AUTH] Must give PASS command\r\n");
 
10528
+       return;
 
10529
+    }
 
10530
+
 
10531
+    if (!(p = canonify_userid(user, NULL, NULL)) ||
 
10532
+            /* '.' isn't allowed if '.' is the hierarchy separator */
 
10533
+            (popd_namespace.hier_sep == '.' && (dot = strchr(p, '.')) &&
 
10534
+             !(config_virtdomains &&  /* allow '.' in dom.ain */
 
10535
+               (domain = strchr(p, '@')) && (dot > domain))) ||
 
10536
+            strlen(p) + 6 > MAX_MAILBOX_PATH) {
 
10537
+       prot_printf(popd_out, "-ERR [AUTH] Invalid user\r\n");
 
10538
+       syslog(LOG_NOTICE,
 
10539
+              "badlogin: %s plaintext %s invalid user",
 
10540
+              popd_clienthost, beautify_string(user));
 
10541
+    }
 
10542
+    else {
 
10543
+       popd_userid = xstrdup(p);
 
10544
+       prot_printf(popd_out, "+OK Name is a valid mailbox\r\n");
 
10545
+    }
 
10546
+}
 
10547
+
 
10548
+void cmd_pass(char *pass)
 
10549
+{
 
10550
+    int plaintextloginpause;
 
10551
+
 
10552
+    if (!popd_userid) {
 
10553
+       prot_printf(popd_out, "-ERR [AUTH] Must give USER command\r\n");
 
10554
+       return;
 
10555
+    }
 
10556
+
 
10557
+#ifdef HAVE_KRB
 
10558
+    if (kflag) {
 
10559
+       if (strcmp(popd_userid, kdata.pname) != 0 ||
 
10560
+           kdata.pinst[0] ||
 
10561
+           strcmp(klrealm, kdata.prealm) != 0) {
 
10562
+           prot_printf(popd_out, "-ERR [AUTH] Invalid login\r\n");
 
10563
+           syslog(LOG_NOTICE,
 
10564
+                  "badlogin: %s kpop %s %s%s%s@%s access denied",
 
10565
+                  popd_clienthost, popd_userid,
 
10566
+                  kdata.pname, kdata.pinst[0] ? "." : "",
 
10567
+                  kdata.pinst, kdata.prealm);
 
10568
+           return;
 
10569
+       }
 
10570
+
 
10571
+       syslog(LOG_NOTICE, "login: %s %s kpop", popd_clienthost, popd_userid);
 
10572
+
 
10573
+       openinbox();
 
10574
+       return;
 
10575
+    }
 
10576
+#endif
 
10577
+
 
10578
+    if (!strcmp(popd_userid, "anonymous")) {
 
10579
+       if (config_getswitch(IMAPOPT_ALLOWANONYMOUSLOGIN)) {
 
10580
+           pass = beautify_string(pass);
 
10581
+           if (strlen(pass) > 500) pass[500] = '\0';
 
10582
+           syslog(LOG_NOTICE, "login: %s anonymous %s",
 
10583
+                  popd_clienthost, pass);
 
10584
+       }
 
10585
+       else {
 
10586
+           syslog(LOG_NOTICE, "badlogin: %s anonymous login refused",
 
10587
+                  popd_clienthost);
 
10588
+           prot_printf(popd_out, "-ERR [AUTH] Invalid login\r\n");
 
10589
+           return;
 
10590
+       }
 
10591
+    }
 
10592
+    else if (sasl_checkpass(popd_saslconn,
 
10593
+                           popd_userid,
 
10594
+                           strlen(popd_userid),
 
10595
+                           pass,
 
10596
+                           strlen(pass))!=SASL_OK) { 
 
10597
+       syslog(LOG_NOTICE, "badlogin: %s plaintext %s %s",
 
10598
+              popd_clienthost, popd_userid, sasl_errdetail(popd_saslconn));
 
10599
+       sleep(3);
 
10600
+       prot_printf(popd_out, "-ERR [AUTH] Invalid login\r\n");
 
10601
+       free(popd_userid);
 
10602
+       popd_userid = 0;
 
10603
+
 
10604
+       return;
 
10605
+    }
 
10606
+    else {
 
10607
+       syslog(LOG_NOTICE, "login: %s %s plaintext%s %s", popd_clienthost,
 
10608
+              popd_userid, popd_starttls_done ? "+TLS" : "", 
 
10609
+              "User logged in");
 
10610
+
 
10611
+       if ((plaintextloginpause = config_getint(IMAPOPT_PLAINTEXTLOGINPAUSE))
 
10612
+            != 0) {
 
10613
+           sleep(plaintextloginpause);
 
10614
+       }
 
10615
+    }
 
10616
+
 
10617
+    popd_authstate = auth_newstate(popd_userid);
 
10618
+
 
10619
+    openinbox();
 
10620
+}
 
10621
+
 
10622
+/* Handle the POP3 Extension extension.
 
10623
+ */
 
10624
+void cmd_capa()
 
10625
+{
 
10626
+    int minpoll = config_getint(IMAPOPT_POPMINPOLL) * 60;
 
10627
+    int expire = config_getint(IMAPOPT_POPEXPIRETIME);
 
10628
+    unsigned mechcount;
 
10629
+    const char *mechlist;
 
10630
+
 
10631
+    prot_printf(popd_out, "+OK List of capabilities follows\r\n");
 
10632
+
 
10633
+    /* SASL special case: print SASL, then a list of supported capabilities */
 
10634
+    if (!popd_mailbox && !backend &&
 
10635
+       sasl_listmech(popd_saslconn,
 
10636
+                     NULL, /* should be id string */
 
10637
+                     "SASL ", " ", "\r\n",
 
10638
+                     &mechlist,
 
10639
+                     NULL, &mechcount) == SASL_OK && mechcount > 0) {
 
10640
+       prot_write(popd_out, mechlist, strlen(mechlist));
 
10641
+    }
 
10642
+
 
10643
+    if (tls_enabled() && !popd_starttls_done && !popd_mailbox && !backend) {
 
10644
+       prot_printf(popd_out, "STLS\r\n");
 
10645
+    }
 
10646
+    if (expire < 0) {
 
10647
+       prot_printf(popd_out, "EXPIRE NEVER\r\n");
 
10648
+    } else {
 
10649
+       prot_printf(popd_out, "EXPIRE %d\r\n", expire);
 
10650
+    }
 
10651
+
 
10652
+    prot_printf(popd_out, "LOGIN-DELAY %d\r\n", minpoll);
 
10653
+    prot_printf(popd_out, "TOP\r\n");
 
10654
+    prot_printf(popd_out, "UIDL\r\n");
 
10655
+    prot_printf(popd_out, "PIPELINING\r\n");
 
10656
+    prot_printf(popd_out, "RESP-CODES\r\n");
 
10657
+    prot_printf(popd_out, "AUTH-RESP-CODE\r\n");
 
10658
+
 
10659
+    if (!popd_mailbox && !backend &&
 
10660
+       (kflag || popd_starttls_done
 
10661
+        || config_getswitch(IMAPOPT_ALLOWPLAINTEXT))) {
 
10662
+       prot_printf(popd_out, "USER\r\n");
 
10663
+    }
 
10664
+    
 
10665
+    prot_printf(popd_out,
 
10666
+               "IMPLEMENTATION Cyrus POP3%s server %s\r\n",
 
10667
+               config_mupdate_server ? " Murder" : "", CYRUS_VERSION);
 
10668
+
 
10669
+    prot_printf(popd_out, ".\r\n");
 
10670
+    prot_flush(popd_out);
 
10671
+}
 
10672
+
 
10673
+
 
10674
+void cmd_auth(char *arg)
 
10675
+{
 
10676
+    int r, sasl_result;
 
10677
+    char *authtype;
 
10678
+    char *canon_user;
 
10679
+
 
10680
+    /* if client didn't specify an argument we give them the list
 
10681
+     *
 
10682
+     * XXX This method of mechanism discovery is an undocumented feature
 
10683
+     * that appeared in draft-myers-sasl-pop3 and is still used by
 
10684
+     * some clients.
 
10685
+     */
 
10686
+    if (!arg) {
 
10687
+       const char *sasllist;
 
10688
+       unsigned int mechnum;
 
10689
+
 
10690
+       prot_printf(popd_out, "+OK List of supported mechanisms follows\r\n");
 
10691
+      
 
10692
+       /* CRLF separated, dot terminated */
 
10693
+       if (sasl_listmech(popd_saslconn, NULL,
 
10694
+                         "", "\r\n", "\r\n",
 
10695
+                         &sasllist,
 
10696
+                         NULL, &mechnum) == SASL_OK) {
 
10697
+           if (mechnum>0) {
 
10698
+               prot_printf(popd_out,"%s",sasllist);
 
10699
+           }
 
10700
+       }
 
10701
+      
 
10702
+       prot_printf(popd_out, ".\r\n");
 
10703
+       return;
 
10704
+    }
 
10705
+
 
10706
+    authtype = arg;
 
10707
+
 
10708
+    /* according to RFC 2449, since we advertise the "SASL" capability, we
 
10709
+     * must accept an optional second argument as an initial client
 
10710
+     * response (base64 encoded!).
 
10711
+     */ 
 
10712
+    while (*arg && !isspace((int) *arg)) {
 
10713
+       arg++;
 
10714
+    }
 
10715
+    if (isspace((int) *arg)) {
 
10716
+       /* null terminate authtype, get argument */
 
10717
+       *arg++ = '\0';
 
10718
+    } else {
 
10719
+       /* no optional client response */
 
10720
+       arg = NULL;
 
10721
+    }
 
10722
+
 
10723
+    r = saslserver(popd_saslconn, authtype, arg, "", "+ ", "",
 
10724
+                  popd_in, popd_out, &sasl_result, NULL);
 
10725
+
 
10726
+    if (r) {
 
10727
+       const char *errorstring = NULL;
 
10728
+
 
10729
+       switch (r) {
 
10730
+       case IMAP_SASL_CANCEL:
 
10731
+           prot_printf(popd_out,
 
10732
+                       "-ERR [AUTH] Client canceled authentication\r\n");
 
10733
+           break;
 
10734
+       case IMAP_SASL_PROTERR:
 
10735
+           errorstring = prot_error(popd_in);
 
10736
+
 
10737
+           prot_printf(popd_out,
 
10738
+                       "-ERR [AUTH] Error reading client response: %s\r\n",
 
10739
+                       errorstring ? errorstring : "");
 
10740
+           break;
 
10741
+       default:
 
10742
+           /* failed authentication */
 
10743
+           sleep(3);
 
10744
+               
 
10745
+           prot_printf(popd_out, "-ERR [AUTH] authenticating: %s\r\n",
 
10746
+                       sasl_errstring(sasl_result, NULL, NULL));
 
10747
+
 
10748
+           if (authtype) {
 
10749
+               syslog(LOG_NOTICE, "badlogin: %s %s %s",
 
10750
+                      popd_clienthost, authtype,
 
10751
+                      sasl_errstring(sasl_result, NULL, NULL));
 
10752
+           } else {
 
10753
+               syslog(LOG_NOTICE, "badlogin: %s %s",
 
10754
+                      popd_clienthost, authtype);
 
10755
+           }
 
10756
+       }
 
10757
+       
 
10758
+       reset_saslconn(&popd_saslconn);
 
10759
+       return;
 
10760
+    }
 
10761
+
 
10762
+    /* successful authentication */
 
10763
+
 
10764
+    /* get the userid from SASL --- already canonicalized from
 
10765
+     * mysasl_proxy_policy()
 
10766
+     */
 
10767
+    sasl_result = sasl_getprop(popd_saslconn, SASL_USERNAME,
 
10768
+                              (const void **) &canon_user);
 
10769
+    popd_userid = xstrdup(canon_user);
 
10770
+    if (sasl_result != SASL_OK) {
 
10771
+       prot_printf(popd_out, 
 
10772
+                   "-ERR [AUTH] weird SASL error %d getting SASL_USERNAME\r\n", 
 
10773
+                   sasl_result);
 
10774
+       return;
 
10775
+    }
 
10776
+    
 
10777
+    syslog(LOG_NOTICE, "login: %s %s %s%s %s", popd_clienthost, popd_userid,
 
10778
+          authtype, popd_starttls_done ? "+TLS" : "", "User logged in");
 
10779
+
 
10780
+    if (!openinbox()) {
 
10781
+       prot_setsasl(popd_in,  popd_saslconn);
 
10782
+       prot_setsasl(popd_out, popd_saslconn);
 
10783
+    }
 
10784
+    else {
 
10785
+       reset_saslconn(&popd_saslconn);
 
10786
+    }
 
10787
+}
 
10788
+
 
10789
+/*
 
10790
+ * Complete the login process by opening and locking the user's inbox
 
10791
+ */
 
10792
+int openinbox(void)
 
10793
+{
 
10794
+    char userid[MAX_MAILBOX_NAME+1], inboxname[MAX_MAILBOX_PATH+1];
 
10795
+    int type, myrights = 0;
 
10796
+    char *server = NULL, *acl;
 
10797
+    int r, log_level = LOG_ERR;
 
10798
+    const char *statusline = NULL;
 
10799
+
 
10800
+    /* Translate any separators in userid
 
10801
+       (use a copy since we need the original userid for AUTH to backend) */
 
10802
+    strlcpy(userid, popd_userid, sizeof(userid));
 
10803
+    mboxname_hiersep_tointernal(&popd_namespace, userid,
 
10804
+                               config_virtdomains ?
 
10805
+                               strcspn(userid, "@") : 0);
 
10806
+
 
10807
+    r = (*popd_namespace.mboxname_tointernal)(&popd_namespace, "INBOX",
 
10808
+                                             userid, inboxname);
 
10809
+
 
10810
+    if (!r) r = mboxlist_detail(inboxname, &type, NULL, &server, &acl, NULL);
 
10811
+    if (!r && (config_popuseacl = config_getswitch(IMAPOPT_POPUSEACL)) &&
 
10812
+       (!acl ||
 
10813
+        !((myrights = cyrus_acl_myrights(popd_authstate, acl)) & ACL_READ))) {
 
10814
+       r = (myrights & ACL_LOOKUP) ?
 
10815
+           IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
 
10816
+       log_level = LOG_INFO;
 
10817
+    }
 
10818
+    if (r) {
 
10819
+       sleep(3);
 
10820
+       syslog(log_level, "Unable to locate maildrop for %s: %s",
 
10821
+              popd_userid, error_message(r));
 
10822
+       prot_printf(popd_out,
 
10823
+                   "-ERR [SYS/PERM] Unable to locate maildrop: %s\r\n",
 
10824
+                   error_message(r));
 
10825
+       goto fail;
 
10826
+    }
 
10827
+
 
10828
+    if (type & MBTYPE_REMOTE) {
 
10829
+       /* remote mailbox */
 
10830
+
 
10831
+       /* xxx hide the fact that we are storing partitions */
 
10832
+       if (server) {
 
10833
+           char *c;
 
10834
+           c = strchr(server, '!');
 
10835
+           if(c) *c = '\0';
 
10836
+       }
 
10837
+
 
10838
+       backend = backend_connect(NULL, server, &protocol[PROTOCOL_POP3],
 
10839
+                                 popd_userid, &statusline);
 
10840
+
 
10841
+       if (!backend) {
 
10842
+           syslog(LOG_ERR, "couldn't authenticate to backend server");
 
10843
+           prot_printf(popd_out, "-ERR%s",
 
10844
+                       statusline ? statusline :
 
10845
+                       " Authentication to backend server failed\r\n");
 
10846
+           prot_flush(popd_out);
 
10847
+           
 
10848
+           goto fail;
 
10849
+       }
 
10850
+    }
 
10851
+    else {
 
10852
+       /* local mailbox */
 
10853
+       int msg;
 
10854
+       struct index_record record;
 
10855
+       int minpoll;
 
10856
+       int doclose = 0;
 
10857
+
 
10858
+       popd_login_time = time(0);
 
10859
+
 
10860
+       r = mailbox_open_header(inboxname, popd_authstate, &mboxstruct);
 
10861
+       if (!r) {
 
10862
+           doclose = 1;
 
10863
+           if (config_popuseacl && !(mboxstruct.myrights & ACL_READ)) {
 
10864
+               r = (mboxstruct.myrights & ACL_LOOKUP) ?
 
10865
+                   IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
 
10866
+               log_level = LOG_INFO;
 
10867
+           }
 
10868
+       }
 
10869
+       if (r) {
 
10870
+           sleep(3);
 
10871
+           syslog(log_level, "Unable to open maildrop for %s: %s",
 
10872
+                  popd_userid, error_message(r));
 
10873
+           prot_printf(popd_out,
 
10874
+                       "-ERR [SYS/PERM] Unable to open maildrop: %s\r\n",
 
10875
+                       error_message(r));
 
10876
+           if (doclose) mailbox_close(&mboxstruct);
 
10877
+           goto fail;
 
10878
+       }
 
10879
+
 
10880
+       r = mailbox_open_index(&mboxstruct);
 
10881
+       if (!r) r = mailbox_lock_pop(&mboxstruct);
 
10882
+       if (r) {
 
10883
+           mailbox_close(&mboxstruct);
 
10884
+           syslog(LOG_ERR, "Unable to lock maildrop for %s: %s",
 
10885
+                  popd_userid, error_message(r));
 
10886
+           prot_printf(popd_out,
 
10887
+                       "-ERR [IN-USE] Unable to lock maildrop: %s\r\n",
 
10888
+                       error_message(r));
 
10889
+           goto fail;
 
10890
+       }
 
10891
+
 
10892
+       if ((minpoll = config_getint(IMAPOPT_POPMINPOLL)) &&
 
10893
+           mboxstruct.pop3_last_login + 60*minpoll > popd_login_time) {
 
10894
+           prot_printf(popd_out,
 
10895
+                       "-ERR [LOGIN-DELAY] Logins must be at least %d minute%s apart\r\n",
 
10896
+                       minpoll, minpoll > 1 ? "s" : "");
 
10897
+           if (!mailbox_lock_index(&mboxstruct)) {
 
10898
+               mboxstruct.pop3_last_login = popd_login_time;
 
10899
+               mailbox_write_index_header(&mboxstruct);
 
10900
+           }
 
10901
+           mailbox_close(&mboxstruct);
 
10902
+           goto fail;
 
10903
+       }
 
10904
+
 
10905
+       if (chdir(mboxstruct.path)) {
 
10906
+           syslog(LOG_ERR, "IOERROR: changing directory to %s: %m",
 
10907
+                  mboxstruct.path);
 
10908
+           r = IMAP_IOERROR;
 
10909
+       }
 
10910
+       if (!r) {
 
10911
+           popd_exists = mboxstruct.exists;
 
10912
+           popd_msg = (struct msg *) xrealloc(popd_msg, (popd_exists+1) *
 
10913
+                                              sizeof(struct msg));
 
10914
+           for (msg = 1; msg <= popd_exists; msg++) {
 
10915
+               if ((r = mailbox_read_index_record(&mboxstruct, msg, &record))!=0)
 
10916
+                   break;
 
10917
+               popd_msg[msg].uid = record.uid;
 
10918
+               popd_msg[msg].size = record.size;
 
10919
+               popd_msg[msg].deleted = 0;
 
10920
+           }
 
10921
+       }
 
10922
+       if (r) {
 
10923
+           mailbox_close(&mboxstruct);
 
10924
+           popd_exists = 0;
 
10925
+           syslog(LOG_ERR, "Unable to read maildrop for %s", popd_userid);
 
10926
+           prot_printf(popd_out,
 
10927
+                       "-ERR [SYS/PERM] Unable to read maildrop\r\n");
 
10928
+           goto fail;
 
10929
+       }
 
10930
+       popd_mailbox = &mboxstruct;
 
10931
+       proc_register("pop3d", popd_clienthost, popd_userid,
 
10932
+                     popd_mailbox->name);
 
10933
+    }
 
10934
+
 
10935
+    /* Create telemetry log */
 
10936
+    popd_logfd = telemetry_log(popd_userid, popd_in, popd_out, 0);
 
10937
+
 
10938
+    prot_printf(popd_out, "+OK%s",
 
10939
+               statusline ? statusline : " Mailbox locked and ready\r\n");
 
10940
+    prot_flush(popd_out);
 
10941
+    return 0;
 
10942
+
 
10943
+  fail:
 
10944
+    free(popd_userid);
 
10945
+    popd_userid = 0;
 
10946
+    auth_freestate(popd_authstate);
 
10947
+    popd_authstate = NULL;
 
10948
+    return 1;
 
10949
+}
 
10950
+
 
10951
+static void blat(int msg,int lines)
 
10952
+{
 
10953
+    FILE *msgfile;
 
10954
+    char buf[4096];
 
10955
+    char fnamebuf[MAILBOX_FNAME_LEN];
 
10956
+    int thisline = -2;
 
10957
+
 
10958
+    mailbox_message_get_fname(popd_mailbox, popd_msg[msg].uid, fnamebuf,
 
10959
+                             sizeof(fnamebuf));
 
10960
+    msgfile = fopen(fnamebuf, "r");
 
10961
+    if (!msgfile) {
 
10962
+       prot_printf(popd_out, "-ERR [SYS/PERM] Could not read message file\r\n");
 
10963
+       return;
 
10964
+    }
 
10965
+    prot_printf(popd_out, "+OK Message follows\r\n");
 
10966
+    while (lines != thisline) {
 
10967
+       if (!fgets(buf, sizeof(buf), msgfile)) break;
 
10968
+
 
10969
+       if (thisline < 0) {
 
10970
+           if (buf[0] == '\r' && buf[1] == '\n') thisline = 0;
 
10971
+       }
 
10972
+       else thisline++;
 
10973
+
 
10974
+       if (buf[0] == '.') prot_putc('.', popd_out);
 
10975
+       do {
 
10976
+           prot_printf(popd_out, "%s", buf);
 
10977
+       }
 
10978
+       while (buf[strlen(buf)-1] != '\n' && fgets(buf, sizeof(buf), msgfile));
 
10979
+    }
 
10980
+    fclose(msgfile);
 
10981
+
 
10982
+    /* Protect against messages not ending in CRLF */
 
10983
+    if (buf[strlen(buf)-1] != '\n') prot_printf(popd_out, "\r\n");
 
10984
+
 
10985
+    prot_printf(popd_out, ".\r\n");
 
10986
+}
 
10987
+
 
10988
+static int parsenum(char **ptr)
 
10989
+{
 
10990
+    char *p = *ptr;
 
10991
+    int result = 0;
 
10992
+
 
10993
+    if (!isdigit((int) *p)) {
 
10994
+       *ptr = 0;
 
10995
+       return -1;
 
10996
+    }
 
10997
+    while (*p && isdigit((int) *p)) {
 
10998
+       result = result * 10 + *p++ - '0';
 
10999
+        if (result < 0) {
 
11000
+            /* xxx overflow */
 
11001
+        }
 
11002
+    }
 
11003
+
 
11004
+    if (*p) {
 
11005
+       while (*p && isspace((int) *p)) p++;
 
11006
+       *ptr = p;
 
11007
+    }
 
11008
+    else *ptr = 0;
 
11009
+    return result;
 
11010
+}
 
11011
+
 
11012
+static int expungedeleted(struct mailbox *mailbox __attribute__((unused)),
 
11013
+                         void *rock __attribute__((unused)), char *index)
 
11014
+{
 
11015
+    int msg;
 
11016
+    int uid = ntohl(*((bit32 *)(index+OFFSET_UID)));
 
11017
+
 
11018
+    for (msg = 1; msg <= popd_exists; msg++) {
 
11019
+       if (popd_msg[msg].uid == uid) {
 
11020
+           return popd_msg[msg].deleted;
 
11021
+       }
 
11022
+    }
 
11023
+    return 0;
 
11024
+}
 
11025
+
 
11026
+/* Reset the given sasl_conn_t to a sane state */
 
11027
+static int reset_saslconn(sasl_conn_t **conn) 
 
11028
+{
 
11029
+    int ret;
 
11030
+    sasl_security_properties_t *secprops = NULL;
 
11031
+
 
11032
+    sasl_dispose(conn);
 
11033
+    /* do initialization typical of service_main */
 
11034
+    ret = sasl_server_new("pop", config_servername,
 
11035
+                         NULL, NULL, NULL,
 
11036
+                         NULL, 0, conn);
 
11037
+    if(ret != SASL_OK) return ret;
 
11038
+
 
11039
+    if(saslprops.ipremoteport)
 
11040
+       ret = sasl_setprop(*conn, SASL_IPREMOTEPORT,
 
11041
+                          saslprops.ipremoteport);
 
11042
+    if(ret != SASL_OK) return ret;
 
11043
+    
 
11044
+    if(saslprops.iplocalport)
 
11045
+       ret = sasl_setprop(*conn, SASL_IPLOCALPORT,
 
11046
+                          saslprops.iplocalport);
 
11047
+    if(ret != SASL_OK) return ret;
 
11048
+    secprops = mysasl_secprops(SASL_SEC_NOPLAINTEXT);
 
11049
+    ret = sasl_setprop(*conn, SASL_SEC_PROPS, secprops);
 
11050
+    if(ret != SASL_OK) return ret;
 
11051
+    /* end of service_main initialization excepting SSF */
 
11052
+
 
11053
+    /* If we have TLS/SSL info, set it */
 
11054
+    if(saslprops.ssf) {
 
11055
+       ret = sasl_setprop(*conn, SASL_SSF_EXTERNAL, &saslprops.ssf);
 
11056
+    }
 
11057
+
 
11058
+    if(ret != SASL_OK) return ret;
 
11059
+
 
11060
+    if(saslprops.authid) {
 
11061
+       ret = sasl_setprop(*conn, SASL_AUTH_EXTERNAL, saslprops.authid);
 
11062
+       if(ret != SASL_OK) return ret;
 
11063
+    }
 
11064
+    /* End TLS/SSL Info */
 
11065
+
 
11066
+    return SASL_OK;
 
11067
+}
 
11068
+
 
11069
+/* we've authenticated the client, we've connected to the backend.
 
11070
+   now it's all up to them */
 
11071
+static void bitpipe(void)
 
11072
+{
 
11073
+    struct protgroup *protin = protgroup_new(2);
 
11074
+    struct protgroup *protout = NULL;
 
11075
+    struct timeval timeout;
 
11076
+    int n, shutdown = 0;
 
11077
+    char buf[4096];
 
11078
+
 
11079
+    /* Reset protin to all zeros (to preserve memory allocation) */
 
11080
+    protgroup_reset(protin);
 
11081
+    protgroup_insert(protin, popd_in);
 
11082
+    protgroup_insert(protin, backend->in);
 
11083
+
 
11084
+    for (;;) {
 
11085
+       /* check for shutdown file */
 
11086
+       if (shutdown_file(buf, sizeof(buf))) {
 
11087
+           shutdown = 1;
 
11088
+           goto done;
 
11089
+       }
 
11090
+
 
11091
+       /* Clear protout if needed */
 
11092
+       protgroup_free(protout);
 
11093
+       protout = NULL;
 
11094
+
 
11095
+       timeout.tv_sec = 60;
 
11096
+       timeout.tv_usec = 0;
 
11097
+
 
11098
+       n = prot_select(protin, PROT_NO_FD, &protout, NULL, &timeout);
 
11099
+       if (n == -1) {
 
11100
+           syslog(LOG_ERR, "prot_select() failed in bitpipe(): %m");
 
11101
+           fatal("prot_select() failed in bitpipe()", EC_TEMPFAIL);
 
11102
+       }
 
11103
+       if (n && protout) {
 
11104
+           struct protstream *ptmp;
 
11105
+
 
11106
+           for (; n; n--) {
 
11107
+               ptmp = protgroup_getelement(protout, n-1);
 
11108
+
 
11109
+               if (ptmp == popd_in) {
 
11110
+                   do {
 
11111
+                       int c = prot_read(popd_in, buf, sizeof(buf));
 
11112
+                       if (c == 0 || c < 0) goto done;
 
11113
+                       prot_write(backend->out, buf, c);
 
11114
+                   } while (popd_in->cnt > 0);
 
11115
+                   prot_flush(backend->out);
 
11116
+               }
 
11117
+               else if (ptmp == backend->in) {
 
11118
+                   do {
 
11119
+                       int c = prot_read(backend->in, buf, sizeof(buf));
 
11120
+                       if (c == 0 || c < 0) goto done;
 
11121
+                       prot_write(popd_out, buf, c);
 
11122
+                   } while (backend->in->cnt > 0);
 
11123
+                   prot_flush(popd_out);
 
11124
+               }
 
11125
+               else {
 
11126
+                   /* XXX shouldn't get here !!! */
 
11127
+                   fatal("unknown protstream returned by prot_select in bitpipe()",
 
11128
+                         EC_SOFTWARE);
 
11129
+               }
 
11130
+           }
 
11131
+       }
 
11132
+    }
 
11133
+
 
11134
+
 
11135
+ done:
 
11136
+    /* ok, we're done. */
 
11137
+    protgroup_free(protin);
 
11138
+    protgroup_free(protout);
 
11139
+
 
11140
+    if (shutdown) {
 
11141
+       char *p;
 
11142
+       for (p = buf; *p == '['; p++); /* can't have [ be first char */
 
11143
+       prot_printf(popd_out, "-ERR [SYS/TEMP] %s\r\n", p);
 
11144
+       shut_down(0);
 
11145
+    }
 
11146
+
 
11147
+    return;
 
11148
+}
 
11149
+
 
11150
+
 
11151
+void printstring(const char *s __attribute__((unused)))
 
11152
+{
 
11153
+    /* needed to link against annotate.o */
 
11154
+    fatal("printstring() executed, but its not used for POP3!",
 
11155
+         EC_SOFTWARE);
 
11156
+}
 
11157
diff -urNad cyrus-imapd-2.2.13/imap/version.c /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/imap/version.c
 
11158
--- cyrus-imapd-2.2.13/imap/version.c   2006-03-31 20:18:13.000000000 +0200
 
11159
+++ /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/imap/version.c  2006-04-18 20:39:35.704094779 +0200
267
11160
@@ -151,6 +151,10 @@
268
11161
     snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
269
11162
             "; %s", SIEVE_VERSION);
275
11168
 #ifdef HAVE_LIBWRAP
276
11169
     snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
277
11170
             "; TCP Wrappers");
278
 
diff -urNad cyrus-imapd-2.2.12/lib/imapoptions /tmp/dpep.FoExSn/cyrus-imapd-2.2.12/lib/imapoptions
279
 
--- cyrus-imapd-2.2.12/lib/imapoptions  2006-02-14 17:13:36.000000000 +0100
280
 
+++ /tmp/dpep.FoExSn/cyrus-imapd-2.2.12/lib/imapoptions 2006-02-14 17:13:44.663437849 +0100
281
 
@@ -196,6 +196,15 @@
 
11171
diff -urNad cyrus-imapd-2.2.13/imap/version.c.orig /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/imap/version.c.orig
 
11172
--- cyrus-imapd-2.2.13/imap/version.c.orig      1970-01-01 01:00:00.000000000 +0100
 
11173
+++ /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/imap/version.c.orig     2006-04-18 20:39:35.705094682 +0200
 
11174
@@ -0,0 +1,181 @@
 
11175
+/* version.c: versioning functions
 
11176
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
 
11177
+ *
 
11178
+ * Redistribution and use in source and binary forms, with or without
 
11179
+ * modification, are permitted provided that the following conditions
 
11180
+ * are met:
 
11181
+ *
 
11182
+ * 1. Redistributions of source code must retain the above copyright
 
11183
+ *    notice, this list of conditions and the following disclaimer. 
 
11184
+ *
 
11185
+ * 2. Redistributions in binary form must reproduce the above copyright
 
11186
+ *    notice, this list of conditions and the following disclaimer in
 
11187
+ *    the documentation and/or other materials provided with the
 
11188
+ *    distribution.
 
11189
+ *
 
11190
+ * 3. The name "Carnegie Mellon University" must not be used to
 
11191
+ *    endorse or promote products derived from this software without
 
11192
+ *    prior written permission. For permission or any other legal
 
11193
+ *    details, please contact  
 
11194
+ *      Office of Technology Transfer
 
11195
+ *      Carnegie Mellon University
 
11196
+ *      5000 Forbes Avenue
 
11197
+ *      Pittsburgh, PA  15213-3890
 
11198
+ *      (412) 268-4387, fax: (412) 268-7395
 
11199
+ *      tech-transfer@andrew.cmu.edu
 
11200
+ *
 
11201
+ * 4. Redistributions of any form whatsoever must retain the following
 
11202
+ *    acknowledgment:
 
11203
+ *    "This product includes software developed by Computing Services
 
11204
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
 
11205
+ *
 
11206
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
11207
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 
11208
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
 
11209
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
11210
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 
11211
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 
11212
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
11213
+ *
 
11214
+ * $Id: version.c,v 1.19 2005/02/16 20:37:58 shadow Exp $
 
11215
+ */
 
11216
+
 
11217
+#include <config.h>
 
11218
+
 
11219
+#include <sasl/sasl.h>
 
11220
+#include <sys/utsname.h>
 
11221
+#ifdef HAVE_BDB
 
11222
+#include <db.h>
 
11223
+#endif
 
11224
+#ifdef HAVE_KRB
 
11225
+#include <krb.h>
 
11226
+#endif
 
11227
+#ifdef HAVE_UCDSNMP
 
11228
+#include <ucd-snmp/version.h>
 
11229
+#endif
 
11230
+
 
11231
+#include <string.h>
 
11232
+#include "version.h"
 
11233
+#include "xversion.h"
 
11234
+#include "prot.h"
 
11235
+#include "cyrusdb.h"
 
11236
+#include "map.h"
 
11237
+#include "lock.h"
 
11238
+#include "nonblock.h"
 
11239
+#include "idle.h"
 
11240
+
 
11241
+#ifdef USE_SIEVE
 
11242
+#include "sieve_interface.h"
 
11243
+#endif
 
11244
+
 
11245
+static char id_resp_command[MAXIDVALUELEN];
 
11246
+static char id_resp_arguments[MAXIDVALUELEN] = "";
 
11247
+
 
11248
+/*
 
11249
+ * Grab the command line args for the ID response.
 
11250
+ */
 
11251
+void id_getcmdline(int argc, char **argv)
 
11252
+{
 
11253
+    snprintf(id_resp_command, MAXIDVALUELEN, *argv);
 
11254
+    while (--argc > 0) {
 
11255
+       snprintf(id_resp_arguments + strlen(id_resp_arguments),
 
11256
+                MAXIDVALUELEN - strlen(id_resp_arguments),
 
11257
+                "%s%s", *++argv, (argc > 1) ? " " : "");
 
11258
+    }
 
11259
+}
 
11260
+
 
11261
+/*
 
11262
+ * Output the ID response.
 
11263
+ * We do NOT close the parameter list so other stuff can be added later.
 
11264
+ */
 
11265
+void id_response(struct protstream *pout)
 
11266
+{
 
11267
+    struct utsname os;
 
11268
+    const char *sasl_imp;
 
11269
+    int sasl_ver;
 
11270
+    char env_buf[MAXIDVALUELEN+1];
 
11271
+
 
11272
+    prot_printf(pout, "* ID ("
 
11273
+               "\"name\" \"Cyrus IMAPD\""
 
11274
+               " \"version\" \"%s %s\""
 
11275
+               " \"vendor\" \"Project Cyrus\""
 
11276
+               " \"support-url\" \"http://asg.web.cmu.edu/cyrus\"",
 
11277
+               CYRUS_VERSION, CYRUS_CVSDATE);
 
11278
+
 
11279
+    /* add the os info */
 
11280
+    if (uname(&os) != -1)
 
11281
+       prot_printf(pout,
 
11282
+                   " \"os\" \"%s\""
 
11283
+                   " \"os-version\" \"%s\"",
 
11284
+                   os.sysname, os.release);
 
11285
+
 
11286
+#ifdef ID_SAVE_CMDLINE
 
11287
+    /* add the command line info */
 
11288
+    prot_printf(pout, " \"command\" \"%s\"", id_resp_command);
 
11289
+    if (strlen(id_resp_arguments)) {
 
11290
+       prot_printf(pout, " \"arguments\" \"%s\"", id_resp_arguments);
 
11291
+    } else {
 
11292
+       prot_printf(pout, " \"arguments\" NIL");
 
11293
+    }
 
11294
+#endif
 
11295
+
 
11296
+    /* SASL information */
 
11297
+    snprintf(env_buf, MAXIDVALUELEN,"Built w/Cyrus SASL %d.%d.%d",
 
11298
+            SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP);
 
11299
+
 
11300
+    sasl_version(&sasl_imp, &sasl_ver);
 
11301
+    snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
 
11302
+            "; Running w/%s %d.%d.%d", sasl_imp,
 
11303
+            (sasl_ver & 0xFF000000) >> 24,
 
11304
+            (sasl_ver & 0x00FF0000) >> 16,
 
11305
+            (sasl_ver & 0x0000FFFF));
 
11306
+
 
11307
+    /* add the environment info */
 
11308
+#ifdef DB_VERSION_STRING
 
11309
+    snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
 
11310
+            "; Built w/%s", DB_VERSION_STRING);
 
11311
+    snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
 
11312
+            "; Running w/%s", db_version(NULL, NULL, NULL));
 
11313
+#endif
 
11314
+#ifdef HAVE_SSL
 
11315
+    snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
 
11316
+            "; Built w/%s", OPENSSL_VERSION_TEXT);
 
11317
+    snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
 
11318
+            "; Running w/%s", SSLeay_version(SSLEAY_VERSION));
 
11319
+#ifdef EGD_SOCKET
 
11320
+    snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
 
11321
+            " (with EGD)");
 
11322
+#endif
 
11323
+#endif
 
11324
+#ifdef USE_SIEVE
 
11325
+    snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
 
11326
+            "; %s", SIEVE_VERSION);
 
11327
+#endif
 
11328
+#ifdef HAVE_LIBWRAP
 
11329
+    snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
 
11330
+            "; TCP Wrappers");
 
11331
+#endif
 
11332
+#ifdef HAVE_UCDSNMP
 
11333
+    snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
 
11334
+            "; UCD-SNMP %s", VersionInfo);
 
11335
+#endif
 
11336
+#ifdef HAVE_NETSNMP
 
11337
+    snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
 
11338
+            "; NET-SNMP");
 
11339
+#endif
 
11340
+    snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
 
11341
+            "; mmap = %s", map_method_desc);
 
11342
+    snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
 
11343
+            "; lock = %s", lock_method_desc);
 
11344
+    snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
 
11345
+            "; nonblock = %s", nonblock_method_desc);
 
11346
+#ifdef HAVE_KRB
 
11347
+    snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
 
11348
+            " (%s)", krb4_version);
 
11349
+#endif
 
11350
+    if (idle_method_desc)
 
11351
+       snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
 
11352
+                "; idle = %s", idle_method_desc);
 
11353
+
 
11354
+    prot_printf(pout, " \"environment\" \"%s\"", env_buf);
 
11355
+}
 
11356
diff -urNad cyrus-imapd-2.2.13/lib/imapoptions /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/lib/imapoptions
 
11357
--- cyrus-imapd-2.2.13/lib/imapoptions  2006-04-18 20:39:34.000000000 +0200
 
11358
+++ /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/lib/imapoptions 2006-04-18 20:39:35.706094585 +0200
 
11359
@@ -199,6 +199,14 @@
282
11360
 { "deleteright", "c", STRING }
283
11361
 /* The right that a user needs to delete a mailbox. */
284
11362
 
285
11363
+{ "dracinterval", 0, INT }
286
11364
+/* If nonzero, enables the use of DRAC (Dynamic Relay Authorization
287
11365
+   Control) by the pop3d and imapd daemons.  Also sets the interval
288
 
+   (in minutes) between re-authorization requests made by imapd.
289
 
+   Default is 0, sensible Value when enabling it is 5. */
 
11366
+   (in minutes) between re-authorization requests made by imapd. */
290
11367
+
291
11368
+{ "drachost", "localhost", STRING }
292
 
+/* Hostname of the RPC dracd server. Default: localhost */
 
11369
+/* Hostname of the RPC dracd server. */
293
11370
+
294
 
 { "duplicate_db", "berkeley-nosync", STRINGLIST("berkeley", "berkeley-nosync", "skiplist")}
 
11371
 { "duplicate_db", "berkeley-nosync", STRINGLIST("berkeley", "berkeley-nosync", "berkeley-hash", "berkeley-hash-nosync", "skiplist")}
295
11372
 /* The cyrusdb backend to use for the duplicate delivery suppression
296
11373
    and sieve. */
 
11374
diff -urNad cyrus-imapd-2.2.13/lib/imapoptions.orig /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/lib/imapoptions.orig
 
11375
--- cyrus-imapd-2.2.13/lib/imapoptions.orig     1970-01-01 01:00:00.000000000 +0100
 
11376
+++ /tmp/dpep.bMlzdR/cyrus-imapd-2.2.13/lib/imapoptions.orig    2006-04-18 20:39:35.707094488 +0200
 
11377
@@ -0,0 +1,895 @@
 
11378
+# things inside of C comments get copied to the manpage
 
11379
+# things starting with # are ignored
 
11380
+
 
11381
+/* .\" -*- nroff -*-
 
11382
+.TH IMAPD.CONF 5 "Project Cyrus" CMU
 
11383
+.\" 
 
11384
+.\" Copyright (c) 1998-2000 Carnegie Mellon University.  All rights reserved.
 
11385
+.\"
 
11386
+.\" Redistribution and use in source and binary forms, with or without
 
11387
+.\" modification, are permitted provided that the following conditions
 
11388
+.\" are met:
 
11389
+.\"
 
11390
+.\" 1. Redistributions of source code must retain the above copyright
 
11391
+.\"    notice, this list of conditions and the following disclaimer. 
 
11392
+.\"
 
11393
+.\" 2. Redistributions in binary form must reproduce the above copyright
 
11394
+.\"    notice, this list of conditions and the following disclaimer in
 
11395
+.\"    the documentation and/or other materials provided with the
 
11396
+.\"    distribution.
 
11397
+.\"
 
11398
+.\" 3. The name "Carnegie Mellon University" must not be used to
 
11399
+.\"    endorse or promote products derived from this software without
 
11400
+.\"    prior written permission. For permission or any other legal
 
11401
+.\"    details, please contact  
 
11402
+.\"      Office of Technology Transfer
 
11403
+.\"      Carnegie Mellon University
 
11404
+.\"      5000 Forbes Avenue
 
11405
+.\"      Pittsburgh, PA  15213-3890
 
11406
+.\"      (412) 268-4387, fax: (412) 268-7395
 
11407
+.\"      tech-transfer@andrew.cmu.edu
 
11408
+.\"
 
11409
+.\" 4. Redistributions of any form whatsoever must retain the following
 
11410
+.\"    acknowledgment:
 
11411
+.\"    "This product includes software developed by Computing Services
 
11412
+.\"     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
 
11413
+.\"
 
11414
+.\" CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
11415
+.\" THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 
11416
+.\" AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
 
11417
+.\" FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
11418
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 
11419
+.\" AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 
11420
+.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
11421
+.\" 
 
11422
+.\" $Id: imapoptions,v 1.36 2006/03/30 15:49:58 murch Exp $
 
11423
+.SH NAME
 
11424
+imapd.conf \- IMAP configuration file
 
11425
+.SH DESCRIPTION
 
11426
+\fB/etc/imapd.conf\fR 
 
11427
+is the configuration file for the Cyrus IMAP server.  It defines
 
11428
+local parameters for IMAP. 
 
11429
+.PP
 
11430
+Each line of the \fB/etc/imapd.conf\fR file has the form
 
11431
+.IP
 
11432
+\fIoption\fR: \fIvalue\fR
 
11433
+.PP
 
11434
+where \fIoption\fR is the name of the configuration option being set
 
11435
+and \fIvalue\fR is the value that the configuration option is being
 
11436
+set to.
 
11437
+.PP
 
11438
+Blank lines and lines beginning with ``#'' are ignored.
 
11439
+.PP
 
11440
+For boolean and enumerated options, the values ``yes'', ``on'', ``t'',
 
11441
+``true'' and ``1'' turn the option on, the values ``no'', ``off'',
 
11442
+``f'', ``false'' and ``0'' turn the option off.
 
11443
+.SH FIELD DESCRIPTIONS
 
11444
+.PP
 
11445
+The sections below detail options that can be placed in the
 
11446
+\fB/etc/imapd.conf\fR file, and show each option's default value.
 
11447
+Some options have no default value, these are listed with
 
11448
+``<no default>''.  Some options default to the empty string, these
 
11449
+are listed with ``<none>''.
 
11450
+*/
 
11451
+
 
11452
+# OPTIONS
 
11453
+
 
11454
+{ "admins", "", STRING }
 
11455
+/* The list of userids with administrative rights.  Separate each userid
 
11456
+   with a space.  Sites using Kerberos authentication may use
 
11457
+   separate "admin" instances.
 
11458
+.PP
 
11459
+   Note that accounts used by users should not be administrators.
 
11460
+   Administrative accounts should not receive mail.  That is, if user
 
11461
+   "jbRo" is a user reading mail, he should not also be in the admins line.
 
11462
+   Some problems may occur otherwise, most notably the ability of
 
11463
+   administrators to create top-level mailboxes visible to users,
 
11464
+   but not writable by users. */
 
11465
+
 
11466
+{ "afspts_localrealms", NULL, STRING }
 
11467
+/* The list of realms which are to be treated as local, and thus stripped
 
11468
+   during identifier canoicalization (for the AFSPTS ptloader module).
 
11469
+   This is different from loginrealms in that it occurs later in the
 
11470
+   authorization process (as the user id is canonified for PTS lookup) */
 
11471
+
 
11472
+{ "afspts_mycell", NULL, STRING }
 
11473
+/* Cell to use for AFS PTS lookups.  Defaults to the local cell. */
 
11474
+
 
11475
+{ "allowallsubscribe", 0, SWITCH }
 
11476
+/* Allow subscription to nonexistent mailboxes.  This option is
 
11477
+   typically used on backend servers in a Murder so that users can
 
11478
+   subscribe to mailboxes that don't reside on their "home" server.
 
11479
+   This option can also be used as a workaround for IMAP clients which
 
11480
+   don't play well with nonexistent or unselectable mailboxes (eg.
 
11481
+   Microsoft Outlook). */
 
11482
+
 
11483
+{ "allowanonymouslogin", 0, SWITCH }
 
11484
+/* Permit logins by the user "anonymous" using any password.  Also
 
11485
+   allows use of the SASL ANONYMOUS mechanism. */
 
11486
+
 
11487
+{ "allowapop", 1, SWITCH }
 
11488
+/* Allow use of the POP3 APOP authentication command.
 
11489
+.PP
 
11490
+  Note that this command requires that SASL is compiled with APOP
 
11491
+  support, that the plaintext passwords are available in a SASL auxprop
 
11492
+  backend (eg. sasldb), and that the system can provide enough entropy
 
11493
+  (eg. from /dev/urandom) to create a challenge in the banner. */
 
11494
+
 
11495
+{ "allownewnews", 0, SWITCH }
 
11496
+/* Allow use of the NNTP NEWNEWS command.
 
11497
+.PP
 
11498
+  Note that this is a very expensive command and should only be
 
11499
+  enabled when absolutely necessary. */
 
11500
+
 
11501
+{ "allowplaintext", 1, SWITCH }
 
11502
+/* Allow the use of cleartext passwords on the wire. */
 
11503
+   
 
11504
+{ "allowusermoves", 0, SWITCH }
 
11505
+/* Allow moving user accounts (with associated meta-data) via RENAME
 
11506
+   or XFER.
 
11507
+.PP
 
11508
+  Note that measures should be taken to make sure that the user being
 
11509
+  moved is not logged in, and can not login during the move.  Failure
 
11510
+  to do so may result in the user's meta-data (seen state,
 
11511
+  subscriptions, etc) being corrupted or out of date. */
 
11512
+   
 
11513
+{ "altnamespace", 0, SWITCH }
 
11514
+/* Use the alternate IMAP namespace, where personal folders reside at the
 
11515
+   same level in the hierarchy as INBOX.
 
11516
+.PP
 
11517
+   This option ONLY applies where interaction takes place with the
 
11518
+   client/user.  Currently this is limited to the IMAP protocol (imapd)
 
11519
+   and Sieve scripts (lmtpd).  This option does NOT apply to admin tools
 
11520
+   such as cyradm (admins ONLY), reconstruct, quota, etc., NOR does it
 
11521
+   affect LMTP delivery of messages directly to mailboxes via
 
11522
+   plus-addressing. */
 
11523
+
 
11524
+{ "annotation_db", "skiplist", STRINGLIST("berkeley", "berkeley-hash", "skiplist")}
 
11525
+/* The cyrusdb backend to use for mailbox annotations. */
 
11526
+
 
11527
+{ "auth_mech", "unix", STRINGLIST("unix", "pts", "krb", "krb5")}
 
11528
+/* The authorization mechanism to use. */
 
11529
+
 
11530
+{ "autocreatequota", 0, INT }
 
11531
+/* If nonzero, normal users may create their own IMAP accounts by
 
11532
+   creating the mailbox INBOX.  The user's quota is set to the value
 
11533
+   if it is positive, otherwise the user has unlimited quota. */
 
11534
+
 
11535
+{ "berkeley_cachesize", 512, INT }
 
11536
+/* Size (in kilobytes) of the shared memory buffer pool (cache) used
 
11537
+   by the berkeley environment.  The minimum allowed value is 20.  The
 
11538
+   maximum allowed value is 4194303 (4GB). */
 
11539
+
 
11540
+{ "berkeley_locks_max", 50000, INT }
 
11541
+/* Maximum number of locks to be held or requested in the berkeley
 
11542
+   environment. */
 
11543
+
 
11544
+{ "berkeley_txns_max", 100, INT }
 
11545
+/* Maximum number of transactions to be supported in the berkeley
 
11546
+   environment. */
 
11547
+
 
11548
+{ "client_timeout", 10, INT }
 
11549
+/* Number of seconds to wait before returning a timeout failure when
 
11550
+   performing a client connection (e.g. in a murder enviornment) */
 
11551
+
 
11552
+{ "configdirectory", NULL, STRING }
 
11553
+/* The pathname of the IMAP configuration directory.  This field is
 
11554
+   required. */
 
11555
+
 
11556
+{ "debug_command", NULL, STRING }
 
11557
+/* Debug command to be used by processes started with -D option.  The string
 
11558
+   is a C format string that gets 3 options: the first is the name of the
 
11559
+   executable (without path).  The second is the pid (integer) and the third
 
11560
+   is the service ID.  Example: /usr/local/bin/gdb /usr/cyrus/bin/%s %d */
 
11561
+
 
11562
+{ "defaultacl", "anyone lrs", STRING }
 
11563
+/* The Access Control List (ACL) placed on a newly-created (non-user)
 
11564
+   mailbox that does not have a parent mailbox. */
 
11565
+
 
11566
+{ "defaultdomain", NULL, STRING }
 
11567
+/* The default domain for virtual domain support. Note that this domain
 
11568
+   is stripped from the email-address transmitted using LMTP, but it
 
11569
+   is not stripped from usernames at login-time. For imapd/pop3d, 
 
11570
+   "user" and "user@defaultdomain" specify two different users.
 
11571
+   Please check install-virtdomains.html for details. */
 
11572
+
 
11573
+{ "defaultpartition", "default", STRING }
 
11574
+/* The partition name used by default for new mailboxes. */
 
11575
+
 
11576
+{ "deleteright", "c", STRING }
 
11577
+/* The right that a user needs to delete a mailbox. */
 
11578
+
 
11579
+{ "duplicate_db", "berkeley-nosync", STRINGLIST("berkeley", "berkeley-nosync", "berkeley-hash", "berkeley-hash-nosync", "skiplist")}
 
11580
+/* The cyrusdb backend to use for the duplicate delivery suppression
 
11581
+   and sieve. */
 
11582
+
 
11583
+{ "duplicatesuppression", 1, SWITCH }
 
11584
+/* If enabled, lmtpd will suppress delivery of a message to a mailbox if
 
11585
+   a message with the same message-id (or resent-message-id) is recorded
 
11586
+   as having already been delivered to the mailbox.  Records the mailbox
 
11587
+   and message-id/resent-message-id of all successful deliveries. */
 
11588
+
 
11589
+{ "foolstupidclients", 0, SWITCH }
 
11590
+/* If enabled, only list the personal namespace when a LIST "*" is performed.
 
11591
+   (it changes the request to a LIST "INBOX*" */
 
11592
+
 
11593
+{ "force_sasl_client_mech", NULL, STRING }
 
11594
+/* Force preference of a given SASL mechanism for client side operations
 
11595
+   (e.g. murder enviornments).  This is separate from (and overridden by)
 
11596
+   the ability to use the <host shortname>_mechs option to set prefered
 
11597
+   mechanisms for a specific host */
 
11598
+
 
11599
+{ "fulldirhash", 0, SWITCH }
 
11600
+/* If enabled, uses an improved directory hashing scheme which hashes
 
11601
+   the entire username instead of using just the first letter.  This
 
11602
+   changes hash algorithm used for quota and user directories and if
 
11603
+   \fIhashimapspool\fR is enabled, the entire mail spool.
 
11604
+.PP
 
11605
+   Note that this option can NOT be changed on a live system.  The
 
11606
+   server must be quiesced and then the directories moved with the
 
11607
+   \fBrehash\fR utility. */
 
11608
+
 
11609
+{ "hashimapspool", 0, SWITCH }
 
11610
+/* If enabled, the partitions will also be hashed, in addition to the
 
11611
+   hashing done on configuration directories.  This is recommended if
 
11612
+   one partition has a very bushy mailbox tree. */
 
11613
+
 
11614
+# Commented out - there's no such thing as "hostname_mechs", but we need
 
11615
+# this for the man page
 
11616
+# { "hostname_mechs", NULL, STRING }
 
11617
+/* Force a particuar list of SASL mechanisms to be used when authenticating
 
11618
+   to the backend server hostname (where hostname is the short hostname of
 
11619
+   the server in question). If it is not specified it will query the server
 
11620
+   for available mechanisms and pick one to use. - Cyrus Murder */
 
11621
+
 
11622
+# Commented out - there's no such thing as "hostname_password", but we need
 
11623
+# this for the man page
 
11624
+# { "hostname_password", NULL, STRING }
 
11625
+/* The password to use for authentication to the backend server hostname
 
11626
+   (where hostname is the short hostname of the server) - Cyrus Murder */
 
11627
+
 
11628
+{ "idlesocket", "{configdirectory}/socket/idle", STRING }
 
11629
+/* Unix domain socket that idled listens on. */
 
11630
+
 
11631
+{ "ignorereference", 0, SWITCH }
 
11632
+/* For backwards compatibility with Cyrus 1.5.10 and earlier -- ignore
 
11633
+  the reference argument in LIST or LSUB commands. */
 
11634
+
 
11635
+{ "imapidlepoll", 60, INT }
 
11636
+/* The interval (in seconds) for polling the mailbox for changes while
 
11637
+   running the IDLE command.  This option is used when idled can not
 
11638
+   be contacted or when polling is used exclusively.  The minimum
 
11639
+   value is 1.  A value of 0 will disable polling (and disable IDLE if
 
11640
+   polling is the only method available). */
 
11641
+
 
11642
+{ "imapidresponse", 1, SWITCH }
 
11643
+/* If enabled, the server responds to an ID command with a parameter 
 
11644
+   list containing: version, vendor, support-url, os, os-version,
 
11645
+   command, arguments, environment.  Otherwise the server returns NIL. */
 
11646
+
 
11647
+{ "imapmagicplus", 0, SWITCH }
 
11648
+/* Only list a restricted set of mailboxes via IMAP by using
 
11649
+   userid+namespace syntax as the authentication/authorization id.
 
11650
+   Using userid+ (with an empty namespace) will list only subscribed
 
11651
+   mailboxes. */ 
 
11652
+
 
11653
+{ "implicit_owner_rights", "lca", STRING }
 
11654
+/* The implicit Access Control List (ACL) for the owner of a mailbox. */
 
11655
+
 
11656
+# Commented out - there's no such thing as "@include", but we need
 
11657
+# this for the man page
 
11658
+# { "@include", NULL, STRING }
 
11659
+/* Directive which includes the specified file as part of the
 
11660
+   configuration.  If the path to the file is not absolute, CYRUS_PATH
 
11661
+   is prepended. */
 
11662
+
 
11663
+{ "ldap_authz", NULL, STRING }
 
11664
+/* SASL authorization ID for the LDAP server */
 
11665
+
 
11666
+{ "ldap_base", "", STRING }
 
11667
+/* Contains the LDAP base dn for the LDAP ptloader module */
 
11668
+
 
11669
+{ "ldap_bind_dn", NULL, STRING }
 
11670
+/* Bind DN for the connection to the LDAP server (simple bind).
 
11671
+   Do not use for anonymous simple binds */
 
11672
+
 
11673
+{ "ldap_deref", "never", STRINGLIST("search", "find", "always", "never") }
 
11674
+/* Specify how aliases dereferencing is handled during search. */
 
11675
+
 
11676
+{ "ldap_filter", "(uid=%u)", STRING }
 
11677
+/* Specify a filter that searches user identifiers.  The following tokens can be
 
11678
+   used in the filter string:
 
11679
+
 
11680
+   %%   = %
 
11681
+   %u   = user
 
11682
+   %U   = user portion of %u (%U = test when %u = test@domain.tld)
 
11683
+   %d   = domain portion of %u if available (%d = domain.tld when %u =
 
11684
+          %test@domain.tld), otherwise same as %r
 
11685
+   %D   = user dn.  (use when ldap_member_method: filter)
 
11686
+   %1-9 = domain tokens (%1 = tld, %2 = domain when %d = domain.tld)
 
11687
+
 
11688
+   ldap_filter is not used when ldap_sasl is enabled. */
 
11689
+
 
11690
+{ "ldap_group_base", "", STRING }
 
11691
+/* LDAP base dn for ldap_group_filter. */
 
11692
+
 
11693
+{ "ldap_group_filter", "(cn=%u)", STRING }
 
11694
+/* Specify a filter that searches for group identifiers.
 
11695
+   See ldap_filter for more options. */ 
 
11696
+
 
11697
+{ "ldap_group_scope", "sub", STRINGLIST("sub", "one", "base") }
 
11698
+/* Specify search scope for ldap_group_filter. */
 
11699
+
 
11700
+{ "ldap_id", NULL, STRING }
 
11701
+/* SASL authentication ID for the LDAP server */
 
11702
+
 
11703
+{ "ldap_mech", NULL, STRING }
 
11704
+/* SASL mechanism for LDAP authentication */
 
11705
+
 
11706
+{ "ldap_member_attribute", NULL, STRING }
 
11707
+/* See ldap_member_method. */
 
11708
+
 
11709
+{ "ldap_member_base", "", STRING }
 
11710
+/* LDAP base dn for ldap_member_filter. */
 
11711
+
 
11712
+{ "ldap_member_filter", "(member=%D)", STRING }
 
11713
+/* Specify a filter for "ldap_member_method: filter".  
 
11714
+   See ldap_filter for more options. */ 
 
11715
+
 
11716
+{ "ldap_member_method", "attribute", STRINGLIST("attribute", "filter") }
 
11717
+/* Specify a group method.  The "attribute" method retrieves groups from 
 
11718
+   a multi-valued attribute specified in ldap_member_attribute.  
 
11719
+
 
11720
+   The "filter" method uses a filter, specified by ldap_member_filter, to find
 
11721
+   groups; ldap_member_attribute is a single-value attribute group name. */
 
11722
+
 
11723
+{ "ldap_member_scope", "sub", STRINGLIST("sub", "one", "base") }
 
11724
+/* Specify search scope for ldap_member_filter. */
 
11725
+
 
11726
+{ "ldap_password", NULL, STRING }
 
11727
+/* Password for the connection to the LDAP server (SASL and simple bind).  
 
11728
+   Do not use for anonymous simple binds */
 
11729
+
 
11730
+{ "ldap_realm", NULL, STRING }
 
11731
+/* SASL realm for LDAP authentication */
 
11732
+
 
11733
+{ "ldap_referrals", 0, SWITCH }
 
11734
+/* Specify whether or not the client should follow referrals. */
 
11735
+
 
11736
+{ "ldap_restart", 1, SWITCH }
 
11737
+/* Specify whether or not LDAP I/O operations are automatically restarted
 
11738
+   if they abort prematurely. */
 
11739
+
 
11740
+{ "ldap_sasl", 1, SWITCH }
 
11741
+/* Use SASL for LDAP binds in the LDAP PTS module. */
 
11742
+
 
11743
+{ "ldap_sasl_authc", NULL, STRING }
 
11744
+/* Depricated.  Use ldap_id */
 
11745
+
 
11746
+{ "ldap_sasl_authz", NULL, STRING }
 
11747
+/* Depricated.  Use ldap_authz */
 
11748
+
 
11749
+{ "ldap_sasl_mech", NULL, STRING }
 
11750
+/* Depricated.  Use ldap_mech */
 
11751
+
 
11752
+{ "ldap_sasl_password", NULL, STRING }
 
11753
+/* Depricated.  User ldap_password */
 
11754
+
 
11755
+{ "ldap_sasl_realm", NULL, STRING }
 
11756
+/* Depricated.  Use ldap_realm */
 
11757
+
 
11758
+{ "ldap_scope", "sub", STRINGLIST("sub", "one", "base") }
 
11759
+/* Specify search scope. */
 
11760
+
 
11761
+{ "ldap_servers", "ldap://localhost/", STRING }
 
11762
+/* Depricated.  Use ldap_uri */
 
11763
+
 
11764
+{ "ldap_size_limit", 1, INT }
 
11765
+/* Specify a number of entries for a search request to return. */
 
11766
+
 
11767
+{ "ldap_start_tls", 0, SWITCH }
 
11768
+/* Use StartTLS extended operation.  Do not use ldaps: ldap_uri when
 
11769
+   this option is enabled. */
 
11770
+
 
11771
+{ "ldap_time_limit", 5, INT }
 
11772
+/* Specify a number of seconds for a search request to complete. */
 
11773
+
 
11774
+{ "ldap_timeout", 5, INT }
 
11775
+/* Specify a number of seconds a search can take before timing out. */
 
11776
+
 
11777
+{ "ldap_tls_cacert_dir", NULL, STRING }
 
11778
+/* Path to directory with CA (Certificate Authority) certificates. */
 
11779
+
 
11780
+{ "ldap_tls_cacert_file", NULL, STRING }
 
11781
+/* File containing CA (Certificate Authority) certificate(s). */
 
11782
+
 
11783
+{ "ldap_tls_cert", NULL, STRING }
 
11784
+/* File containing the client certificate. */
 
11785
+
 
11786
+{ "ldap_tls_check_peer", 0, SWITCH }
 
11787
+/* Require and verify server certificate.  If this option is yes,
 
11788
+   you must specify ldap_tls_cacert_file or ldap_tls_cacert_dir. */
 
11789
+
 
11790
+{ "ldap_tls_ciphers", NULL, STRING }
 
11791
+/* List of SSL/TLS ciphers to allow.  The format of the string is
 
11792
+   described in ciphers(1). */
 
11793
+
 
11794
+{ "ldap_tls_key", NULL, STRING }
 
11795
+/* File containing the private client key. */
 
11796
+
 
11797
+{ "ldap_uri", NULL, STRING }
 
11798
+/* Contains a list of the URLs of all the LDAP servers when using the
 
11799
+   LDAP PTS module. */
 
11800
+
 
11801
+{ "ldap_version", 3, INT }
 
11802
+/* Specify the LDAP protocol version.  If ldap_start_tls and/or
 
11803
+   ldap_use_sasl are enabled, ldap_version will be automatiacally
 
11804
+   set to 3. */
 
11805
+
 
11806
+{ "lmtp_downcase_rcpt", 0, SWITCH }
 
11807
+/* If enabled, lmtpd will convert the recipient address to lowercase
 
11808
+   (up to a '+' character, if present). */
 
11809
+
 
11810
+{ "lmtp_over_quota_perm_failure", 0, SWITCH }
 
11811
+/* If enabled, lmtpd returns a permanent failure code when a user's
 
11812
+   mailbox is over quota.  By default, the failure is temporary,
 
11813
+   causing the MTA to queue the message and retry later. */
 
11814
+
 
11815
+{ "lmtpsocket", "{configdirectory}/socket/lmtp", STRING }
 
11816
+/* Unix domain socket that lmtpd listens on, used by deliver(8). This should
 
11817
+   match the path specified in cyrus.conf(5). */
 
11818
+
 
11819
+# xxx how does this tie into virtual domains?
 
11820
+{ "loginrealms", "", STRING }
 
11821
+/* The list of remote realms whose users may authenticate using cross-realm
 
11822
+   authentication identifiers.  Seperate each realm name by a space.  (A
 
11823
+   cross-realm identity is considered any identity returned by SASL
 
11824
+   with an "@" in it.) Note that to support multiple virtual domains
 
11825
+   on the same interface/IP, you need to list them all as loginreals.
 
11826
+   If you don't list them here, your users probably won't be able to
 
11827
+   log in. */
 
11828
+
 
11829
+{ "loginuseacl", 0, SWITCH }
 
11830
+/* If enabled, any authentication identity which has \fBa\fR rights on a
 
11831
+   user's INBOX may log in as that user. */
 
11832
+
 
11833
+{ "logtimestamps", 0, SWITCH }
 
11834
+/* Include notations in the protocol telemetry logs indicating the number of
 
11835
+   seconds since the last command or response. */
 
11836
+
 
11837
+{ "mailnotifier", NULL, STRING }
 
11838
+/* Notifyd(8) method to use for "MAIL" notifications.  If not set, "MAIL"
 
11839
+   notifications are disabled. */
 
11840
+
 
11841
+{ "maxmessagesize", 0, INT }
 
11842
+/* Maximum incoming LMTP message size.  If non-zero, lmtpd will reject
 
11843
+   messages larger than \fImaxmessagesize\fR bytes.  If set to 0, this
 
11844
+   will allow messages of any size (the default). */
 
11845
+
 
11846
+{ "mboxlist_db", "skiplist", STRINGLIST("flat", "berkeley", "berkeley-hash", "skiplist")}
 
11847
+/* The cyrusdb backend to use for the mailbox list. */
 
11848
+
 
11849
+{ "munge8bit", 1, SWITCH }
 
11850
+/* If enabled, lmtpd changes 8-bit characters to `X'. Also see reject8bit.
 
11851
+   (A proper soultion to non-ASCII characters in headers is offered by  
 
11852
+   RFC 2047 and its predecessors.) */
 
11853
+
 
11854
+# xxx badly worded
 
11855
+{ "mupdate_connections_max", 128, INT }
 
11856
+/* The max number of connections that a mupdate process will allow, this
 
11857
+   is related to the number of file descriptors in the mupdate process.
 
11858
+   Beyond this number connections will be immedately issued a BYE response. */
 
11859
+
 
11860
+{ "mupdate_authname", NULL, STRING }
 
11861
+/* The SASL username (Authentication Name) to use when authenticating to the
 
11862
+   mupdate server (if needed). */
 
11863
+
 
11864
+{ "mupdate_password", NULL, STRING }
 
11865
+/* The SASL password (if needed) to use when authenticating to the
 
11866
+   mupdate server. */
 
11867
+
 
11868
+{ "mupdate_port", 3905, INT }
 
11869
+/* The port of the mupdate server for the Cyrus Murder */
 
11870
+
 
11871
+{ "mupdate_realm", NULL, STRING }
 
11872
+/* The SASL realm (if needed) to use when authenticating to the mupdate
 
11873
+   server. */
 
11874
+
 
11875
+{ "mupdate_retry_delay", 20, INT }
 
11876
+/* The base time to wait between connection retries to the mupdate server. */
 
11877
+
 
11878
+{ "mupdate_server", NULL, STRING }
 
11879
+/* The mupdate server for the Cyrus Murder */
 
11880
+
 
11881
+{ "mupdate_workers_start", 5, INT }
 
11882
+/* The number of mupdate worker threads to start */
 
11883
+
 
11884
+{ "mupdate_workers_minspare", 2, INT }
 
11885
+/* The minimum number of idle mupdate worker threads */
 
11886
+
 
11887
+{ "mupdate_workers_maxspare", 10, INT }
 
11888
+/* The maximum number of idle mupdate worker threads */
 
11889
+
 
11890
+{ "mupdate_workers_max", 50, INT }
 
11891
+/* The maximum number of mupdate worker threads (overall) */
 
11892
+
 
11893
+{ "mupdate_username", "", STRING }
 
11894
+/* The SASL username (Authorization Name) to use when authenticating to
 
11895
+   the mupdate server */
 
11896
+
 
11897
+{ "netscapeurl", "http://asg.web.cmu.edu/cyrus/imapd/netscape-admin.html", STRING }
 
11898
+/* If enabled at compile time, this specifies a URL to reply when
 
11899
+   Netscape asks the server where the mail administration HTTP server
 
11900
+   is.  The default is a site at CMU with a hopefully informative
 
11901
+   message; administrators should set this to a local resource with
 
11902
+   some information of greater use. */
 
11903
+
 
11904
+{ "newsmaster", "news", STRING }
 
11905
+/* Userid that is used for checking access controls when executing
 
11906
+   Usenet control messages.  For instance, to allow articles to be
 
11907
+   automatically deleted by cancel messages, give the "news" user
 
11908
+   the 'd' right on the desired mailboxes.  To allow newsgroups to be 
 
11909
+   automatically created, deleted and renamed by the corresponding
 
11910
+   control messages, give the "news" user the 'c' right on the desired
 
11911
+   mailbox hierarchies. */
 
11912
+
 
11913
+{ "newspeer", NULL, STRING }
 
11914
+/* A list of whitespace-separated news server specifications to which
 
11915
+   articles should be fed.  Each server specification is a string of
 
11916
+   the form [user[:pass]@]host[:port][/wildmat] where 'host' is the fully
 
11917
+   qualified hostname of the server, 'port' is the port on which the
 
11918
+   server is listening, 'user' and 'pass' are the authentication
 
11919
+   credentials and 'wildmat' is a pattern that specifies which groups
 
11920
+   should be fed.  If no 'port' is specified, port 119 is used.  If
 
11921
+   no 'wildmat' is specified, all groups are fed.  If 'user' is specified
 
11922
+   (even if empty), then the NNTP POST command will be used to feed
 
11923
+   the article to the server, otherwise the IHAVE command will be
 
11924
+   used.
 
11925
+.br
 
11926
+.sp
 
11927
+   A '@' may be used in place of '!' in the wildmat to prevent feeding
 
11928
+   articles cross-posted to the given group, otherwise cross-posted
 
11929
+   articles are fed if any part of the wildmat matches.  For example,
 
11930
+   the string "peer.example.com:*,!control.*,@local.*" would feed all
 
11931
+   groups except control messages and local groups to
 
11932
+   peer.example.com.  In the case of cross-posting to local groups,
 
11933
+   these articles would not be fed. */
 
11934
+
 
11935
+{ "newspostuser", NULL, STRING }
 
11936
+/* Userid used to deliver usenet articles to newsgroup folders
 
11937
+   (usually via lmtp2nntp).  For example, if set to "post", email sent
 
11938
+   to "post+comp.mail.imap" would be delivered to the "comp.mail.imap"
 
11939
+   folder.
 
11940
+.br
 
11941
+.sp
 
11942
+   When set, the Cyrus NNTP server will add a \fITo:\fR header to each
 
11943
+   incoming usenet article.  This \fITo:\fR header will contain email
 
11944
+   delivery addresses corresponding to each newsgroup in the
 
11945
+   \fINewsgroups:\fR header.  By default, a \fITo:\fR header is not
 
11946
+   added to usenet articles. */
 
11947
+
 
11948
+{ "newsprefix", NULL, STRING }
 
11949
+/* Prefix to be prepended to newsgroup names to make the corresponding
 
11950
+   IMAP mailbox names. */
 
11951
+
 
11952
+{ "notifysocket", "{configdirectory}/socket/notify", STRING }
 
11953
+/* Unix domain socket that the mail notification daemon listens on. */
 
11954
+
 
11955
+# Commented out - there's no such thing as "partition-name", but we need
 
11956
+# this for the man page
 
11957
+# { "partition-name", NULL, STRING }
 
11958
+/* The pathname of the partition \fIname\fR.  At least one field, for the
 
11959
+   partition named in the \fBdefaultpartition\fR option, is required.
 
11960
+   For example, if the value of the \fBdefaultpartion\fR option is
 
11961
+   \fBdefault\fR, then the \fBpartition-default\fR field is required. */
 
11962
+
 
11963
+{ "plaintextloginpause", 0, INT }
 
11964
+/* Number of seconds to pause after a successful plaintext login.  For
 
11965
+   systems that support strong authentication, this permits users to  
 
11966
+   perceive a cost of using plaintext passwords.  (This does not
 
11967
+   affect the use of PLAIN in SASL authentications.) */
 
11968
+
 
11969
+{ "plaintextloginalert", NULL, STRING }
 
11970
+/* Message to send to client after a successful plaintext login. */
 
11971
+
 
11972
+{ "popexpiretime", -1, INT }
 
11973
+/* The number of days advertised as being the minimum a message may be
 
11974
+   left on the POP server before it is deleted (via the CAPA command,
 
11975
+   defined in the POP3 Extension Mechanism, which some clients may
 
11976
+   support).  "NEVER", the default, may be specified with a negative
 
11977
+   number.  The Cyrus POP3 server never deletes mail, no matter what  
 
11978
+   the value of this parameter is.  However, if a site implements a 
 
11979
+   less liberal policy, it needs to change this parameter
 
11980
+   accordingly. */
 
11981
+
 
11982
+{ "popminpoll", 0, INT }
 
11983
+/* Set the minimum amount of time the server forces users to wait
 
11984
+   between successive POP logins, in minutes. */ 
 
11985
+
 
11986
+{ "poppollpadding", 1, INT }
 
11987
+/* Create a softer minimum poll restriction.  Allows \fIpoppollpadding\fR
 
11988
+   connections before the minpoll restriction is triggered.  Additionally,
 
11989
+   one padding entry is recovered every \fIpopminpoll\fR minutes.
 
11990
+   This allows for the occasional polling rate faster than popminpoll, 
 
11991
+   (i.e. for clients that require a send/recieve to send mail) but still 
 
11992
+   enforces the rate long-term.  Default is 1 (disabled).
 
11993
+.br
 
11994
+.sp
 
11995
+   The easiest way to think of it is a queue of past connections, with one
 
11996
+   slot being filled for every connection, and one slot being cleared 
 
11997
+   every \fIpopminpoll\fR minutes. When the queue is full, the user
 
11998
+   will not be able to check mail again until a slot is cleared.  If the 
 
11999
+   user waits a sufficent amount of time, they will get back many or all
 
12000
+   of the slots. */
 
12001
+
 
12002
+{ "poptimeout", 10, INT }
 
12003
+/* Set the length of the POP server's inactivity autologout timer,    
 
12004
+   in minutes.  The minimum value is 10, the default. */
 
12005
+
 
12006
+{ "popuseacl", 0, SWITCH }
 
12007
+/* Enforce IMAP ACLs in the pop server.  Due to the nature of the POP3
 
12008
+   protocol, the only rights which are used by the pop server are 'r'
 
12009
+   and 'd' for the owner of the mailbox.  The 'r' right allows the
 
12010
+   user to open the mailbox and list/retrieve messages.  The 'd' right
 
12011
+   allows the user to delete messages. */
 
12012
+
 
12013
+{ "postmaster", "postmaster", STRING }
 
12014
+/* Username that is used as the 'From' address in rejection MDNs produced
 
12015
+   by sieve. */
 
12016
+   
 
12017
+{ "postspec", NULL, STRING }
 
12018
+
 
12019
+{ "postuser", "", STRING }
 
12020
+/* Userid used to deliver messages to shared folders.  For example, if
 
12021
+   set to "bb", email sent to "bb+shared.blah" would be delivered to
 
12022
+   the "shared.blah" folder.  By default, an email address of
 
12023
+   "+shared.blah" would be used. */ 
 
12024
+
 
12025
+{ "proxy_authname", "proxy", STRING }
 
12026
+/* The authentication name to use when authenticating to a backend server
 
12027
+   in the Cyrus Murder. */
 
12028
+
 
12029
+{ "proxy_password", NULL, STRING }
 
12030
+/* The default password to use when authenticating to a backend server
 
12031
+   in the Cyrus Murder.  May be overridden on a host-specific basis using
 
12032
+   the hostname_password option. */
 
12033
+
 
12034
+{ "proxy_realm", NULL, STRING }
 
12035
+/* The authentication realm to use when authenticating to a backend server
 
12036
+   in the Cyrus Murder */
 
12037
+
 
12038
+{ "proxyd_allow_status_referral", 0, SWITCH }
 
12039
+/* Set to true to allow proxyd to issue referrals to clients that support it
 
12040
+   when answering the STATUS command.  This is disabled by default since
 
12041
+   some clients issue many STATUS commands in a row, and do not cache the
 
12042
+   connections that these referrals would cause, thus resulting in a higher
 
12043
+   authentication load on the respective backend server. */
 
12044
+
 
12045
+{ "proxyservers", NULL, STRING }
 
12046
+/* A list of users and groups that are allowed to proxy for other
 
12047
+   users, seperated by spaces.  Any user listed in this will be
 
12048
+   allowed to login for any other user: use with caution. */ 
 
12049
+
 
12050
+{ "pts_module", "afskrb", STRINGLIST("afskrb", "ldap") }
 
12051
+/* The PTS module to use. */
 
12052
+
 
12053
+{ "ptloader_sock", NULL, STRING }
 
12054
+/* Unix domain socket that ptloader listens on.
 
12055
+   (defaults to configdir/ptclient/ptsock) */
 
12056
+
 
12057
+{ "ptscache_db", "berkeley", STRINGLIST("berkeley", "berkeley-hash", "skiplist")}
 
12058
+/* The cyrusdb backend to use for the pts cache. */
 
12059
+
 
12060
+{ "ptscache_timeout", 10800, INT }
 
12061
+/* The timeout (in seconds) for the PTS cache database when using the
 
12062
+   auth_krb_pts authorization method (default: 3 hours). */
 
12063
+
 
12064
+{ "ptskrb5_convert524", 1, SWITCH }
 
12065
+/* When using the AFSKRB ptloader module with Kerberos 5 canonicalization,
 
12066
+   do the final 524 conversion to get a n AFS style name (using '.' instead
 
12067
+   of '/', and using short names */
 
12068
+
 
12069
+{ "ptskrb5_strip_default_realm", 1, SWITCH }
 
12070
+/* When using the AFSKRB ptloader module with Kerberos 5 canonicalization,
 
12071
+   strip the default realm from the userid (this does not affect the stripping
 
12072
+   of realms specified by the afspts_localrealms option) */
 
12073
+
 
12074
+{ "quota_db", "quotalegacy", STRINGLIST("flat", "berkeley", "berkeley-hash", "skiplist", "quotalegacy")}
 
12075
+/* The cyrusdb backend to use for quotas. */
 
12076
+
 
12077
+{ "quotawarn", 90, INT }
 
12078
+/* The percent of quota utilization over which the server generates
 
12079
+   warnings. */
 
12080
+
 
12081
+{ "quotawarnkb", 0, INT }
 
12082
+/* The maximum amount of free space (in kB) in which to give a quota
 
12083
+   warning (if this value is 0, or if the quota is smaller than this
 
12084
+   amount, than warnings are always given). */
 
12085
+
 
12086
+{ "reject8bit", 0, SWITCH }
 
12087
+/* If enabled, lmtpd rejects messages with 8-bit characters in the
 
12088
+   headers. Also see munge8bit, which is only applied if reject8bit is
 
12089
+   not activated. (A proper soultion to non-ASCII characters in headers
 
12090
+   is offered by RFC 2047 and its predecessors.) */
 
12091
+
 
12092
+{ "rfc2046_strict", 0, SWITCH }
 
12093
+/* If enabled, imapd will be strict (per RFC 2046) when matching MIME
 
12094
+   boundary strings.  This means that boundaries containing other
 
12095
+   boundaries as substrings will be treated as identical.  Since
 
12096
+   enabling this option will break some messages created by Eudora 5.1
 
12097
+   (and earlier), it is recommended that it be left disabled unless
 
12098
+   there is good reason to do otherwise. */
 
12099
+
 
12100
+{ "rfc3028_strict", 1, SWITCH }
 
12101
+/* If enabled, Sieve will be strict (per RFC 3028) with regards to
 
12102
+   which headers are allowed to be used in address and envelope tests.
 
12103
+   This means that only those headers which are defined to contain addresses
 
12104
+   will be allowed in address tests and only "to" and "from" will be
 
12105
+   allowed in envelope tests.  When disabled, ANY grammatically correct header
 
12106
+   will be allowed. */
 
12107
+
 
12108
+# Commented out - used by libsasl
 
12109
+# { "sasl_auto_transition", 0, SWITCH }
 
12110
+/* If enabled, the SASL library will automatically create authentication
 
12111
+   secrets when given a plaintext password.  See the SASL documentation. */
 
12112
+
 
12113
+{ "sasl_maximum_layer", 256, INT }
 
12114
+/* Maximum SSF (security strength factor) that the server will allow a
 
12115
+   client to negotiate. */
 
12116
+
 
12117
+{ "sasl_minimum_layer", 0, INT }
 
12118
+/* The minimum SSF that the server will allow a client to negotiate.
 
12119
+   A value of 1 requires integrity protection; any higher value  
 
12120
+   requires some amount of encryption. */
 
12121
+
 
12122
+# Commented out - used by libsasl
 
12123
+# { "sasl_option", 0, STRING }
 
12124
+/* Any SASL option can be set by preceeding it with "sasl_".  This
 
12125
+   file overrides the SASL configuration file. */
 
12126
+
 
12127
+# Commented out - used by libsasl
 
12128
+# { "sasl_pwcheck_method", NULL, STRING }
 
12129
+/* The mechanism used by the server to verify plaintext passwords. 
 
12130
+   Possible values include "auxprop", "saslauthd", and "pwcheck". */
 
12131
+
 
12132
+{ "seenstate_db", "skiplist", STRINGLIST("flat", "berkeley", "berkeley-hash", "skiplist")}
 
12133
+/* The cyrusdb backend to use for the seen state. */
 
12134
+
 
12135
+{ "sendmail", "/usr/lib/sendmail", STRING }
 
12136
+/* The pathname of the sendmail executable.  Sieve invokes sendmail
 
12137
+   for sending rejections, redirects and vacation responses. */
 
12138
+
 
12139
+{ "servername", NULL, STRING }
 
12140
+/* This is the hostname visible in the greeting messages of the POP,
 
12141
+   IMAP and LMTP daemons. If it is unset, then the result returned
 
12142
+   from gethostname(2) is used. */
 
12143
+   
 
12144
+{ "sharedprefix", "Shared Folders", STRING }
 
12145
+/* If using the alternate IMAP namespace, the prefix for the shared
 
12146
+   namespace.  The hierarchy delimiter will be automatically appended. */
 
12147
+
 
12148
+{ "sieve_maxscriptsize", 32, INT }
 
12149
+/* Maximum size (in kilobytes) any sieve script can be, enforced at
 
12150
+   submission by timsieved(8). */
 
12151
+
 
12152
+{ "sieve_maxscripts", 5, INT }
 
12153
+/* Maximum number of sieve scripts any user may have, enforced at
 
12154
+   submission by timsieved(8). */
 
12155
+   
 
12156
+{ "sievedir", "/usr/sieve", STRING }
 
12157
+/* If sieveusehomedir is false, this directory is searched for Sieve
 
12158
+   scripts. */
 
12159
+
 
12160
+{ "sievenotifier", NULL, STRING }
 
12161
+/* Notifyd(8) method to use for "SIEVE" notifications.  If not set, "SIEVE"
 
12162
+   notifications are disabled.
 
12163
+.PP
 
12164
+   This method is only used when no method is specified in the script. */
 
12165
+
 
12166
+{ "sieveusehomedir", 0, SWITCH }
 
12167
+/* If enabled, lmtpd will look for Sieve scripts in user's home
 
12168
+   directories: ~user/.sieve. */
 
12169
+
 
12170
+{ "singleinstancestore", 1, SWITCH }
 
12171
+/* If enabled, imapd, lmtpd and nntpd attempt to only write one copy
 
12172
+   of a message per partition and create hard links, resulting in a
 
12173
+   potentially large disk savings. */
 
12174
+
 
12175
+{ "skiplist_unsafe", 0, SWITCH }
 
12176
+/* If enabled, this option forces the skiplist cyrusdb backend to
 
12177
+   not sync writes to the disk.  Enabling this option is NOT RECOMMENDED. */
 
12178
+
 
12179
+{ "soft_noauth", 1, SWITCH }
 
12180
+/* If enabled, lmtpd returns temporary failures if the client does not
 
12181
+   successfully authenticate.  Otherwise lmtpd returns permanant failures
 
12182
+   (causing the mail to bounce immediately). */
 
12183
+
 
12184
+{ "srvtab", "", STRING }
 
12185
+/* The pathname of \fIsrvtab\fR file containing the server's private
 
12186
+   key.  This option is passed to the SASL library and overrides its
 
12187
+   default setting. */
 
12188
+
 
12189
+{ "subscription_db", "flat", STRINGLIST("flat", "berkeley", "berkeley-hash", "skiplist")}
 
12190
+/* The cyrusdb backend to use for the subscriptions list. */
 
12191
+
 
12192
+{ "syslog_prefix", NULL, STRING }
 
12193
+/* String to be appended to the process name in syslog entries. */
 
12194
+
 
12195
+{ "temp_path", "/tmp", STRING }
 
12196
+/* The pathname to store temporary files in */
 
12197
+
 
12198
+{ "timeout", 30, INT }   
 
12199
+/* The length of the IMAP server's inactivity autologout timer,       
 
12200
+   in minutes.  The minimum value is 30, the default. */
 
12201
+
 
12202
+{ "tls_ca_file", NULL, STRING }
 
12203
+/* File containing one or more Certificate Authority (CA) certificates. */
 
12204
+
 
12205
+{ "tls_ca_path", NULL, STRING }
 
12206
+/* Path to directory with certificates of CAs.  This directory must
 
12207
+   have filenames with the hashed value of the certificate (see
 
12208
+   openssl(XXX)). */
 
12209
+
 
12210
+{ "tlscache_db", "berkeley-nosync", STRINGLIST("berkeley", "berkeley-nosync", "berkeley-hash", "berkeley-hash-nosync", "skiplist")}
 
12211
+/* The cyrusdb backend to use for the TLS cache. */
 
12212
+
 
12213
+{ "tls_cert_file", NULL, STRING }
 
12214
+/* File containing the certificate presented for server authentication
 
12215
+   during STARTTLS.  A value of "disabled" will disable SSL/TLS. */
 
12216
+
 
12217
+{ "tls_cipher_list", "DEFAULT", STRING }
 
12218
+/* The list of SSL/TLS ciphers to allow.  The format of the string is
 
12219
+   described in ciphers(1). */
 
12220
+
 
12221
+{ "tls_key_file", NULL, STRING }
 
12222
+/* File containing the private key belonging to the server
 
12223
+   certificate.  A value of "disabled" will disable SSL/TLS. */
 
12224
+
 
12225
+{ "tls_require_cert", 0, SWITCH }
 
12226
+/* Require a client certificate for ALL services (imap, pop3, lmtp, sieve). */
 
12227
+
 
12228
+{ "tls_session_timeout", 1440, INT }
 
12229
+/* The length of time (in minutes) that a TLS session will be cached
 
12230
+   for later reuse.  The maximum value is 1440 (24 hours), the
 
12231
+   default.  A value of 0 will disable session caching. */
 
12232
+
 
12233
+{ "umask", "077", STRING }
 
12234
+/* The umask value used by various Cyrus IMAP programs. */
 
12235
+
 
12236
+{ "username_tolower", 1, SWITCH }
 
12237
+/* Convert usernames to all lowercase before login/authenticate.  This
 
12238
+   is useful with authentication backends which ignore case during
 
12239
+   username lookups (such as LDAP).  */
 
12240
+
 
12241
+{ "userprefix", "Other Users", STRING }
 
12242
+/* If using the alternate IMAP namespace, the prefix for the other users
 
12243
+   namespace.  The hierarchy delimiter will be automatically appended. */
 
12244
+
 
12245
+# xxx badly worded
 
12246
+{ "unix_group_enable", 1, SWITCH }
 
12247
+/* Should we look up groups when using auth_unix (disable this if you are
 
12248
+   not using groups in ACLs for your IMAP server, and you are using auth_unix
 
12249
+   with a backend (such as LDAP) that can make getgrent() calls very
 
12250
+   slow) */
 
12251
+
 
12252
+{ "unixhierarchysep", 0, SWITCH }
 
12253
+/* Use the UNIX separator character '/' for delimiting levels of
 
12254
+   mailbox hierarchy.  The default is to use the netnews separator
 
12255
+   character '.'. */
 
12256
+
 
12257
+{ "virtdomains", "off", ENUM("off", "userid", "on") }
 
12258
+/* Enable virtual domain support.  If enabled, the user's domain will
 
12259
+   be determined by splitting a fully qualified userid at the last '@'
 
12260
+   or '%' symbol.  If the userid is unqualified, and the virtdomains
 
12261
+   option is set to "on", then the domain will be determined by doing
 
12262
+   a reverse lookup on the IP address of the incoming network
 
12263
+   interface, otherwise the user is assumed to be in the default
 
12264
+   domain (if set). */
 
12265
+
 
12266
+/*
 
12267
+.SH SEE ALSO
 
12268
+.PP
 
12269
+\fBimapd(8)\fR, \fBpop3d(8)\fR, \fBnntpd(8)\fR, \fBlmtpd(8)\fR,
 
12270
+\fBtimsieved(8)\fR, \fBidled(8)\fR, \fBnotifyd(8)\fR,
 
12271
+\fBdeliver(8)\fR, \fBmaster(8)\fR, \fBciphers(1)\fR
 
12272
+*/