~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-12-07 17:31:51 UTC
  • Revision ID: james.westby@ubuntu.com-20061207173151-u34z5dafs5nh9sat
Tags: 2.2.13-9ubuntu1
* Merge with Debian unstable; remaining changes:
  - Build using DB4.3.

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.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
 
8
diff -urNad cyrus-imapd-2.2.13/configure.in /tmp/dpep.ikKBvZ/cyrus-imapd-2.2.13/configure.in
 
9
--- cyrus-imapd-2.2.13/configure.in     2006-09-14 22:52:27.000000000 +0200
 
10
+++ /tmp/dpep.ikKBvZ/cyrus-imapd-2.2.13/configure.in    2006-09-14 22:52:28.341085956 +0200
11
11
@@ -974,6 +974,19 @@
12
12
 SNMP_SUBDIRS=""
13
13
 AC_SUBST(SNMP_SUBDIRS)
28
28
 CMU_LIBWRAP
29
29
 CMU_UCDSNMP
30
30
 
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
 
31
diff -urNad cyrus-imapd-2.2.13/imap/Makefile.in /tmp/dpep.ikKBvZ/cyrus-imapd-2.2.13/imap/Makefile.in
 
32
--- cyrus-imapd-2.2.13/imap/Makefile.in 2006-09-14 22:52:27.000000000 +0200
 
33
+++ /tmp/dpep.ikKBvZ/cyrus-imapd-2.2.13/imap/Makefile.in        2006-09-14 22:52:28.344085662 +0200
1261
34
@@ -69,6 +69,7 @@
1262
35
 SIEVE_LIBS = @SIEVE_LIBS@
1263
36
 IMAP_COM_ERR_LIBS = @IMAP_COM_ERR_LIBS@
1296
69
 
1297
70
 nntpd: nntpd.o backend.o index.o smtpclient.o spool.o tls.o \
1298
71
         mutex_fake.o nntp_err.o libimap.a $(DEPLIBS) $(SERVICE)
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
 
72
diff -urNad cyrus-imapd-2.2.13/imap/imapd.c /tmp/dpep.ikKBvZ/cyrus-imapd-2.2.13/imap/imapd.c
 
73
--- cyrus-imapd-2.2.13/imap/imapd.c     2006-09-14 22:52:27.000000000 +0200
 
74
+++ /tmp/dpep.ikKBvZ/cyrus-imapd-2.2.13/imap/imapd.c    2006-09-14 22:52:28.348085270 +0200
1660
75
@@ -138,6 +138,18 @@
1661
76
     1, 1, &imapd_authstate, &imapd_userisadmin, &imapd_userisproxyadmin
1662
77
 };
1775
190
 /*
1776
191
  * Top-level command loop parsing
1777
192
  */
1778
 
@@ -1848,6 +1924,11 @@
 
193
@@ -1851,6 +1927,11 @@
1779
194
 
1780
195
     prot_printf(imapd_out, "%s OK %s\r\n", tag, reply);
1781
196
 
1787
202
     /* Create telemetry log */
1788
203
     imapd_logfd = telemetry_log(imapd_userid, imapd_in, imapd_out, 0);
1789
204
 
1790
 
@@ -1994,6 +2075,11 @@
 
205
@@ -1999,6 +2080,11 @@
1791
206
     prot_setsasl(imapd_in,  imapd_saslconn);
1792
207
     prot_setsasl(imapd_out, imapd_saslconn);
1793
208
 
1799
214
     /* Create telemetry log */
1800
215
     imapd_logfd = telemetry_log(imapd_userid, imapd_in, imapd_out, 0);
1801
216
 
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
 
217
diff -urNad cyrus-imapd-2.2.13/imap/pop3d.c /tmp/dpep.ikKBvZ/cyrus-imapd-2.2.13/imap/pop3d.c
 
218
--- cyrus-imapd-2.2.13/imap/pop3d.c     2006-09-14 22:52:27.000000000 +0200
 
219
+++ /tmp/dpep.ikKBvZ/cyrus-imapd-2.2.13/imap/pop3d.c    2006-09-14 22:52:28.360084093 +0200
9433
220
@@ -100,6 +100,10 @@
9434
221
 extern int opterr;
9435
222
 
9452
239
     if (kflag) kpop();
9453
240
 
9454
241
     /* we were connected on pop3s port so we should do 
9455
 
@@ -1450,6 +1458,21 @@
 
242
@@ -1456,6 +1464,21 @@
9456
243
        popd_mailbox = &mboxstruct;
9457
244
        proc_register("pop3d", popd_clienthost, popd_userid,
9458
245
                      popd_mailbox->name);
9474
261
     }
9475
262
 
9476
263
     /* Create telemetry log */
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
 
264
diff -urNad cyrus-imapd-2.2.13/imap/version.c /tmp/dpep.ikKBvZ/cyrus-imapd-2.2.13/imap/version.c
 
265
--- cyrus-imapd-2.2.13/imap/version.c   2006-09-14 22:40:12.000000000 +0200
 
266
+++ /tmp/dpep.ikKBvZ/cyrus-imapd-2.2.13/imap/version.c  2006-09-14 22:52:28.363083799 +0200
11160
267
@@ -151,6 +151,10 @@
11161
268
     snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
11162
269
             "; %s", SIEVE_VERSION);
11168
275
 #ifdef HAVE_LIBWRAP
11169
276
     snprintf(env_buf + strlen(env_buf), MAXIDVALUELEN - strlen(env_buf),
11170
277
             "; TCP Wrappers");
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
 
278
diff -urNad cyrus-imapd-2.2.13/lib/imapoptions /tmp/dpep.ikKBvZ/cyrus-imapd-2.2.13/lib/imapoptions
 
279
--- cyrus-imapd-2.2.13/lib/imapoptions  2006-09-14 22:52:27.000000000 +0200
 
280
+++ /tmp/dpep.ikKBvZ/cyrus-imapd-2.2.13/lib/imapoptions 2006-09-14 22:52:28.364083701 +0200
11359
281
@@ -199,6 +199,14 @@
11360
282
 { "deleteright", "c", STRING }
11361
283
 /* The right that a user needs to delete a mailbox. */
11371
293
 { "duplicate_db", "berkeley-nosync", STRINGLIST("berkeley", "berkeley-nosync", "berkeley-hash", "berkeley-hash-nosync", "skiplist")}
11372
294
 /* The cyrusdb backend to use for the duplicate delivery suppression
11373
295
    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
 
+*/