[SVN] r741 - /trunk/cyrus-imapd-2.2.13/debian/patches/24-configurable-referrals.dpatch

debian at incase.de debian at incase.de
Fri Jun 22 16:19:13 UTC 2007


Author: astronut
Date: Fri Jun 22 18:19:12 2007
New Revision: 741

URL: https://mail.incase.de/viewcvs?rev=3D741&root=3Dcyrus22&view=3Drev
Log:
Fix patch

Modified:
    trunk/cyrus-imapd-2.2.13/debian/patches/24-configurable-referrals.dpatch

Modified: trunk/cyrus-imapd-2.2.13/debian/patches/24-configurable-referrals=
.dpatch
URL: https://mail.incase.de/viewcvs/trunk/cyrus-imapd-2.2.13/debian/patches=
/24-configurable-referrals.dpatch?rev=3D741&root=3Dcyrus22&r1=3D740&r2=3D74=
1&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- trunk/cyrus-imapd-2.2.13/debian/patches/24-configurable-referrals.dpatc=
h (original)
+++ trunk/cyrus-imapd-2.2.13/debian/patches/24-configurable-referrals.dpatc=
h Fri Jun 22 18:19:12 2007
@@ -2,13 +2,12 @@
 ## 24-configurable-referrals.dpatch by Benjamin Seidenberg <benjamin at debia=
n.org>
 ##
 ## All lines beginning with `## DP:' are a description of the patch.
-## DP: Adds a config option to disable referrals from frontends to backends
-## DP: Contributed by Andrew Morgan <morgan at orst.edu> =

+## DP: No description.
 =

 @DPATCH@
 diff -urNad cyrus-imapd-2.2.13~/imap/proxyd.c cyrus-imapd-2.2.13/imap/prox=
yd.c
---- cyrus-imapd-2.2.13~/imap/proxyd.c	2007-06-22 16:47:44.000000000 +0100
-+++ cyrus-imapd-2.2.13/imap/proxyd.c	2007-06-22 16:48:05.000000000 +0100
+--- cyrus-imapd-2.2.13~/imap/proxyd.c	2007-06-22 17:16:23.000000000 +0100
++++ cyrus-imapd-2.2.13/imap/proxyd.c	2007-06-22 17:16:52.000000000 +0100
 @@ -1161,7 +1161,7 @@
      =

      /* Cleanup Globals */
@@ -29,5223 +28,9 @@
      if (config_getint(IMAPOPT_IMAPIDLEPOLL) > 0) {
  	prot_printf(proxyd_out, " IDLE");
      }
-diff -urNad cyrus-imapd-2.2.13~/imap/proxyd.c.orig cyrus-imapd-2.2.13/imap=
/proxyd.c.orig
---- cyrus-imapd-2.2.13~/imap/proxyd.c.orig	1970-01-01 01:00:00.000000000 +=
0100
-+++ cyrus-imapd-2.2.13/imap/proxyd.c.orig	2007-06-22 16:47:44.000000000 +0=
100
-@@ -0,0 +1,5210 @@
-+/* proxyd.c -- IMAP server proxy for Cyrus Murder
-+ *
-+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserv=
ed.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ *
-+ * 1. Redistributions of source code must retain the above copyright
-+ *    notice, this list of conditions and the following disclaimer. =

-+ *
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ *    notice, this list of conditions and the following disclaimer in
-+ *    the documentation and/or other materials provided with the
-+ *    distribution.
-+ *
-+ * 3. The name "Carnegie Mellon University" must not be used to
-+ *    endorse or promote products derived from this software without
-+ *    prior written permission. For permission or any other legal
-+ *    details, please contact  =

-+ *      Office of Technology Transfer
-+ *      Carnegie Mellon University
-+ *      5000 Forbes Avenue
-+ *      Pittsburgh, PA  15213-3890
-+ *      (412) 268-4387, fax: (412) 268-7395
-+ *      tech-transfer at andrew.cmu.edu
-+ *
-+ * 4. Redistributions of any form whatsoever must retain the following
-+ *    acknowledgment:
-+ *    "This product includes software developed by Computing Services
-+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
-+ *
-+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
-+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
-+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
-+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
-+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+/* $Id: proxyd.c,v 1.199 2006/02/07 20:57:27 murch Exp $ */
-+
-+#include <config.h>
-+
-+#include <stdio.h>
-+#include <string.h>
-+#include <signal.h>
-+#ifdef HAVE_UNISTD_H
-+#include <unistd.h>
-+#endif
-+#include <fcntl.h>
-+#include <sys/types.h>
-+#include <sys/param.h>
-+#include <sys/stat.h>
-+#include <sys/un.h>
-+#include <syslog.h>
-+#include <netdb.h>
-+#include <sys/socket.h>
-+#include <netinet/in.h>
-+#include <arpa/inet.h>
-+#include <assert.h>
-+#include <ctype.h>
-+#include <errno.h>
-+
-+#include <sasl/sasl.h>
-+#include <sasl/saslutil.h>
-+
-+#include "prot.h"
-+
-+#include "acl.h"
-+#include "annotate.h"
-+#include "util.h"
-+#include "auth.h"
-+#include "map.h"
-+#include "global.h"
-+#include "tls.h"
-+#include "version.h"
-+#include "charset.h"
-+#include "imparse.h"
-+#include "iptostring.h"
-+#include "exitcodes.h"
-+#include "imap_err.h"
-+#include "mboxname.h"
-+#include "mailbox.h"
-+#include "mupdate-client.h"
-+#include "xmalloc.h"
-+#include "mboxlist.h"
-+#include "imapurl.h"
-+#include "pushstats.h"
-+#include "telemetry.h"
-+#include "backend.h"
-+
-+/* config.c stuff */
-+const int config_need_data =3D 0;
-+
-+/* PROXY STUFF */
-+/* we want a list of our outgoing connections here and which one we're
-+   currently piping */
-+#define IDLE_TIMEOUT (5 * 60)
-+
-+static const int ultraparanoid =3D 1; /* should we kick after every opera=
tion? */
-+static unsigned int proxyd_cmdcnt;
-+
-+static int referral_kick =3D 0; /* kick after next command recieved, for
-+				 referrals that are likely to change the
-+				 mailbox list */
-+
-+/* all subscription commands go to the backend server containing the
-+   user's inbox */
-+struct backend *backend_inbox =3D NULL;
-+
-+/* the current server most commands go to */
-+struct backend *backend_current =3D NULL;
-+
-+/* our cached connections */
-+struct backend **backend_cached =3D NULL;
-+
-+/* are we doing virtdomains with multiple IPs? */
-+static int disable_referrals;
-+
-+/* has the client issued an RLIST or RLSUB? */
-+static int supports_referrals;
-+
-+
-+/* -------- from imapd ---------- */
-+
-+extern int optind;
-+extern char *optarg;
-+
-+/* global state */
-+static char shutdownfilename[1024];
-+static int imaps =3D 0;
-+static sasl_ssf_t extprops_ssf =3D 0;
-+static nosaslpasswdcheck =3D 0;
-+
-+/* per-user session state */
-+struct protstream *proxyd_out =3D NULL;
-+struct protstream *proxyd_in =3D NULL;
-+static char proxyd_clienthost[NI_MAXHOST*2+1] =3D "[local]";
-+static int proxyd_logfd =3D -1;
-+time_t proxyd_logtime;
-+char *proxyd_userid =3D NULL;
-+static char *proxyd_magicplus =3D NULL;
-+struct auth_state *proxyd_authstate =3D 0;
-+int proxyd_userisadmin;
-+sasl_conn_t *proxyd_saslconn; /* the sasl connection context to the clien=
t */
-+int proxyd_starttls_done =3D 0; /* have we done a successful starttls yet=
? */
-+const char *plaintextloginalert =3D NULL;
-+#ifdef HAVE_SSL
-+static SSL *tls_conn;
-+#endif /* HAVE_SSL */
-+
-+/* the sasl proxy policy context */
-+static struct proxy_context proxyd_proxyctx =3D {
-+    1, 1, &proxyd_authstate, &proxyd_userisadmin, NULL
-+};
-+
-+/* current namespace */
-+static struct namespace proxyd_namespace;
-+
-+void motd_file(int fd);
-+void shut_down(int code);
-+void fatal(const char *s, int code);
-+
-+void proxyd_downserver(struct backend *s);
-+
-+void cmdloop(void);
-+void cmd_login(char *tag, char *user);
-+void cmd_authenticate(char *tag, char *authtype, char *resp);
-+void cmd_noop(char *tag, char *cmd);
-+void cmd_capability(char *tag);
-+void cmd_append(char *tag, char *name);
-+void cmd_select(char *tag, char *cmd, char *name);
-+void cmd_close(char *tag);
-+void cmd_fetch(char *tag, char *sequence, int usinguid);
-+void cmd_partial(char *tag, char *msgno, char *data,
-+		 char *start, char *count);
-+void cmd_store(char *tag, char *sequence, char *operation, int usinguid);
-+void cmd_search(char *tag, int usinguid);
-+void cmd_sort(char *tag, int usinguid);
-+void cmd_thread(char *tag, int usinguid);
-+void cmd_copy(char *tag, char *sequence, char *name, int usinguid);
-+void cmd_expunge(char *tag, char *sequence);
-+void cmd_create(char *tag, char *name, char *partition);
-+void cmd_delete(char *tag, char *name);
-+void cmd_rename(char *tag, char *oldname, char *newname, char *partition);
-+void cmd_find(char *tag, char *namespace, char *pattern);
-+void cmd_list(char *tag, int listopts, char *reference, char *pattern);
-+void cmd_changesub(char *tag, char *namespace, char *name, int add);
-+void cmd_getacl(const char *tag, const char *name);
-+void cmd_listrights(char *tag, char *name, char *identifier);
-+void cmd_myrights(const char *tag, const char *name);
-+void cmd_setacl(char *tag, const char *name,
-+		const char *identifier, const char *rights);
-+void cmd_getquota(char *tag, char *name);
-+void cmd_getquotaroot(char *tag, char *name);
-+void cmd_setquota(char *tag, char *quotaroot);
-+void cmd_status(char *tag, char *name);
-+void cmd_getuids(char *tag, char *startuid);
-+void cmd_unselect(char* tag);
-+void cmd_namespace(char* tag);
-+void cmd_reconstruct(char *tag, char *name);
-+
-+void cmd_id(char* tag);
-+struct idparamlist {
-+    char *field;
-+    char *value;
-+    struct idparamlist *next;
-+};
-+extern void id_getcmdline(int argc, char **argv);
-+extern void id_response(struct protstream *pout);
-+void id_appendparamlist(struct idparamlist **l, char *field, char *value);
-+void id_freeparamlist(struct idparamlist *l);
-+
-+void cmd_idle(char* tag);
-+void cmd_starttls(char *tag, int imaps);
-+
-+#ifdef ENABLE_X_NETSCAPE_HACK
-+void cmd_netscape (char* tag);
-+#endif
-+
-+void cmd_getannotation(char* tag, char *mboxpat);
-+void cmd_setannotation(char* tag, char *mboxpat);
-+
-+int getannotatefetchdata(char *tag,
-+			 struct strlist **entries, struct strlist **attribs);
-+int getannotatestoredata(char *tag, struct entryattlist **entryatts);
-+
-+void annotate_response(struct entryattlist *l);
-+int annotate_fetch_proxy(const char *server, const char *mbox_pat,
-+			 struct strlist *entry_pat,
-+			 struct strlist *attribute_pat);
-+int annotate_store_proxy(const char *server, const char *mbox_pat,
-+			 struct entryattlist *entryatts);
-+
-+void printstring (const char *s);
-+void printastring (const char *s);
-+
-+static int mailboxdata(char *name, int matchlen, int maycreate, void *roc=
k);
-+static int listdata(char *name, int matchlen, int maycreate, void *rock);
-+static void mstringdata(char *cmd, char *name, int matchlen, int maycreat=
e);
-+
-+static int mlookup(const char *name, char **pathp, =

-+		   char **aclp, void *tid);
-+
-+extern int saslserver(sasl_conn_t *conn, const char *mech,
-+		      const char *init_resp, const char *resp_prefix,
-+		      const char *continuation, const char *empty_chal,
-+		      struct protstream *pin, struct protstream *pout,
-+		      int *sasl_result, char **success_data);
-+
-+/* Enable the resetting of a sasl_conn_t */
-+static int reset_saslconn(sasl_conn_t **conn);
-+
-+static struct =

-+{
-+    char *ipremoteport;
-+    char *iplocalport;    =

-+    sasl_ssf_t ssf;
-+    char *authid;
-+} saslprops =3D {NULL,NULL,0,NULL};
-+
-+#define BUFGROWSIZE 100
-+
-+/* proxy support functions */
-+enum {
-+    PROXY_NOCONNECTION =3D -1,
-+    PROXY_OK =3D 0,
-+    PROXY_NO =3D 1,
-+    PROXY_BAD =3D 2
-+};
-+
-+static void proxyd_gentag(char *tag, size_t len)
-+{
-+    snprintf(tag, len, "PROXY%d", proxyd_cmdcnt++);
-+}
-+
-+/* pipe_response() reads from 's->in' until either the tagged response
-+   starting with 'tag' appears, or if 'tag' is NULL, to the end of the
-+   current line.  If 'include_tag' is set, the tagged line is included
-+   in the output, otherwise the tagged line is stored in 's->last_result'=
. =

-+   In either case, the result of the tagged command is returned.
-+
-+/* 's->last_result' assumes that tagged responses don't contain literals.
-+   Unfortunately, the IMAP grammar allows them */
-+
-+/* force_notfatal says to not fatal() if we lose connection to backend_cu=
rrent
-+ * even though it is in 95% of the cases, a good idea... */
-+static int pipe_response(struct backend *s, char *tag, int include_tag,
-+			 int force_notfatal)
-+{
-+    char buf[2048];
-+    char eol[128];
-+    int sl;
-+    int cont =3D 0, last =3D !tag, r =3D PROXY_OK;
-+    size_t taglen;
-+
-+    s->timeout->mark =3D time(NULL) + IDLE_TIMEOUT;
-+
-+    if (tag) {
-+	taglen =3D strlen(tag);
-+	if(taglen >=3D sizeof(buf)) {
-+	    fatal("tag too large",EC_TEMPFAIL);
-+	}
-+    }
-+
-+    s->last_result.len =3D 0;
-+
-+    /* the only complication here are literals */
-+    do {
-+	/* if 'cont' is set, we're looking at the continuation to a very
-+	   long line.
-+	   if 'last' is set, we've seen the tag we're looking for, we're
-+	   just reading the end of the line. */
-+	if (!cont) eol[0] =3D '\0';
-+
-+	if (!prot_fgets(buf, sizeof(buf), s->in)) {
-+	    /* uh oh */
-+	    if(s =3D=3D backend_current && !force_notfatal)
-+		fatal("Lost connection to selected backend", EC_UNAVAILABLE);
-+	    proxyd_downserver(s);
-+	    return PROXY_NOCONNECTION;
-+	}
-+
-+	sl =3D strlen(buf);
-+
-+	if (tag) {
-+	    /* Check for the tagged line */
-+	    if (!cont && buf[taglen] =3D=3D ' ' && !strncmp(tag, buf, taglen)) {
-+
-+		switch (buf[taglen + 1]) {
-+		case 'O': case 'o':
-+		    r =3D PROXY_OK;
-+		    break;
-+		case 'N': case 'n':
-+		    r =3D PROXY_NO;
-+		    break;
-+		case 'B': case 'b':
-+		    r =3D PROXY_BAD;
-+		    break;
-+		default: /* huh? no result? */
-+		    if(s =3D=3D backend_current && !force_notfatal)
-+			fatal("Lost connection to selected backend",
-+			      EC_UNAVAILABLE);
-+		    proxyd_downserver(s);
-+		    r =3D PROXY_NOCONNECTION;
-+		    break;
-+		}
-+
-+		last =3D 1;
-+	    }
-+	=

-+	    if (last && !include_tag) {
-+		/* Store the tagged line */
-+		if (sl > s->last_result.alloc - s->last_result.len) {
-+		    s->last_result.alloc =3D
-+			(s->last_result.alloc =3D=3D 0) ? sizeof(buf) :
-+			s->last_result.alloc * 2;
-+		    s->last_result.s =3D xrealloc(s->last_result.s,
-+						s->last_result.alloc+1);
-+		}
-+
-+		strcpy(s->last_result.s + s->last_result.len, buf + taglen + 1);
-+		s->last_result.len +=3D sl - taglen - 1;
-+	    }
-+	}
-+
-+	if (sl =3D=3D (sizeof(buf) - 1) && buf[sl-1] !=3D '\n') {
-+            /* only got part of a line */
-+	    /* we save the last 64 characters in case it has important
-+	       literal information */
-+	    strcpy(eol, buf + sl - 64);
-+
-+	    /* write out this part, but we have to keep reading until we
-+	       hit the end of the line */
-+	    if (!last || include_tag) prot_write(proxyd_out, buf, sl);
-+	    cont =3D 1;
-+	    continue;
-+	} else {		/* we got the end of the line */
-+	    int i;
-+	    int litlen =3D 0, islit =3D 0;
-+
-+	    if (!last || include_tag) prot_write(proxyd_out, buf, sl);
-+
-+	    /* now we have to see if this line ends with a literal */
-+	    if (sl < 64) {
-+		strcat(eol, buf);
-+	    } else {
-+		strcat(eol, buf + sl - 63);
-+	    }
-+
-+	    /* eol now contains the last characters from the line; we want
-+	       to see if we've hit a literal */
-+	    i =3D strlen(eol);
-+	    if (i >=3D 4 &&
-+		eol[i-1] =3D=3D '\n' && eol[i-2] =3D=3D '\r' && eol[i-3] =3D=3D '}') {
-+		/* possible literal */
-+		i -=3D 4;
-+		while (i > 0 && eol[i] !=3D '{' && isdigit((int) eol[i])) {
-+		    i--;
-+		}
-+		if (eol[i] =3D=3D '{') {
-+		    islit =3D 1;
-+		    litlen =3D atoi(eol + i + 1);
-+		}
-+	    }
-+
-+	    /* copy the literal over */
-+	    if (islit) {
-+		while (litlen > 0) {
-+		    int j =3D (litlen > sizeof(buf) ? sizeof(buf) : litlen);
-+		    =

-+		    j =3D prot_read(s->in, buf, j);
-+		    if(!j) {
-+			/* EOF or other error */
-+			return -1;
-+		    }
-+		    if (!last || include_tag) prot_write(proxyd_out, buf, j);
-+		    litlen -=3D j;
-+		}
-+
-+		/* none of our saved information has any relevance now */
-+		eol[0] =3D '\0';
-+		=

-+		/* have to keep going for the end of the line */
-+		cont =3D 1;
-+		continue;
-+	    }
-+	}
-+
-+	/* ok, let's read another line */
-+	cont =3D 0;
-+
-+    } while (!last || cont);
-+
-+    return r;
-+}
-+
-+static int pipe_until_tag(struct backend *s, char *tag, int force_notfata=
l)
-+{
-+    return pipe_response(s, tag, 0, force_notfatal);
-+}
-+
-+static int pipe_including_tag(struct backend *s, char *tag, int force_not=
fatal) {
-+    int r;
-+
-+    r =3D pipe_response(s, tag, 1, force_notfatal);
-+    if (r =3D=3D PROXY_NOCONNECTION) {
-+	/* don't have to worry about downing the server, since
-+	 * pipe_until_tag does that for us */
-+	prot_printf(proxyd_out, "%s NO %s\r\n", tag,
-+		    error_message(IMAP_SERVER_UNAVAILABLE));
-+    }
-+    return r;
-+}
-+
-+static int pipe_to_end_of_response(struct backend *s, int force_notfatal)
-+{
-+    return pipe_response(s, NULL, 0, force_notfatal);
-+}
-+
-+/* copy our current input to 's' until we hit a true EOL.
-+
-+   'optimistic_literal' is how happy we should be about assuming
-+   that a command will go through by converting synchronizing literals of
-+   size less than optimistic_literal to nonsync
-+
-+   returns 0 on success, <0 on big failure, >0 on full command not sent */
-+static int pipe_command(struct backend *s, int optimistic_literal)
-+{
-+    char buf[2048];
-+    char eol[128];
-+    int sl;
-+
-+    s->timeout->mark =3D time(NULL) + IDLE_TIMEOUT;
-+    =

-+    eol[0] =3D '\0';
-+
-+    /* again, the complication here are literals */
-+    for (;;) {
-+	if (!prot_fgets(buf, sizeof(buf), proxyd_in)) {
-+	    /* uh oh */
-+	    return -1;
-+	}
-+
-+	sl =3D strlen(buf);
-+
-+	if (sl =3D=3D (sizeof(buf) - 1) && buf[sl-1] !=3D '\n') {
-+            /* only got part of a line */
-+	    strcpy(eol, buf + sl - 64);
-+
-+	    /* and write this out, except for what we've saved */
-+	    prot_write(s->out, buf, sl - 64);
-+	    continue;
-+	} else {
-+	    int i, nonsynch =3D 0, islit =3D 0, litlen =3D 0;
-+
-+	    if (sl < 64) {
-+		strcat(eol, buf);
-+	    } else {
-+		/* write out what we have, and copy the last 64 characters
-+		   to eol */
-+		prot_printf(s->out, "%s", eol);
-+		prot_write(s->out, buf, sl - 64);
-+		strcpy(eol, buf + sl - 64);
-+	    }
-+
-+	    /* now determine if eol has a literal in it */
-+	    i =3D strlen(eol);
-+	    if (i >=3D 4 &&
-+		eol[i-1] =3D=3D '\n' && eol[i-2] =3D=3D '\r' && eol[i-3] =3D=3D '}') {
-+		/* possible literal */
-+		i -=3D 4;
-+		if (eol[i] =3D=3D '+') {
-+		    nonsynch =3D 1;
-+		    i--;
-+		}
-+		while (i > 0 && eol[i] !=3D '{' && isdigit((int) eol[i])) {
-+		    i--;
-+		}
-+		if (eol[i] =3D=3D '{') {
-+		    islit =3D 1;
-+		    litlen =3D atoi(eol + i + 1);
-+		}
-+	    }
-+
-+	    if (islit) {
-+		if (nonsynch) {
-+		    prot_write(s->out, eol, strlen(eol));
-+		} else if (!nonsynch && (litlen <=3D optimistic_literal)) {
-+		    prot_printf(proxyd_out, "+ i am an optimist\r\n");
-+		    prot_write(s->out, eol, strlen(eol) - 3);
-+		    /* need to insert a + to turn it into a nonsynch */
-+		    prot_printf(s->out, "+}\r\n");
-+		} else {
-+		    /* we do a standard synchronizing literal */
-+		    prot_write(s->out, eol, strlen(eol));
-+		    /* but here the game gets tricky... */
-+		    prot_fgets(buf, sizeof(buf), s->in);
-+		    /* but for now we cheat */
-+		    prot_write(proxyd_out, buf, strlen(buf));
-+		    if (buf[0] !=3D '+' && buf[1] !=3D ' ') {
-+			/* char *p =3D strchr(buf, ' '); */
-+			/* strncpy(s->last_result, p + 1, LAST_RESULT_LEN);*/
-+
-+			/* stop sending command now */
-+			return 1;
-+		    }
-+		}
-+
-+		/* gobble literal and sent it onward */
-+		while (litlen > 0) {
-+		    int j =3D (litlen > sizeof(buf) ? sizeof(buf) : litlen);
-+
-+		    j =3D prot_read(proxyd_in, buf, j);
-+		    if(!j) {
-+			/* EOF or other error */
-+			return -1;
-+		    }
-+		    prot_write(s->out, buf, j);
-+		    litlen -=3D j;
-+		}
-+
-+		eol[0] =3D '\0';
-+		=

-+		/* have to keep going for the send of the command */
-+		continue;
-+	    } else {
-+		/* no literal, so we're done! */
-+		prot_write(s->out, eol, strlen(eol));
-+
-+		return 0;
-+	    }
-+	}
-+    }
-+}
-+
-+/* This handles piping of the LSUB command, because we have to figure out
-+ * what mailboxes actually exist before passing them to the end user.
-+ *
-+ * It is also needed if we are doing a FIND MAILBOXES, for that we do an
-+ * LSUB on the backend anyway, because the semantics of FIND do not allow
-+ * it to return nonexistant mailboxes (RFC1176), but we need to really du=
mb
-+ * down the response when this is the case.
-+ */
-+static int pipe_lsub(struct backend *s, char *tag, int force_notfatal,
-+		     const char *resp)
-+{
-+    int taglen =3D strlen(tag);
-+    int c;
-+    int r =3D PROXY_OK;
-+    int exist_r;
-+    char mailboxname[MAX_MAILBOX_PATH + 1];
-+    static struct buf tagb, cmd, sep, name;
-+    int cur_flags_size =3D 64;
-+    char *flags =3D xmalloc(cur_flags_size);
-+
-+    const char *end_strip_flags[] =3D { " \\NonExistent)", "\\NonExistent=
)",
-+				      NULL };
-+    const char *mid_strip_flags[] =3D { "\\NonExistent ",
-+				      NULL =

-+				    };
-+
-+    assert(s);
-+    assert(s->timeout);
-+    =

-+    s->timeout->mark =3D time(NULL) + IDLE_TIMEOUT;
-+
-+    while(1) {
-+	c =3D getword(s->in, &tagb);
-+
-+	if(c =3D=3D EOF) {
-+	    if(s =3D=3D backend_current && !force_notfatal)
-+		fatal("Lost connection to selected backend", EC_UNAVAILABLE);
-+	    proxyd_downserver(s);
-+	    free(flags);
-+	    return PROXY_NOCONNECTION;
-+	}
-+
-+	if(!strncmp(tag, tagb.s, taglen)) {
-+	    char buf[2048];
-+	    if(!prot_fgets(buf, sizeof(buf), s->in)) {
-+		if(s =3D=3D backend_current && !force_notfatal)
-+		    fatal("Lost connection to selected backend",
-+			  EC_UNAVAILABLE);
-+		proxyd_downserver(s);
-+		free(flags);
-+		return PROXY_NOCONNECTION;
-+	    }	=

-+	    /* Got the end of the response */
-+	    if (s->last_result.alloc =3D=3D 0) {
-+		s->last_result.alloc =3D sizeof(buf);
-+		s->last_result.s =3D xmalloc(s->last_result.alloc+1);
-+	    }
-+	    strcpy(s->last_result.s, buf);
-+	    s->last_result.len =3D strlen(buf);
-+
-+	    switch (buf[0]) {
-+	    case 'O': case 'o':
-+		r =3D PROXY_OK;
-+		break;
-+	    case 'N': case 'n':
-+		r =3D PROXY_NO;
-+		break;
-+	    case 'B': case 'b':
-+		r =3D PROXY_BAD;
-+		break;
-+	    default: /* huh? no result? */
-+		if(s =3D=3D backend_current && !force_notfatal)
-+		    fatal("Lost connection to selected backend",
-+			  EC_UNAVAILABLE);
-+		proxyd_downserver(s);
-+		r =3D PROXY_NOCONNECTION;
-+		break;
-+	    }
-+	    break; /* we're done */
-+	}
-+
-+	c =3D getword(s->in, &cmd);
-+
-+	if(c =3D=3D EOF) {
-+	    if(s =3D=3D backend_current && !force_notfatal)
-+		fatal("Lost connection to selected backend", EC_UNAVAILABLE);
-+	    proxyd_downserver(s);
-+	    free(flags);
-+	    return PROXY_NOCONNECTION;
-+	}
-+
-+	if(strncasecmp("LSUB", cmd.s, 4)) {
-+	    prot_printf(proxyd_out, "%s %s ", tagb.s, cmd.s);
-+	    r =3D pipe_to_end_of_response(s, force_notfatal);
-+	    if(r !=3D PROXY_OK) {
-+		free(flags);
-+		return r;
-+	    }
-+	} else {
-+	    /* build up the response bit by bit */
-+	    int i =3D 0;
-+	    char *p;
-+
-+	    c =3D prot_getc(s->in);
-+	    while(c !=3D ')' && c !=3D EOF) {
-+		flags[i++] =3D c;
-+		if(i =3D=3D cur_flags_size) {
-+		    /* expand our buffer */
-+		    cur_flags_size *=3D 2;
-+		    flags =3D xrealloc(flags, cur_flags_size);
-+		}
-+		c =3D prot_getc(s->in);
-+	    }
-+
-+	    if(c !=3D EOF) {
-+		/* terminate string */
-+		flags[i++] =3D ')';
-+		if(i =3D=3D cur_flags_size) {
-+		    /* expand our buffer */
-+		    cur_flags_size *=3D 2;
-+		    flags =3D xrealloc(flags, cur_flags_size);
-+		}
-+		flags[i] =3D '\0';
-+		/* get the next character */
-+ 		c =3D prot_getc(s->in);
-+	    }
-+	    =

-+	    if(c !=3D ' ') {
-+		if(s =3D=3D backend_current && !force_notfatal)
-+		    fatal("Bad LSUB response from selected backend",
-+			  EC_UNAVAILABLE);
-+		proxyd_downserver(s);
-+		free(flags);
-+		return PROXY_NOCONNECTION;
-+	    }
-+
-+	    /* Check for flags that we should remove
-+	     * (e.g. NoSelect, NonExistent) */
-+	    for(i=3D0; end_strip_flags[i]; i++) {
-+		p =3D strstr(flags, end_strip_flags[i]);
-+		if(p) {
-+		    *p =3D ')';
-+		    *(p+1) =3D '\0';
-+		}
-+	    }
-+
-+	    for(i=3D0; mid_strip_flags[i]; i++) {
-+		int mid_strip_len =3D strlen(mid_strip_flags[i]);
-+		p =3D strstr(flags, mid_strip_flags[i]);
-+		while(p) {
-+		    strcpy(p, p + mid_strip_len);
-+		    p =3D strstr(flags, mid_strip_flags[i]);
-+		}
-+	    }
-+		=

-+	    /* Get separator */
-+	    c =3D getastring(s->in, s->out, &sep);
-+
-+	    if(c !=3D ' ') {
-+		if(s =3D=3D backend_current && !force_notfatal)
-+		    fatal("Bad LSUB response from selected backend",
-+			  EC_UNAVAILABLE);
-+		proxyd_downserver(s);
-+		free(flags);
-+		return PROXY_NOCONNECTION;
-+	    }
-+
-+	    /* Get name */
-+	    c =3D getastring(s->in, s->out, &name);
-+
-+	    if(c =3D=3D '\r') c =3D prot_getc(s->in);
-+	    if(c !=3D '\n') {
-+		if(s =3D=3D backend_current && !force_notfatal)
-+		    fatal("Bad LSUB response from selected backend",
-+			  EC_UNAVAILABLE);
-+		proxyd_downserver(s);
-+		free(flags);
-+		return PROXY_NOCONNECTION;
-+	    }
-+
-+	    /* lookup name */
-+	    exist_r =3D 1;
-+	    r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace,
-+							name.s,
-+							proxyd_userid,
-+							mailboxname);
-+	    if (!r) {
-+		int mbtype;
-+		exist_r =3D mboxlist_detail(mailboxname, &mbtype,
-+					  NULL, NULL, NULL, NULL);
-+		if(!exist_r && (mbtype & MBTYPE_RESERVE))
-+		    exist_r =3D IMAP_MAILBOX_RESERVED;
-+	    } else {
-+		/* skip this one */
-+		syslog(LOG_ERR, "could not convert %s to internal form",
-+		       name.s);
-+		continue;
-+	    }
-+
-+	    /* send our response */
-+	    /* we need to set \Noselect if it's not in our mailboxes.db */
-+	    if(resp[0] =3D=3D 'L') {
-+		if(!exist_r) {
-+		    prot_printf(proxyd_out, "* %s %s \"%s\" ",
-+				resp, flags, sep.s);
-+		} else {
-+		    prot_printf(proxyd_out, "* %s (\\Noselect) \"%s\" ",
-+				resp, sep.s);
-+		}
-+
-+		printstring(name.s);
-+		prot_printf(proxyd_out, "\r\n");
-+
-+	    } else if(resp[0] =3D=3D 'M' && !exist_r) {
-+		/* Note that it has to exist for a find response */
-+		prot_printf(proxyd_out, "* %s ", resp);
-+		printastring(name.s);
-+		prot_printf(proxyd_out, "\r\n");
-+	    }
-+	}
-+    } /* while(1) */
-+
-+    free(flags);
-+    return r;
-+}
-+
-+void proxyd_downserver(struct backend *s)
-+{
-+    if (!s || !s->timeout) {
-+	/* already disconnected */
-+	return;
-+    }
-+
-+    /* need to logout of server */
-+    backend_disconnect(s, &protocol[PROTOCOL_IMAP]);
-+
-+    if(s =3D=3D backend_inbox) backend_inbox =3D NULL;
-+    if(s =3D=3D backend_current) backend_current =3D NULL;
-+
-+    /* remove the timeout */
-+    prot_removewaitevent(proxyd_in, s->timeout);
-+    s->timeout =3D NULL;
-+}
-+
-+struct prot_waitevent *backend_timeout(struct protstream *s __attribute__=
((unused)),
-+				       struct prot_waitevent *ev, void *rock)
-+{
-+    struct backend *be =3D (struct backend *) rock;
-+    int is_active =3D (be->context ? *((int *) be->context) : 0);
-+
-+    if ((be !=3D backend_current) && !is_active) {
-+	/* server is not our current server, and idle too long.
-+	 * down the backend server (removes the event as a side-effect)
-+	 */
-+	proxyd_downserver(be);
-+	return NULL;
-+    }
-+    else {
-+	/* it will timeout in IDLE_TIMEOUT seconds from now */
-+	ev->mark =3D time(NULL) + IDLE_TIMEOUT;
-+	return ev;
-+    }
-+}
-+
-+/* return the connection to the server */
-+struct backend *proxyd_findserver(const char *server)
-+{
-+    int i =3D 0;
-+    struct backend *ret =3D NULL;
-+
-+    while (backend_cached && backend_cached[i]) {
-+	if (!strcmp(server, backend_cached[i]->hostname)) {
-+	    /* xxx do we want to ping/noop the server here? */
-+	    ret =3D backend_cached[i];
-+	    break;
-+	}
-+	i++;
-+    }
-+
-+    if (!ret || !ret->timeout) {
-+	char authid[MAX_MAILBOX_NAME+1];
-+
-+	/* Translate any separators in userid for AUTH to backend */
-+	strlcpy(authid, proxyd_userid, sizeof(authid));
-+        mboxname_hiersep_toexternal(&proxyd_namespace, authid,
-+				    config_virtdomains ?
-+				    strcspn(authid, "@") : 0);
-+
-+	/* need to (re)establish connection to server or create one */
-+	ret =3D backend_connect(ret, server, &protocol[PROTOCOL_IMAP],
-+			      authid, NULL);
-+	if(!ret) return NULL;
-+
-+	/* add the timeout */
-+	ret->timeout =3D prot_addwaitevent(proxyd_in, time(NULL) + IDLE_TIMEOUT,
-+					 backend_timeout, ret);
-+    }
-+
-+    ret->timeout->mark =3D time(NULL) + IDLE_TIMEOUT;
-+
-+    /* insert server in list of cached connections */
-+    if (!backend_cached[i]) {
-+	backend_cached =3D (struct backend **) =

-+	    xrealloc(backend_cached, (i + 2) * sizeof(struct backend *));
-+	backend_cached[i] =3D ret;
-+	backend_cached[i + 1] =3D NULL;
-+    }
-+
-+    return ret;
-+}
-+
-+/* proxy mboxlist_lookup; on misses, it asks the listener for this
-+   machine to make a roundtrip to the master mailbox server to make
-+   sure it's up to date */
-+static int mlookup(const char *name, char **pathp, =

-+		   char **aclp, void *tid)
-+{
-+    int r;
-+    int mbtype =3D 0;
-+
-+    if(pathp) *pathp =3D NULL;
-+
-+    r =3D mboxlist_detail(name, &mbtype, pathp, NULL, aclp, tid);
-+    if (r =3D=3D IMAP_MAILBOX_NONEXISTENT || (mbtype & MBTYPE_RESERVE)) {
-+	/* It is not currently active, make sure we have the most recent
-+	 * copy of the database */
-+	kick_mupdate();
-+	r =3D mboxlist_lookup(name, pathp, aclp, tid);
-+    }
-+
-+    /* xxx hide the fact that we are storing partitions */
-+    if(pathp && *pathp) {
-+	char *c;
-+	c =3D strchr(*pathp, '!');
-+	if(c) *c =3D '\0';
-+    }
-+    return r;
-+}
-+
-+static struct backend *proxyd_findinboxserver(void)
-+{
-+    char inbox[MAX_MAILBOX_NAME+1];
-+    int r;
-+    char *server =3D NULL;
-+    struct backend *s =3D NULL;
-+
-+    r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace, "INB=
OX",
-+						proxyd_userid, inbox);
-+
-+    if(!r) {
-+	r =3D mlookup(inbox, &server, NULL, NULL);
-+	if (!r) {
-+	    s =3D proxyd_findserver(server);
-+	}
-+    }
-+    =

-+    return s;
-+}
-+
-+/* proxyd_refer() issues a referral to the client. */
-+static void proxyd_refer(const char *tag,
-+			 const char *server,
-+			 const char *mailbox)
-+{
-+    char url[MAX_MAILBOX_PATH + 1];
-+
-+    if(!strcmp(proxyd_userid, "anonymous")) {
-+	imapurl_toURL(url, server, mailbox, "ANONYMOUS");
-+    } else {
-+	imapurl_toURL(url, server, mailbox, "*");
-+    }
-+    =

-+    prot_printf(proxyd_out, "%s NO [REFERRAL %s] Remote mailbox.\r\n", =

-+		tag, url);
-+}
-+
-+static int proxyd_canon_user(sasl_conn_t *conn, void *context,
-+			     const char *user, unsigned ulen,
-+			     unsigned flags, const char *user_realm,
-+			     char *out, unsigned out_max, unsigned *out_ulen)
-+{
-+    char userbuf[MAX_MAILBOX_NAME+1], *p;
-+    size_t n;
-+    int r;
-+
-+    if (!ulen) ulen =3D strlen(user);
-+
-+    if (config_getswitch(IMAPOPT_IMAPMAGICPLUS)) {
-+	/* make a working copy of the auth[z]id */
-+	if (ulen > MAX_MAILBOX_NAME) {
-+	    sasl_seterror(conn, 0, "buffer overflow while canonicalizing");
-+	    return SASL_BUFOVER;
-+	}
-+	/* make a working copy of the auth[z]id */
-+	memcpy(userbuf, user, ulen);
-+	userbuf[ulen] =3D '\0';
-+	user =3D userbuf;
-+
-+	/* See if we're using the magic plus
-+	   (currently we don't support anything after '+') */
-+	if ((p =3D strchr(userbuf, '+')) && =

-+	    (n =3D config_virtdomains ? strcspn(p, "@") : strlen(p)) =3D=3D 1) {
-+
-+	    if (flags & SASL_CU_AUTHZID) {
-+		/* make a copy of the magic plus */
-+		if (proxyd_magicplus) free(proxyd_magicplus);
-+		proxyd_magicplus =3D xstrndup(p, n);
-+	    }
-+
-+	    /* strip the magic plus from the auth[z]id */
-+	    memmove(p, p+n, strlen(p+n)+1);
-+	    ulen -=3D n;
-+	}
-+    }
-+
-+    r =3D mysasl_canon_user(conn, context, user, ulen, flags, user_realm,
-+			  out, out_max, out_ulen);
-+
-+    if (!r && proxyd_magicplus && flags =3D=3D SASL_CU_AUTHZID) {
-+	/* If we're only doing the authzid, put back the magic plus
-+	   in case its used in the challenge/response calculation */
-+	n =3D strlen(proxyd_magicplus);
-+	if (*out_ulen + n > out_max) {
-+	    sasl_seterror(conn, 0, "buffer overflow while canonicalizing");
-+	    r =3D SASL_BUFOVER;
-+	}
-+	else {
-+	    p =3D (config_virtdomains && (p =3D strchr(out, '@'))) ?
-+		p : out + *out_ulen;
-+	    memmove(p+n, p, strlen(p)+1);
-+	    memcpy(p, proxyd_magicplus, n);
-+	    *out_ulen +=3D n;
-+	}
-+    }
-+
-+    return r;
-+}
-+
-+static int proxyd_proxy_policy(sasl_conn_t *conn,
-+			       void *context,
-+			       const char *requested_user, unsigned rlen,
-+			       const char *auth_identity, unsigned alen,
-+			       const char *def_realm,
-+			       unsigned urlen,
-+			       struct propctx *propctx)
-+{
-+    if (config_getswitch(IMAPOPT_IMAPMAGICPLUS)) {
-+	char userbuf[MAX_MAILBOX_NAME+1], *p;
-+	size_t n;
-+
-+	/* make a working copy of the authzid */
-+	if (!rlen) rlen =3D strlen(requested_user);
-+	if (rlen > MAX_MAILBOX_NAME) {
-+	    sasl_seterror(conn, 0, "buffer overflow while canonicalizing");
-+	    return SASL_BUFOVER;
-+	}
-+	memcpy(userbuf, requested_user, rlen);
-+	userbuf[rlen] =3D '\0';
-+	requested_user =3D userbuf;
-+
-+	/* See if we're using the magic plus */
-+	if ((p =3D strchr(userbuf, '+'))) {
-+	    n =3D config_virtdomains ? strcspn(p, "@") : strlen(p);
-+
-+	    /* strip the magic plus from the authzid */
-+	    memmove(p, p+n, strlen(p+n)+1);
-+	    rlen -=3D n;
-+	}
-+    }
-+
-+    return mysasl_proxy_policy(conn, context, requested_user, rlen,
-+			       auth_identity, alen, def_realm, urlen, propctx);
-+}
-+
-+static struct sasl_callback mysasl_cb[] =3D {
-+    { SASL_CB_GETOPT, &mysasl_config, NULL },
-+    { SASL_CB_PROXY_POLICY, &proxyd_proxy_policy, (void*) &proxyd_proxyct=
x },
-+    { SASL_CB_CANON_USER, &proxyd_canon_user, (void*) &disable_referrals =
},
-+    { SASL_CB_LIST_END, NULL, NULL }
-+};
-+
-+extern void setproctitle_init(int argc, char **argv, char **envp);
-+extern int proc_register(const char *progname, const char *clienthost, =

-+			 const char *userid, const char *mailbox);
-+extern void proc_cleanup(void);
-+
-+/*
-+ * run once when process is forked;
-+ * MUST NOT exit directly; must return with non-zero error code
-+ */
-+int service_init(int argc, char **argv, char **envp)
-+{
-+    int opt;
-+
-+    if (geteuid() =3D=3D 0) fatal("must run as the Cyrus user", EC_USAGE);
-+    setproctitle_init(argc, argv, envp);
-+
-+    /* set signal handlers */
-+    signals_set_shutdown(&shut_down);
-+    signal(SIGPIPE, SIG_IGN);
-+
-+    /* load the SASL plugins */
-+    global_sasl_init(1, 1, mysasl_cb);
-+
-+    /* open the mboxlist, we'll need it for real work */
-+    mboxlist_init(0);
-+    mboxlist_open(NULL);
-+
-+    while ((opt =3D getopt(argc, argv, "sp:N")) !=3D EOF) {
-+	switch (opt) {
-+	case 's': /* imaps (do starttls right away) */
-+	    imaps =3D 1;
-+	    if (!tls_enabled()) {
-+		syslog(LOG_ERR, "imaps: required OpenSSL options not present");
-+		fatal("imaps: required OpenSSL options not present",
-+		      EC_CONFIG);
-+	    }
-+	    break;
-+	case 'p': /* external protection */
-+	    extprops_ssf =3D atoi(optarg);
-+	    break;
-+	case 'N': /*bypass SASL password check.  Not recommended unless you know
-+                   *what you're doing */
-+            nosaslpasswdcheck =3D 1;
-+	   syslog( LOG_NOTICE, "setting nosaslpasswdcheck to true" );
-+            break;
-+	default:
-+	    break;
-+	}
-+    }
-+
-+    /* Initialize the annotatemore extention */
-+    annotatemore_init(0, annotate_fetch_proxy, annotate_store_proxy);
-+    annotatemore_open(NULL);
-+
-+    return 0;
-+}
-+
-+static void proxyd_reset(void) =

-+{
-+    int i;
-+    =

-+    proc_cleanup();
-+
-+    /* close backend connections */
-+    i =3D 0;
-+    while (backend_cached[i]) {
-+	proxyd_downserver(backend_cached[i]);
-+	if (backend_cached[i]->last_result.s) {
-+	    free(backend_cached[i]->last_result.s);
-+	}
-+	free(backend_cached[i]);
-+	i++;
-+    }
-+    free(backend_cached);
-+    backend_cached =3D NULL;
-+    backend_inbox =3D backend_current =3D NULL;
-+
-+    /* Cleanup file descriptors. note: after last call to proxyd_downserv=
er */
-+    if(proxyd_in) {
-+	prot_NONBLOCK(proxyd_in);
-+	prot_fill(proxyd_in);
-+	=

-+	prot_free(proxyd_in);
-+    }
-+    if(proxyd_out) {
-+	prot_flush(proxyd_out);
-+	prot_free(proxyd_out);
-+    }
-+    =

-+    proxyd_in =3D proxyd_out =3D NULL;
-+
-+#ifdef HAVE_SSL
-+    if (tls_conn) {
-+	if (tls_reset_servertls(&tls_conn) =3D=3D -1) {
-+	    fatal("tls_reset() failed", EC_TEMPFAIL);
-+	}
-+	tls_conn =3D NULL;
-+    }
-+#endif
-+
-+    cyrus_reset_stdio(); =

-+    =

-+    /* Cleanup Globals */
-+    proxyd_cmdcnt =3D 0;
-+    disable_referrals =3D 0;
-+    supports_referrals =3D 0;
-+    proxyd_userisadmin =3D 0;
-+    proxyd_starttls_done =3D 0;
-+    proxyd_logtime =3D 0;
-+    plaintextloginalert =3D NULL;
-+
-+    strcpy(proxyd_clienthost, "[local]");
-+
-+    if(proxyd_logfd !=3D -1) {
-+	close(proxyd_logfd);
-+	proxyd_logfd =3D -1;
-+    }
-+
-+    if(proxyd_userid) {
-+	free(proxyd_userid);
-+	proxyd_userid =3D NULL;
-+    }
-+    if(proxyd_magicplus !=3D NULL) {
-+	free(proxyd_magicplus);
-+	proxyd_magicplus =3D NULL;
-+    }
-+    if(proxyd_authstate) {
-+	auth_freestate(proxyd_authstate);
-+	proxyd_authstate =3D NULL;
-+    }
-+
-+    /* Cleanup SASL */
-+    if(proxyd_saslconn) {
-+	sasl_dispose(&proxyd_saslconn);
-+	proxyd_saslconn =3D NULL;
-+    }
-+    if(saslprops.iplocalport) {
-+	free(saslprops.iplocalport);
-+	saslprops.iplocalport =3D NULL;
-+    }
-+    if(saslprops.ipremoteport) {
-+	free(saslprops.ipremoteport);
-+	saslprops.ipremoteport =3D NULL;
-+    }
-+    if(saslprops.authid) {
-+	free(saslprops.authid);
-+	saslprops.authid =3D NULL;
-+    }
-+    saslprops.ssf =3D 0;
-+}
-+
-+int service_main(int argc __attribute__((unused)),
-+		 char **argv __attribute__((unused)),
-+		 char **envp __attribute__((unused)))
-+{
-+    socklen_t salen;
-+    char hbuf[NI_MAXHOST];
-+    struct sockaddr_storage proxyd_localaddr, proxyd_remoteaddr;
-+    char localip[60], remoteip[60];
-+    int niflags;
-+    int timeout;
-+    int proxyd_haveaddr =3D 0;
-+    sasl_security_properties_t *secprops =3D NULL;
-+
-+    signals_poll();
-+
-+#ifdef ID_SAVE_CMDLINE
-+    /* get command line args for use in ID before getopt mangles them */
-+    id_getcmdline(argc, argv);
-+#endif
-+
-+    proxyd_in =3D prot_new(0, 0);
-+    proxyd_out =3D prot_new(1, 1);
-+
-+    /* Find out name of client host */
-+    salen =3D sizeof(proxyd_remoteaddr);
-+    if (getpeername(0, (struct sockaddr *)&proxyd_remoteaddr, &salen) =3D=
=3D 0 &&
-+	(proxyd_remoteaddr.ss_family =3D=3D AF_INET ||
-+	 proxyd_remoteaddr.ss_family =3D=3D AF_INET6)) {
-+	if (getnameinfo((struct sockaddr *)&proxyd_remoteaddr, salen,
-+			hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD) =3D=3D 0) {
-+	    strncpy(proxyd_clienthost, hbuf, sizeof(hbuf));
-+	    strlcat(proxyd_clienthost, " ", sizeof(proxyd_clienthost));
-+	} else {
-+	    proxyd_clienthost[0] =3D '\0';
-+	}
-+	niflags =3D NI_NUMERICHOST;
-+#ifdef NI_WITHSCOPEID
-+	if (((struct sockaddr *)&proxyd_remoteaddr)->sa_family =3D=3D AF_INET6)
-+	    niflags |=3D NI_WITHSCOPEID;
-+#endif
-+	if (getnameinfo((struct sockaddr *)&proxyd_remoteaddr, salen, hbuf,
-+			sizeof(hbuf), NULL, 0, niflags) !=3D 0)
-+	    strlcpy(hbuf, "unknown", sizeof(hbuf));
-+	strlcat(proxyd_clienthost, "[", sizeof(proxyd_clienthost));
-+	strlcat(proxyd_clienthost, hbuf, sizeof(proxyd_clienthost));
-+	strlcat(proxyd_clienthost, "]", sizeof(proxyd_clienthost));
-+	salen =3D sizeof(proxyd_localaddr);
-+	if (getsockname(0, (struct sockaddr *)&proxyd_localaddr,
-+			&salen) =3D=3D 0) {
-+	    if(iptostring((struct sockaddr *)&proxyd_remoteaddr,
-+			  salen, remoteip, 60) =3D=3D 0
-+	       && iptostring((struct sockaddr *)&proxyd_localaddr,
-+			     salen, localip, 60) =3D=3D 0) {
-+		proxyd_haveaddr =3D 1;
-+	    }
-+	}
-+    }
-+
-+    /* create the SASL connection */
-+    /* Make a SASL connection and setup some properties for it */
-+    /* other params should be filled in */
-+    if (sasl_server_new("imap", config_servername, =

-+			NULL,
-+			(proxyd_haveaddr ? localip : NULL),
-+			(proxyd_haveaddr ? remoteip : NULL),
-+			NULL, 0, =

-+			&proxyd_saslconn) !=3D SASL_OK) {
-+	fatal("SASL failed initializing: sasl_server_new()", EC_TEMPFAIL); =

-+    }
-+
-+    if(proxyd_haveaddr) {
-+        saslprops.ipremoteport =3D xstrdup(remoteip);
-+        saslprops.iplocalport =3D xstrdup(localip);
-+    }    =

-+
-+    secprops =3D mysasl_secprops(SASL_SEC_NOPLAINTEXT);
-+    sasl_setprop(proxyd_saslconn, SASL_SEC_PROPS, secprops);
-+    sasl_setprop(proxyd_saslconn, SASL_SSF_EXTERNAL, &extprops_ssf);
-+
-+    proc_register("proxyd", proxyd_clienthost, (char *)0, (char *)0);
-+
-+    /* Set inactivity timer */
-+    timeout =3D config_getint(IMAPOPT_TIMEOUT);
-+    if (timeout < 30) timeout =3D 30;
-+    prot_settimeout(proxyd_in, timeout*60);
-+    prot_setflushonread(proxyd_in, proxyd_out);
-+
-+    /* setup the cache */
-+    backend_cached =3D xmalloc(sizeof(struct backend *));
-+    backend_cached[0] =3D NULL;
-+
-+    /* we were connected on imaps port so we should do =

-+       TLS negotiation immediately */
-+    if (imaps =3D=3D 1) cmd_starttls(NULL, 1);
-+
-+    cmdloop();
-+    =

-+    /* cleanup */    =

-+    prot_flush(proxyd_out);
-+    proxyd_reset();
-+    =

-+    /* return to service another connection */
-+    return 0;
-+}
-+
-+/* Called by service API to shut down the service */
-+void service_abort(int error)
-+{
-+    shut_down(error);
-+}
-+
-+/*
-+ * found a motd file; spit out message and return
-+ */
-+void motd_file(int fd)
-+{
-+    struct protstream *motd_in;
-+    char buf[1024];
-+    char *p;
-+
-+    motd_in =3D prot_new(fd, 0);
-+
-+    prot_fgets(buf, sizeof(buf), motd_in);
-+    if ((p =3D strchr(buf, '\r')) !=3D NULL) *p =3D 0;
-+    if ((p =3D strchr(buf, '\n')) !=3D NULL) *p =3D 0;
-+
-+    for(p =3D buf; *p =3D=3D '['; p++); /* can't have [ be first char, si=
gh */
-+    prot_printf(proxyd_out, "* OK [ALERT] %s\r\n", p);
-+}
-+
-+/*
-+ * Cleanly shut down and exit
-+ */
-+void shut_down(int code) __attribute__((noreturn));
-+void shut_down(int code)
-+{
-+    int i;
-+
-+    proc_cleanup();
-+
-+    i =3D 0;
-+    while (backend_cached && backend_cached[i]) {
-+	proxyd_downserver(backend_cached[i]);
-+	if (backend_cached[i]->last_result.s) {
-+	    free(backend_cached[i]->last_result.s);
-+	}
-+	free(backend_cached[i]);
-+	i++;
-+    }
-+
-+    mboxlist_close();
-+    mboxlist_done();
-+
-+    annotatemore_close();
-+    annotatemore_done();
-+
-+    if (proxyd_in) {
-+	prot_NONBLOCK(proxyd_in);
-+	prot_fill(proxyd_in);
-+
-+	prot_free(proxyd_in);
-+    }
-+
-+    if (proxyd_out) {
-+	prot_flush(proxyd_out);
-+
-+	prot_free(proxyd_out);
-+    }
-+
-+#ifdef HAVE_SSL
-+    tls_shutdown_serverengine();
-+#endif
-+
-+    cyrus_done();
-+
-+    exit(code);
-+}
-+
-+void fatal(const char *s, int code)
-+{
-+    static int recurse_code =3D 0;
-+
-+    if (recurse_code) {
-+	/* We were called recursively. Just give up */
-+	proc_cleanup();
-+	exit(recurse_code);
-+    }
-+    recurse_code =3D code;
-+    if (proxyd_out) {
-+	prot_printf(proxyd_out, "* BYE Fatal error: %s\r\n", s);
-+	prot_flush(proxyd_out);
-+    }
-+    shut_down(code);
-+}
-+
-+/*
-+ * Top-level command loop parsing
-+ */
-+void cmdloop()
-+{
-+    int fd;
-+    char motdfilename[1024];
-+    char hostname[MAXHOSTNAMELEN+1];
-+    int c;
-+    int usinguid, havepartition, havenamespace;
-+    static struct buf tag, cmd, arg1, arg2, arg3, arg4;
-+    char *p, shut[1024];
-+    const char *err;
-+
-+    snprintf(shutdownfilename, sizeof(shutdownfilename), =

-+	     "%s/msg/shutdown", config_dir);
-+
-+    gethostname(hostname, sizeof(hostname));
-+    prot_printf(proxyd_out,
-+		"* OK %s Cyrus IMAP4 Murder %s server ready\r\n", hostname,
-+		CYRUS_VERSION);
-+
-+    snprintf(motdfilename, sizeof(motdfilename), "%s/msg/motd", config_di=
r);
-+    if ((fd =3D open(motdfilename, O_RDONLY, 0)) !=3D -1) {
-+	motd_file(fd);
-+	close(fd);
-+    }
-+
-+    for (;;) {
-+	if (! proxyd_userisadmin && shutdown_file(shut, sizeof(shut))) {
-+	    for (p =3D shut; *p =3D=3D '['; p++); /* can't have [ be first char =
*/
-+	    prot_printf(proxyd_out, "* BYE [ALERT] %s\r\n", p);
-+	    shut_down(0);
-+	}
-+
-+	signals_poll();
-+
-+	/* Parse tag */
-+	c =3D getword(proxyd_in, &tag);
-+	if (c =3D=3D EOF) {
-+	    err =3D prot_error(proxyd_in);
-+	    if (err) {
-+		syslog(LOG_WARNING, "PROTERR: %s", err);
-+		prot_printf(proxyd_out, "* BYE %s\r\n", err);
-+	    }
-+	    return;
-+	}
-+	if (c !=3D ' ' || !imparse_isatom(tag.s) || =

-+	    (tag.s[0] =3D=3D '*' && !tag.s[1])) {
-+	    prot_printf(proxyd_out, "* BAD Invalid tag\r\n");
-+	    eatline(proxyd_in, c);
-+	    continue;
-+	}
-+
-+	/* Parse command name */
-+	c =3D getword(proxyd_in, &cmd);
-+	if (!cmd.s[0]) {
-+	    prot_printf(proxyd_out, "%s BAD Null command\r\n", tag.s);
-+	    eatline(proxyd_in, c);
-+	    continue;
-+	}
-+	if (islower((unsigned char) cmd.s[0])) cmd.s[0] =3D toupper(cmd.s[0]);
-+	for (p =3D &cmd.s[1]; *p; p++) {
-+	    if (isupper((unsigned char) *p)) *p =3D tolower(*p);
-+	}
-+
-+	/* if we need to force a kick, do so */
-+	if(referral_kick) {
-+	    kick_mupdate();
-+	    referral_kick =3D 0;
-+	}
-+
-+	if (plaintextloginalert) {
-+	    prot_printf(proxyd_out, "* OK [ALERT] %s\r\n",
-+			plaintextloginalert);
-+	    plaintextloginalert =3D NULL;
-+	}
-+	=

-+	/* Only Authenticate/Login/Logout/Noop/Starttls =

-+	   allowed when not logged in */
-+	if (!proxyd_userid && !strchr("ALNCIS", cmd.s[0])) goto nologin;
-+    	switch (cmd.s[0]) {
-+	case 'A':
-+	    if (!strcmp(cmd.s, "Authenticate")) {
-+		int haveinitresp =3D 0;
-+
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getword(proxyd_in, &arg1);
-+		if (!imparse_isatom(arg1.s)) {
-+		    prot_printf(proxyd_out, =

-+				"%s BAD Invalid authenticate mechanism\r\n", =

-+				tag.s);
-+		    eatline(proxyd_in, c);
-+		    continue;
-+		}
-+		if (c =3D=3D ' ') {
-+		    haveinitresp =3D 1;
-+		    c =3D getword(proxyd_in, &arg2);
-+		    if (c =3D=3D EOF) goto missingargs;
-+		}
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		=

-+		if (proxyd_userid) {
-+		    prot_printf(proxyd_out, =

-+				"%s BAD Already authenticated\r\n", tag.s);
-+		    continue;
-+		}
-+		cmd_authenticate(tag.s, arg1.s, haveinitresp ? arg2.s : NULL);
-+	    }
-+	    else if (!proxyd_userid) goto nologin;
-+	    else if (!strcmp(cmd.s, "Append")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c !=3D ' ') goto missingargs;
-+
-+		cmd_append(tag.s, arg1.s);
-+	    }
-+	    else goto badcmd;
-+	    break;
-+
-+	case 'B':
-+	    if (!strcmp(cmd.s, "Bboard")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c =3D=3D EOF) goto missingargs;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+
-+		cmd_select(tag.s, cmd.s, arg1.s);
-+	    }
-+	    else goto badcmd;
-+	    break;
-+
-+	case 'C':
-+	    if (!strcmp(cmd.s, "Capability")) {
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_capability(tag.s);
-+	    }
-+	    else if (!proxyd_userid) goto nologin;
-+	    else if (!strcmp(cmd.s, "Check")) {
-+		if (!backend_current) goto nomailbox;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_noop(tag.s, cmd.s);
-+	    }
-+	    else if (!strcmp(cmd.s, "Copy")) {
-+		if (!backend_current) goto nomailbox;
-+		usinguid =3D 0;
-+		if (c !=3D ' ') goto missingargs;
-+	    copy:
-+		c =3D getword(proxyd_in, &arg1);
-+		if (c =3D=3D '\r') goto missingargs;
-+		if (c !=3D ' ' || !imparse_issequence(arg1.s)) goto badsequence;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg2);
-+		if (c =3D=3D EOF) goto missingargs;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+
-+		cmd_copy(tag.s, arg1.s, arg2.s, usinguid);
-+	    }
-+	    else if (!strcmp(cmd.s, "Create")) {
-+		havepartition =3D 0;
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c =3D=3D EOF) goto missingargs;
-+		if (c =3D=3D ' ') {
-+		    havepartition =3D 1;
-+		    c =3D getword(proxyd_in, &arg2);
-+		    if (!imparse_isatom(arg2.s)) goto badpartition;
-+		}
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_create(tag.s, arg1.s, havepartition ? arg2.s : 0);
-+	    }
-+	    else if (!strcmp(cmd.s, "Close")) {
-+		if (!backend_current) goto nomailbox;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_close(tag.s);
-+	    }
-+	    else goto badcmd;
-+	    break;
-+
-+	case 'D':
-+	    if (!strcmp(cmd.s, "Delete")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c =3D=3D EOF) goto missingargs;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_delete(tag.s, arg1.s);
-+	    }
-+	    else if (!strcmp(cmd.s, "Deleteacl")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg2);
-+		if (c =3D=3D EOF) goto missingargs;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_setacl(tag.s, arg1.s, arg2.s, (char *)0);
-+	    }
-+	    else goto badcmd;
-+	    break;
-+
-+	case 'E':
-+	    if (!strcmp(cmd.s, "Expunge")) {
-+		if (!backend_current) goto nomailbox;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_expunge(tag.s, 0);
-+	    }
-+	    else if (!strcmp(cmd.s, "Examine")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c =3D=3D EOF) goto missingargs;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+
-+		cmd_select(tag.s, cmd.s, arg1.s);
-+	    }
-+	    else goto badcmd;
-+	    break;
-+
-+	case 'F':
-+	    if (!strcmp(cmd.s, "Fetch")) {
-+		if (!backend_current) goto nomailbox;
-+		usinguid =3D 0;
-+		if (c !=3D ' ') goto missingargs;
-+	    fetch:
-+		c =3D getword(proxyd_in, &arg1);
-+		if (c =3D=3D '\r') goto missingargs;
-+		if (c !=3D ' ' || !imparse_issequence(arg1.s)) goto badsequence;
-+		cmd_fetch(tag.s, arg1.s, usinguid);
-+	    }
-+	    else if (!strcmp(cmd.s, "Find")) {
-+		c =3D getword(proxyd_in, &arg1);
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg2);
-+		if (c =3D=3D EOF) goto missingargs;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_find(tag.s, arg1.s, arg2.s);
-+	    }
-+	    else goto badcmd;
-+	    break;
-+
-+	case 'G':
-+	    if (!strcmp(cmd.s, "Getacl")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c =3D=3D EOF) goto missingargs;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_getacl(tag.s, arg1.s);
-+	    }
-+	    else if (!strcmp(cmd.s, "Getannotation")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c !=3D ' ') goto missingargs;
-+
-+		cmd_getannotation(tag.s, arg1.s);
-+
-+		snmp_increment(GETANNOTATION_COUNT, 1);
-+	    }
-+	    else if (!strcmp(cmd.s, "Getquota")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c =3D=3D EOF) goto missingargs;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_getquota(tag.s, arg1.s);
-+	    }
-+	    else if (!strcmp(cmd.s, "Getquotaroot")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c =3D=3D EOF) goto missingargs;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_getquotaroot(tag.s, arg1.s);
-+	    }
-+	    else goto badcmd;
-+	    break;
-+
-+	case 'I':
-+	    if (!strcmp(cmd.s, "Id")) {
-+		if (c !=3D ' ') goto missingargs;
-+		cmd_id(tag.s);
-+	    }
-+	    else if (!proxyd_userid) goto nologin;
-+	    else if (!strcmp(cmd.s, "Idle")) {
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_idle(tag.s);
-+	    }
-+	    else goto badcmd;
-+	    break;
-+
-+	case 'L':
-+	    if (!strcmp(cmd.s, "Login")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if(c !=3D ' ') goto missingargs;
-+
-+		cmd_login(tag.s, arg1.s);
-+	    }
-+	    else if (!strcmp(cmd.s, "Logout")) {
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		=

-+		prot_printf(proxyd_out, =

-+			    "* BYE %s\r\n", error_message(IMAP_BYE_LOGOUT));
-+		prot_printf(proxyd_out, "%s OK %s\r\n", =

-+			    tag.s, error_message(IMAP_OK_COMPLETED));
-+
-+		return;
-+	    }
-+	    else if (!proxyd_userid) goto nologin;
-+	    else if (!strcmp(cmd.s, "List")) {
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg2);
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_list(tag.s, proxyd_magicplus ? LIST_SUBSCRIBED : 0,
-+			 arg1.s, arg2.s);
-+	    }
-+	    else if (!strcmp(cmd.s, "Lsub")) {
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg2);
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_list(tag.s, 1, arg1.s, arg2.s);
-+	    }
-+	    else if (!strcmp(cmd.s, "Listrights")) {
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg2);
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_listrights(tag.s, arg1.s, arg2.s);
-+	    }
-+	    else goto badcmd;
-+	    break;
-+
-+	case 'M':
-+	    if (!strcmp(cmd.s, "Myrights")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c =3D=3D EOF) goto missingargs;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_myrights(tag.s, arg1.s);
-+	    }
-+	    else goto badcmd;
-+	    break;
-+
-+	case 'N':
-+	    if (!strcmp(cmd.s, "Noop")) {
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_noop(tag.s, cmd.s);
-+	    }
-+#ifdef ENABLE_X_NETSCAPE_HACK
-+	    else if (!strcmp(cmd.s, "Netscape")) {
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_netscape(tag.s);
-+	    }
-+#endif
-+	    else if (!proxyd_userid) goto nologin;
-+	    else if (!strcmp(cmd.s, "Namespace")) {
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_namespace(tag.s);
-+	    }
-+	    else goto badcmd;
-+	    break;
-+
-+	case 'P':
-+	    if (!strcmp(cmd.s, "Partial")) {
-+		if (!backend_current) goto nomailbox;
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getword(proxyd_in, &arg1);
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getword(proxyd_in, &arg2);
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getword(proxyd_in, &arg3);
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getword(proxyd_in, &arg4);
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_partial(tag.s, arg1.s, arg2.s, arg3.s, arg4.s);
-+	    }
-+	    else goto badcmd;
-+	    break;
-+
-+	case 'R':
-+	    if (!strcmp(cmd.s, "Rename")) {
-+		havepartition =3D 0;
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg2);
-+		if (c =3D=3D EOF) goto missingargs;
-+		if (c =3D=3D ' ') {
-+		    havepartition =3D 1;
-+		    c =3D getword(proxyd_in, &arg3);
-+		    if (!imparse_isatom(arg3.s)) goto badpartition;
-+		}
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_rename(tag.s, arg1.s, arg2.s, havepartition ? arg3.s : 0);
-+	    }
-+	    else if (!strcmp(cmd.s, "Rlist")) {
-+		supports_referrals =3D !disable_referrals;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg2);
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_list(tag.s, 0, arg1.s, arg2.s);
-+	    }
-+	    else if (!strcmp(cmd.s, "Rlsub")) {
-+		supports_referrals =3D !disable_referrals;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg2);
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_list(tag.s, 1, arg1.s, arg2.s);
-+	    } else if(!strcmp(cmd.s, "Reconstruct")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if(c =3D=3D ' ') {
-+		    /* Optional RECURSEIVE argument */
-+		    c =3D getword(proxyd_in, &arg2);
-+		    if(!imparse_isatom(arg2.s))
-+			goto extraargs;
-+		    else if(strcasecmp(arg2.s, "RECURSIVE"))
-+			goto extraargs;
-+		    /* we ignore the argument, because proxyd does not care */
-+		}
-+		if(c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if(c !=3D '\n') goto extraargs;
-+		cmd_reconstruct(tag.s, arg1.s);
-+	    }
-+	    else goto badcmd;
-+	    break;
-+	    =

-+	case 'S':
-+	    if (!strcmp(cmd.s, "Starttls")) {
-+		if (!tls_enabled()) {
-+		    /* we don't support starttls */
-+		    goto badcmd;
-+		}
-+
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+
-+		/* if we've already done SASL fail */
-+		if (proxyd_userid !=3D NULL) {
-+		    prot_printf(proxyd_out, =

-+		     "%s BAD Can't Starttls after authentication\r\n", tag.s);
-+		    continue;
-+		}
-+		=

-+		/* check if already did a successful tls */
-+		if (proxyd_starttls_done =3D=3D 1) {
-+		    prot_printf(proxyd_out, =

-+				"%s BAD Already did a successful Starttls\r\n",
-+				tag.s);
-+		    continue;
-+		}
-+		cmd_starttls(tag.s, 0);	=

-+
-+		continue;
-+	    }
-+
-+	    if (!proxyd_userid) {
-+		goto nologin;
-+	    } else if (!strcmp(cmd.s, "Store")) {
-+		if (!backend_current) goto nomailbox;
-+		usinguid =3D 0;
-+		if (c !=3D ' ') goto missingargs;
-+	    store:
-+		c =3D getword(proxyd_in, &arg1);
-+		if (c !=3D ' ' || !imparse_issequence(arg1.s)) goto badsequence;
-+		c =3D getword(proxyd_in, &arg2);
-+		if (c !=3D ' ') goto badsequence;
-+		cmd_store(tag.s, arg1.s, arg2.s, usinguid);
-+	    }
-+	    else if (!strcmp(cmd.s, "Select")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c =3D=3D EOF) goto missingargs;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+
-+		cmd_select(tag.s, cmd.s, arg1.s);
-+	    }
-+	    else if (!strcmp(cmd.s, "Search")) {
-+		if (!backend_current) goto nomailbox;
-+		usinguid =3D 0;
-+		if (c !=3D ' ') goto missingargs;
-+	    search:
-+		cmd_search(tag.s, usinguid);
-+	    }
-+	    else if (!strcmp(cmd.s, "Subscribe")) {
-+		if (c !=3D ' ') goto missingargs;
-+		havenamespace =3D 0;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c =3D=3D ' ') {
-+		    havenamespace =3D 1;
-+		    c =3D getastring(proxyd_in, proxyd_out, &arg2);
-+		}
-+		if (c =3D=3D EOF) goto missingargs;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		if (havenamespace) {
-+		    cmd_changesub(tag.s, arg1.s, arg2.s, 1);
-+		}
-+		else {
-+		    cmd_changesub(tag.s, (char *)0, arg1.s, 1);
-+		}
-+	    }		=

-+	    else if (!strcmp(cmd.s, "Setacl")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg2);
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg3);
-+		if (c =3D=3D EOF) goto missingargs;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_setacl(tag.s, arg1.s, arg2.s, arg3.s);
-+	    }
-+	    else if (!strcmp(cmd.s, "Setannotation")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c !=3D ' ') goto missingargs;
-+
-+		cmd_setannotation(tag.s, arg1.s);
-+	    }
-+	    else if (!strcmp(cmd.s, "Setquota")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c !=3D ' ') goto missingargs;
-+		cmd_setquota(tag.s, arg1.s);
-+	    }
-+	    else if (!strcmp(cmd.s, "Sort")) {
-+		if (!backend_current) goto nomailbox;
-+		usinguid =3D 0;
-+		if (c !=3D ' ') goto missingargs;
-+	    sort:
-+		cmd_sort(tag.s, usinguid);
-+	    }
-+	    else if (!strcmp(cmd.s, "Status")) {
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c !=3D ' ') goto missingargs;
-+		cmd_status(tag.s, arg1.s);
-+	    }
-+	    else goto badcmd;
-+	    break;
-+
-+	case 'T':
-+	    if (!strcmp(cmd.s, "Thread")) {
-+		if (!backend_current) goto nomailbox;
-+		usinguid =3D 0;
-+		if (c !=3D ' ') goto missingargs;
-+	    thread:
-+		cmd_thread(tag.s, usinguid);
-+	    }
-+	    else goto badcmd;
-+	    break;
-+
-+	case 'U':
-+	    if (!strcmp(cmd.s, "Uid")) {
-+		if (!backend_current) goto nomailbox;
-+		usinguid =3D 1;
-+		if (c !=3D ' ') goto missingargs;
-+		c =3D getword(proxyd_in, &arg1);
-+		if (c !=3D ' ') goto missingargs;
-+		lcase(arg1.s);
-+		if (!strcmp(arg1.s, "fetch")) {
-+		    goto fetch;
-+		}
-+		else if (!strcmp(arg1.s, "store")) {
-+		    goto store;
-+		}
-+		else if (!strcmp(arg1.s, "search")) {
-+		    goto search;
-+		}
-+		else if (!strcmp(arg1.s, "sort")) {
-+		    goto sort;
-+		}
-+		else if (!strcmp(arg1.s, "thread")) {
-+		    goto thread;
-+		}
-+		else if (!strcmp(arg1.s, "copy")) {
-+		    goto copy;
-+		}
-+		else if (!strcmp(arg1.s, "expunge")) {
-+		    c =3D getword(proxyd_in, &arg1);
-+		    if (!imparse_issequence(arg1.s)) goto badsequence;
-+		    if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		    if (c !=3D '\n') goto extraargs;
-+		    cmd_expunge(tag.s, arg1.s);
-+		}
-+		else {
-+		    prot_printf(proxyd_out, =

-+				"%s BAD Unrecognized UID subcommand\r\n", =

-+				tag.s);
-+		    eatline(proxyd_in, c);
-+		}
-+	    }
-+	    else if (!strcmp(cmd.s, "Unsubscribe")) {
-+		if (c !=3D ' ') goto missingargs;
-+		havenamespace =3D 0;
-+		c =3D getastring(proxyd_in, proxyd_out, &arg1);
-+		if (c =3D=3D ' ') {
-+		    havenamespace =3D 1;
-+		    c =3D getastring(proxyd_in, proxyd_out, &arg2);
-+		}
-+		if (c =3D=3D EOF) goto missingargs;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		if (havenamespace) {
-+		    cmd_changesub(tag.s, arg1.s, arg2.s, 0);
-+		}
-+		else {
-+		    cmd_changesub(tag.s, (char *)0, arg1.s, 0);
-+		}
-+	    }		=

-+	    else if (!strcmp(cmd.s, "Unselect")) {
-+		if (!backend_current) goto nomailbox;
-+		if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+		if (c !=3D '\n') goto extraargs;
-+		cmd_unselect(tag.s);
-+	    }
-+	    else goto badcmd;
-+	    break;
-+
-+	default:
-+	badcmd:
-+	    prot_printf(proxyd_out, "%s BAD Unrecognized command\r\n", tag.s);
-+	    eatline(proxyd_in, c);
-+	}
-+
-+	continue;
-+
-+    nologin:
-+	prot_printf(proxyd_out, "%s BAD Please login first\r\n", tag.s);
-+	eatline(proxyd_in, c);
-+	continue;
-+
-+    nomailbox:
-+	prot_printf(proxyd_out, "%s BAD Please select a mailbox first\r\n", =

-+		    tag.s);
-+	eatline(proxyd_in, c);
-+	continue;
-+
-+    missingargs:
-+	prot_printf(proxyd_out, "%s BAD Missing required argument to %s\r\n", =

-+		    tag.s, cmd.s);
-+	eatline(proxyd_in, c);
-+	continue;
-+
-+    extraargs:
-+	prot_printf(proxyd_out, "%s BAD Unexpected extra arguments to %s\r\n",
-+		    tag.s, cmd.s);
-+	eatline(proxyd_in, c);
-+	continue;
-+
-+    badsequence:
-+	prot_printf(proxyd_out, "%s BAD Invalid sequence in %s\r\n", =

-+		    tag.s, cmd.s);
-+	eatline(proxyd_in, c);
-+	continue;
-+
-+    badpartition:
-+	prot_printf(proxyd_out, "%s BAD Invalid partition name in %s\r\n",
-+		    tag.s, cmd.s);
-+	eatline(proxyd_in, c);
-+	continue;
-+    }
-+}
-+
-+/*
-+ * Perform a LOGIN command
-+ */
-+void cmd_login(char *tag, char *user)
-+{
-+    char userbuf[MAX_MAILBOX_NAME+1], *canon_user =3D userbuf;
-+    unsigned userlen;
-+    char c;
-+    struct buf passwdbuf;
-+    char *passwd;
-+    char *reply =3D 0;
-+    int r;
-+
-+    if (proxyd_userid) {
-+	eatline(proxyd_in, ' ');
-+	prot_printf(proxyd_out, "%s BAD Already logged in\r\n", tag);
-+	return;
-+    }
-+
-+    r =3D proxyd_canon_user(proxyd_saslconn, &disable_referrals, user, 0,
-+			  SASL_CU_AUTHID | SASL_CU_AUTHZID, NULL,
-+			  userbuf, sizeof(userbuf), &userlen);
-+
-+    if (r) {
-+	syslog(LOG_NOTICE, "badlogin: %s plaintext %s invalid user",
-+	       proxyd_clienthost, beautify_string(user));
-+	prot_printf(proxyd_out, "%s NO %s\r\n", tag, =

-+		    error_message(IMAP_INVALID_USER));
-+	return;
-+    }
-+
-+    /* possibly disallow login */
-+    if ((proxyd_starttls_done =3D=3D 0) &&
-+	(config_getswitch(IMAPOPT_ALLOWPLAINTEXT) =3D=3D 0) &&
-+	strcmp(canon_user, "anonymous") !=3D 0) {
-+	eatline(proxyd_in, ' ');
-+	prot_printf(proxyd_out, "%s NO Login only available under a layer\r\n",
-+		    tag);
-+	return;
-+    }
-+
-+    memset(&passwdbuf,0,sizeof(struct buf));
-+    c =3D getastring(proxyd_in, proxyd_out, &passwdbuf);
-+
-+    if(c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+    if (c !=3D '\n') {
-+	freebuf(&passwdbuf);
-+	prot_printf(proxyd_out,
-+		    "%s BAD Unexpected extra arguments to LOGIN\r\n",
-+		    tag);
-+	eatline(proxyd_in, c);
-+	return;
-+    }
-+
-+    passwd =3D passwdbuf.s;
-+
-+    if (!strcmp(canon_user, "anonymous")) {
-+	if (config_getswitch(IMAPOPT_ALLOWANONYMOUSLOGIN)) {
-+	    passwd =3D beautify_string(passwd);
-+	    if (strlen(passwd) > 500) passwd[500] =3D '\0';
-+	    syslog(LOG_NOTICE, "login: %s anonymous %s",
-+		   proxyd_clienthost, passwd);
-+	    reply =3D "Anonymous access granted";
-+	    proxyd_userid =3D xstrdup("anonymous");
-+	}
-+	else {
-+	    syslog(LOG_NOTICE, "badlogin: %s anonymous login refused",
-+		   proxyd_clienthost);
-+	    prot_printf(proxyd_out, "%s NO %s\r\n", tag,
-+		   error_message(IMAP_ANONYMOUS_NOT_PERMITTED));
-+	    freebuf(&passwdbuf);
-+	    return;
-+	}
-+    }
-+    else if ( nosaslpasswdcheck ) {
-+        /* bypassing sasl_checkpass() */
-+        proxyd_userid =3D xstrdup(canon_user);
-+        syslog( LOG_NOTICE, "bypassing sasl_checkpass()" );  =

-+    }
-+    else if ((r =3D sasl_checkpass(proxyd_saslconn,
-+				 canon_user,
-+				 strlen(canon_user),
-+				 passwd,
-+				 strlen(passwd)))!=3DSASL_OK) {
-+	const char *errorstring =3D sasl_errstring(r, NULL, NULL);
-+	if (reply) {
-+	    syslog(LOG_NOTICE, "badlogin: %s plaintext %s %s",
-+		   proxyd_clienthost, canon_user, reply);
-+	}
-+	/* Apply penalty only if not under layer */
-+	if (proxyd_starttls_done =3D=3D 0)
-+	    sleep(3);
-+	if (errorstring) {
-+	    prot_printf(proxyd_out, "%s NO Login failed: %s\r\n", =

-+			tag, errorstring);
-+	} else {
-+	    prot_printf(proxyd_out, "%s NO Login failed.", tag);
-+	}
-+	freebuf(&passwdbuf);
-+	return;
-+    }
-+    else {
-+	proxyd_userid =3D xstrdup(canon_user);
-+
-+	syslog(LOG_NOTICE, "login: %s %s%s plaintext%s %s", proxyd_clienthost,
-+	       proxyd_userid, proxyd_magicplus ? proxyd_magicplus : "",
-+	       proxyd_starttls_done ? "+TLS" : "", =

-+	       reply ? reply : "");
-+
-+	/* Apply penalty only if not under layer */
-+	if (!proxyd_starttls_done) {
-+	    int plaintextloginpause =3D config_getint(IMAPOPT_PLAINTEXTLOGINPAUS=
E);
-+	    if (plaintextloginpause) {
-+		sleep(plaintextloginpause);
-+	    }
-+
-+	    /* Fetch plaintext login nag message */
-+	    plaintextloginalert =3D config_getstring(IMAPOPT_PLAINTEXTLOGINALERT=
);
-+	}
-+    }
-+    =

-+    proxyd_authstate =3D auth_newstate(proxyd_userid);
-+
-+    proxyd_userisadmin =3D global_authisa(proxyd_authstate, IMAPOPT_ADMIN=
S);
-+
-+    if (!reply) reply =3D "User logged in";
-+
-+    prot_printf(proxyd_out, "%s OK %s\r\n", tag, reply);
-+
-+    /* Create telemetry log */
-+    proxyd_logfd =3D telemetry_log(proxyd_userid, proxyd_in, proxyd_out, =
0);
-+
-+    /* Set namespace */
-+    if ((r =3D mboxname_init_namespace(&proxyd_namespace, proxyd_userisad=
min)) !=3D 0) {
-+	syslog(LOG_ERR, error_message(r));
-+	fatal(error_message(r), EC_CONFIG);
-+    }
-+
-+    /* Translate any separators in userid */
-+    mboxname_hiersep_tointernal(&proxyd_namespace, proxyd_userid,
-+				config_virtdomains ?
-+				strcspn(proxyd_userid, "@") : 0);
-+
-+    freebuf(&passwdbuf);
-+    return;
-+}
-+
-+/*
-+ * Perform an AUTHENTICATE command
-+ */
-+void cmd_authenticate(char *tag, char *authtype, char *resp)
-+{
-+    int sasl_result;
-+    const char *canon_user;
-+    =

-+    const int *ssfp;
-+    char *ssfmsg=3DNULL;
-+
-+    int r;
-+
-+    r =3D saslserver(proxyd_saslconn, authtype, resp, "", "+ ", "",
-+		   proxyd_in, proxyd_out, &sasl_result, NULL);
-+
-+    if (r) {
-+	const char *errorstring =3D NULL;
-+
-+	switch (r) {
-+	case IMAP_SASL_CANCEL:
-+	    prot_printf(proxyd_out,
-+			"%s BAD Client canceled authentication\r\n", tag);
-+	    break;
-+	case IMAP_SASL_PROTERR:
-+	    errorstring =3D prot_error(proxyd_in);
-+
-+	    prot_printf(proxyd_out,
-+			"%s NO Error reading client response: %s\r\n",
-+			tag, errorstring ? errorstring : "");
-+	    break;
-+	default: =

-+	    /* failed authentication */
-+	    errorstring =3D sasl_errstring(sasl_result, NULL, NULL);
-+
-+	    syslog(LOG_NOTICE, "badlogin: %s %s [%s]",
-+		   proxyd_clienthost, authtype, sasl_errdetail(proxyd_saslconn));
-+
-+	    snmp_increment_args(AUTHENTICATION_NO, 1,
-+				VARIABLE_AUTH, 0, /* hash_simple(authtype) */ =

-+				VARIABLE_LISTEND);
-+	    sleep(3);
-+
-+	    if (errorstring) {
-+		prot_printf(proxyd_out, "%s NO %s\r\n", tag, errorstring);
-+	    } else {
-+		prot_printf(proxyd_out, "%s NO Error authenticating\r\n", tag);
-+	    }
-+	}
-+
-+	reset_saslconn(&proxyd_saslconn);
-+	return;
-+    }
-+
-+    /* successful authentication */
-+
-+    /* get the userid from SASL --- already canonicalized from
-+     * mysasl_proxy_policy()
-+     */
-+    sasl_result =3D sasl_getprop(proxyd_saslconn, SASL_USERNAME,
-+			       (const void **)&canon_user);
-+
-+    if (sasl_result!=3DSASL_OK)
-+    {
-+	prot_printf(proxyd_out, "%s NO weird SASL error %d SASL_USERNAME\r\n", =

-+		    tag, sasl_result);
-+	syslog(LOG_ERR, "weird SASL error %d getting SASL_USERNAME", =

-+	       sasl_result);
-+	reset_saslconn(&proxyd_saslconn);
-+	return;
-+    }
-+
-+    /* If we're proxying, the authzid may contain a magic plus,
-+       so re-canonify it */
-+    if (config_getswitch(IMAPOPT_IMAPMAGICPLUS) && strchr(canon_user, '+'=
)) {
-+	char userbuf[MAX_MAILBOX_NAME+1];
-+	unsigned userlen;
-+
-+	sasl_result =3D proxyd_canon_user(proxyd_saslconn, NULL, canon_user, 0,
-+					SASL_CU_AUTHID | SASL_CU_AUTHZID,
-+					NULL, userbuf, sizeof(userbuf), &userlen);
-+	if (sasl_result !=3D SASL_OK) {
-+	    prot_printf(proxyd_out, =

-+			"%s NO SASL canonification error %d\r\n", =

-+			tag, sasl_result);
-+	    reset_saslconn(&proxyd_saslconn);
-+	    return;
-+	}
-+
-+	proxyd_userid =3D xstrdup(userbuf);
-+    } else {
-+	proxyd_userid =3D xstrdup(canon_user);
-+    }
-+
-+    proc_register("proxyd", proxyd_clienthost, proxyd_userid, (char *)0);
-+
-+    syslog(LOG_NOTICE, "login: %s %s%s %s%s %s", proxyd_clienthost,
-+	   proxyd_userid, proxyd_magicplus ? proxyd_magicplus : "",
-+	   authtype, proxyd_starttls_done ? "+TLS" : "", "User logged in");
-+
-+    sasl_getprop(proxyd_saslconn, SASL_SSF, (const void **) &ssfp);
-+
-+    if (proxyd_starttls_done) {
-+	switch(*ssfp) {
-+	case 0: ssfmsg =3D "tls protection"; break;
-+	case 1: ssfmsg =3D "tls plus integrity protection"; break;
-+	default: ssfmsg =3D "tls plus privacy protection"; break;
-+	}
-+    } else {
-+	switch(*ssfp) {
-+	case 0: ssfmsg=3D"no protection"; break;
-+	case 1: ssfmsg=3D"integrity protection"; break;
-+	default: ssfmsg=3D"privacy protection"; break;
-+	}
-+    }
-+
-+    prot_printf(proxyd_out, "%s OK Success (%s)\r\n", tag,ssfmsg);
-+    prot_flush(proxyd_out);
-+
-+    prot_setsasl(proxyd_in,  proxyd_saslconn);
-+    prot_setsasl(proxyd_out, proxyd_saslconn);
-+
-+    /* Create telemetry log */
-+    proxyd_logfd =3D telemetry_log(proxyd_userid, proxyd_in, proxyd_out, =
0);
-+
-+    /* Set namespace */
-+    if ((r =3D mboxname_init_namespace(&proxyd_namespace, proxyd_userisad=
min)) !=3D 0) {
-+	syslog(LOG_ERR, error_message(r));
-+	fatal(error_message(r), EC_CONFIG);
-+    }
-+
-+    /* Translate any separators in userid */
-+    mboxname_hiersep_tointernal(&proxyd_namespace, proxyd_userid,
-+				config_virtdomains ?
-+				strcspn(proxyd_userid, "@") : 0);
-+
-+    return;
-+}
-+
-+/*
-+ * Perform a NOOP command
-+ */
-+void cmd_noop(char *tag, char *cmd)
-+{
-+    if (backend_current) {
-+	prot_printf(backend_current->out, "%s %s\r\n", tag, cmd);
-+	pipe_including_tag(backend_current, tag, 0);
-+    } else {
-+	prot_printf(proxyd_out, "%s OK %s\r\n", tag,
-+		    error_message(IMAP_OK_COMPLETED));
-+    }
-+}
-+
-+/*
-+ * Parse and perform an ID command.
-+ *
-+ * the command has been parsed up to the parameter list.
-+ *
-+ * we only allow one ID in non-authenticated state from a given client.
-+ * we only allow MAXIDFAILED consecutive failed IDs from a given client.
-+ * we only record MAXIDLOG ID responses from a given client.
-+ */
-+void cmd_id(char *tag)
-+{
-+    static int did_id =3D 0;
-+    static int failed_id =3D 0;
-+    static int logged_id =3D 0;
-+    int error =3D 0;
-+    int c =3D EOF, npair =3D 0;
-+    static struct buf arg, field;
-+    struct idparamlist *params =3D 0;
-+
-+    /* check if we've already had an ID in non-authenticated state */
-+    if (!proxyd_userid && did_id) {
-+	prot_printf(proxyd_out,
-+		    "%s NO Only one Id allowed in non-authenticated state\r\n",
-+		    tag);
-+	eatline(proxyd_in, c);
-+	return;
-+    }
-+
-+    /* check if we've had too many failed IDs in a row */
-+    if (failed_id >=3D MAXIDFAILED) {
-+	prot_printf(proxyd_out, "%s NO Too many (%u) invalid Id commands\r\n",
-+		    tag, failed_id);
-+	eatline(proxyd_in, c);
-+	return;
-+    }
-+
-+    /* ok, accept parameter list */
-+    c =3D getword(proxyd_in, &arg);
-+    /* check for "NIL" or start of parameter list */
-+    if (strcasecmp(arg.s, "NIL") && c !=3D '(') {
-+	prot_printf(proxyd_out, "%s BAD Invalid parameter list in Id\r\n", tag);
-+	eatline(proxyd_in, c);
-+	failed_id++;
-+	return;
-+    }
-+
-+    /* parse parameter list */
-+    if (c =3D=3D '(') {
-+	for (;;) {
-+	    if (c =3D=3D ')') {
-+		/* end of string/value pairs */
-+		break;
-+	    }
-+
-+	    /* get field name */
-+	    c =3D getstring(proxyd_in, proxyd_out, &field);
-+	    if (c !=3D ' ') {
-+		prot_printf(proxyd_out,
-+			    "%s BAD Invalid/missing field name in Id\r\n",
-+			    tag);
-+		error =3D 1;
-+		break;
-+	    }
-+
-+	    /* get field value */
-+	    c =3D getnstring(proxyd_in, proxyd_out, &arg);
-+	    if (c !=3D ' ' && c !=3D ')') {
-+		prot_printf(proxyd_out,
-+			    "%s BAD Invalid/missing value in Id\r\n",
-+			    tag);
-+		error =3D 1;
-+		break;
-+	    }
-+
-+	    /* ok, we're anal, but we'll still process the ID command */
-+	    if (strlen(field.s) > MAXIDFIELDLEN) {
-+		prot_printf(proxyd_out, =

-+			    "%s BAD field longer than %u octets in Id\r\n",
-+			    tag, MAXIDFIELDLEN);
-+		error =3D 1;
-+		break;
-+	    }
-+	    if (strlen(arg.s) > MAXIDVALUELEN) {
-+		prot_printf(proxyd_out,
-+			    "%s BAD value longer than %u octets in Id\r\n",
-+			    tag, MAXIDVALUELEN);
-+		error =3D 1;
-+		break;
-+	    }
-+	    if (++npair > MAXIDPAIRS) {
-+		prot_printf(proxyd_out,
-+			    "%s BAD too many (%u) field-value pairs in ID\r\n",
-+			    tag, MAXIDPAIRS);
-+		error =3D 1;
-+		break;
-+	    }
-+	    =

-+	    /* ok, we're happy enough */
-+	    id_appendparamlist(&params, field.s, arg.s);
-+	}
-+
-+	if (error || c !=3D ')') {
-+	    /* erp! */
-+	    eatline(proxyd_in, c);
-+	    id_freeparamlist(params);
-+	    failed_id++;
-+	    return;
-+	}
-+	c =3D prot_getc(proxyd_in);
-+    }
-+
-+    /* check for CRLF */
-+    if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+    if (c !=3D '\n') {
-+	prot_printf(proxyd_out,
-+		    "%s BAD Unexpected extra arguments to Id\r\n", tag);
-+	eatline(proxyd_in, c);
-+	id_freeparamlist(params);
-+	failed_id++;
-+	return;
-+    }
-+
-+    /* log the client's ID string.
-+       eventually this should be a callback or something. */
-+    if (npair && logged_id < MAXIDLOG) {
-+	char logbuf[MAXIDLOGLEN + 1] =3D "";
-+	struct idparamlist *pptr;
-+
-+	for (pptr =3D params; pptr; pptr =3D pptr->next) {
-+	    /* should we check for and format literals here ??? */
-+	    snprintf(logbuf + strlen(logbuf), MAXIDLOGLEN - strlen(logbuf),
-+		     " \"%s\" ", pptr->field);
-+	    if (!strcmp(pptr->value, "NIL"))
-+		snprintf(logbuf + strlen(logbuf), MAXIDLOGLEN - strlen(logbuf),
-+			 "NIL");
-+	    else
-+		snprintf(logbuf + strlen(logbuf), MAXIDLOGLEN - strlen(logbuf),
-+			"\"%s\"", pptr->value);
-+	}
-+
-+	syslog(LOG_INFO, "client id:%s", logbuf);
-+
-+	logged_id++;
-+    }
-+
-+    id_freeparamlist(params);
-+
-+    /* spit out our ID string.
-+       eventually this might be configurable. */
-+    if (config_getswitch(IMAPOPT_IMAPIDRESPONSE)) {
-+	id_response(proxyd_out);
-+
-+	/* add info about the backend */
-+	if (backend_current)
-+	    prot_printf(proxyd_out, " \"backend-url\" \"imap://%s\"",
-+			backend_current->hostname);
-+	else
-+	    prot_printf(proxyd_out, " \"backend-url\" NIL");
-+
-+	prot_printf(proxyd_out, ")\r\n");
-+    }
-+    else
-+	prot_printf(proxyd_out, "* ID NIL\r\n");
-+
-+    prot_printf(proxyd_out, "%s OK %s\r\n", tag,
-+		error_message(IMAP_OK_COMPLETED));
-+
-+    failed_id =3D 0;
-+    did_id =3D 1;
-+}
-+
-+/*
-+ * Append the 'field' / 'value' pair to the idparamlist 'l'.
-+ */
-+void id_appendparamlist(struct idparamlist **l, char *field, char *value)
-+{
-+    struct idparamlist **tail =3D l;
-+
-+    while (*tail) tail =3D &(*tail)->next;
-+
-+    *tail =3D (struct idparamlist *)xmalloc(sizeof(struct idparamlist));
-+    (*tail)->field =3D xstrdup(field);
-+    (*tail)->value =3D xstrdup(value);
-+    (*tail)->next =3D 0;
-+}
-+
-+/*
-+ * Free the idparamlist 'l'
-+ */
-+void id_freeparamlist(struct idparamlist *l)
-+{
-+    struct idparamlist *n;
-+
-+    while (l) {
-+	n =3D l->next;
-+	free(l->field);
-+	free(l->value);
-+	l =3D n;
-+    }
-+}
-+
-+/*
-+ * Perform an IDLE command
-+ */
-+void cmd_idle(char *tag)
-+{
-+    static int idle_period =3D -1;
-+    static struct buf arg;
-+    struct protgroup *protin =3D protgroup_new(2);
-+    struct protgroup *protout =3D NULL;
-+    struct timeval timeout;
-+    int c =3D EOF, n, done =3D 0, shutdown =3D 0;
-+    char buf[2048], shut[1024];
-+
-+    /* get polling period */
-+    if (idle_period =3D=3D -1) {
-+      idle_period =3D config_getint(IMAPOPT_IMAPIDLEPOLL);
-+      if (idle_period < 1) idle_period =3D 0;
-+    }
-+
-+    if (!idle_period) {
-+	/* IDLE has been disabled */
-+	prot_printf(proxyd_out, "%s BAD Unrecognized command\r\n", tag);
-+	return;
-+    }
-+
-+    /* Reset protin to all zeros (to preserve memory allocation) */
-+    protgroup_reset(protin);
-+    protgroup_insert(protin, proxyd_in);
-+
-+    if (backend_current && CAPA(backend_current, CAPA_IDLE)) {
-+	/* Start IDLE on backend */
-+	prot_printf(backend_current->out, "%s IDLE\r\n", tag);
-+	if (!prot_fgets(buf, sizeof(buf), backend_current->in)) {
-+
-+	    /* If we received nothing from the backend, fail */
-+	    prot_printf(proxyd_out, "%s NO %s\r\n", tag, =

-+			error_message(IMAP_SERVER_UNAVAILABLE));
-+	    goto done;
-+	}
-+	if (buf[0] !=3D '+') {
-+
-+	    /* If we received anything but a continuation response,
-+	       spit out what we received and quit */
-+	    prot_write(proxyd_out, buf, strlen(buf));
-+	    goto done;
-+	}
-+
-+	protgroup_insert(protin, backend_current->in);
-+    }
-+
-+    /* Tell client we are idling and waiting for end of command */
-+    prot_printf(proxyd_out, "+ go ahead\r\n");
-+    prot_flush(proxyd_out);
-+
-+    while (!done) {
-+	/* check for shutdown file */
-+	if (!proxyd_userisadmin && shutdown_file(shut, sizeof(shut))) {
-+	    shutdown =3D done =3D 1;
-+	    goto done;
-+	}
-+
-+	if (backend_current && !CAPA(backend_current, CAPA_IDLE)) {
-+	    /* Simulate IDLE by polling the backend */
-+	    char mytag[128];
-+	=

-+	    proxyd_gentag(mytag, sizeof(mytag));
-+	    prot_printf(backend_current->out, "%s Noop\r\n", mytag);
-+	    pipe_until_tag(backend_current, mytag, 0);
-+	    prot_flush(proxyd_out);
-+	}
-+
-+	/* Clear protout if needed */
-+	protgroup_free(protout);
-+	protout =3D NULL;
-+
-+	timeout.tv_sec =3D idle_period;
-+	timeout.tv_usec =3D 0;
-+
-+	n =3D prot_select(protin, PROT_NO_FD, &protout, NULL, &timeout);
-+	if (n =3D=3D -1) {
-+	    syslog(LOG_ERR, "prot_select() failed in cmd_idle(): %m");
-+	    fatal("prot_select() failed in cmd_idle()", EC_TEMPFAIL);
-+	}
-+	if (n && protout) {
-+	    struct protstream *ptmp;
-+
-+	    for (; n; n--) {
-+		ptmp =3D protgroup_getelement(protout, n-1);
-+		if (ptmp =3D=3D proxyd_in) {
-+		    /* The client sent us something, we're done */
-+		    done =3D 1;
-+		}
-+		else if (backend_current && ptmp =3D=3D backend_current->in) {
-+		    /* Get unsolicited untagged responses from the backend */
-+		    do {
-+			int c =3D prot_read(backend_current->in, buf, sizeof(buf));
-+			if (c =3D=3D 0 || c < 0) break;
-+			prot_write(proxyd_out, buf, c);
-+		    } while (backend_current->in->cnt > 0);
-+		    prot_flush(proxyd_out);
-+
-+		    if (prot_error(backend_current->in)) {
-+			/* uh oh, we're not happy */
-+			fatal("Lost connection to selected backend",
-+			      EC_UNAVAILABLE);
-+		    }
-+		}
-+		else {
-+		    /* XXX shouldn't get here !!! */
-+		    fatal("unknown protstream returned by prot_select in cmd_idle",
-+			  EC_SOFTWARE);
-+		}
-+	    }
-+	}
-+    }
-+
-+    /* Get continuation data */
-+    c =3D getword(proxyd_in, &arg);
-+
-+  done:
-+    protgroup_free(protin);
-+    protgroup_free(protout);
-+
-+    if (done && backend_current && CAPA(backend_current, CAPA_IDLE)) {
-+	/* Either the client timed out, or gave us a continuation,
-+	   or we found a shutdown file.  In any case we're done,
-+	   so terminate IDLE on backend */
-+	prot_printf(backend_current->out, "DONE\r\n");
-+	pipe_until_tag(backend_current, tag, 0);
-+    }
-+
-+    if (shutdown) {
-+	char *p;
-+
-+	for (p =3D shut; *p =3D=3D '['; p++); /* can't have [ be first char */
-+	prot_printf(proxyd_out, "* BYE [ALERT] %s\r\n", p);
-+	shut_down(0);
-+    }
-+
-+    if (c !=3D EOF) {
-+	if (!strcasecmp(arg.s, "Done") &&
-+	    (c =3D (c =3D=3D '\r') ? prot_getc(proxyd_in) : c) =3D=3D '\n') {
-+	    prot_printf(proxyd_out, "%s OK %s\r\n", tag,
-+			error_message(IMAP_OK_COMPLETED));
-+	}
-+	else {
-+	    prot_printf(proxyd_out, =

-+			"%s BAD Invalid Idle continuation\r\n", tag);
-+	    eatline(proxyd_in, c);
-+	}
-+    }
-+}
-+
-+/*
-+ * Perform a CAPABILITY command
-+ */
-+void cmd_capability(char *tag)
-+{
-+    const char *sasllist; /* the list of SASL mechanisms */
-+    int mechcount;
-+
-+    if (backend_current) {
-+	char mytag[128];
-+	=

-+	proxyd_gentag(mytag, sizeof(mytag));
-+	/* do i want to do a NOOP for every operation? */
-+	prot_printf(backend_current->out, "%s Noop\r\n", mytag);
-+	pipe_until_tag(backend_current, mytag, 0);
-+    }
-+    prot_printf(proxyd_out, "* CAPABILITY ");
-+    prot_printf(proxyd_out, CAPABILITY_STRING);
-+
-+    if (config_getint(IMAPOPT_IMAPIDLEPOLL) > 0) {
-+	prot_printf(proxyd_out, " IDLE");
-+    }
-+
-+    if (tls_enabled() && !proxyd_starttls_done && !proxyd_authstate) {
-+	prot_printf(proxyd_out, " STARTTLS");
-+    }
-+    if (proxyd_authstate ||
-+	(!proxyd_starttls_done && !config_getswitch(IMAPOPT_ALLOWPLAINTEXT))) {
-+	prot_printf(proxyd_out, " LOGINDISABLED");	=

-+    }
-+
-+    if (!proxyd_authstate &&
-+	sasl_listmech(proxyd_saslconn, NULL, =

-+		      "AUTH=3D", " AUTH=3D", " SASL-IR",
-+		      &sasllist,
-+		      NULL, &mechcount) =3D=3D SASL_OK && mechcount > 0) {
-+	prot_printf(proxyd_out, " %s", sasllist);      =

-+    } else {
-+	/* else don't show anything */
-+    }
-+
-+#ifdef ENABLE_X_NETSCAPE_HACK
-+    prot_printf(proxyd_out, " X-NETSCAPE");
-+#endif
-+
-+    prot_printf(proxyd_out, "\r\n");
-+
-+    prot_printf(proxyd_out, "%s OK %s\r\n", tag,
-+		error_message(IMAP_OK_COMPLETED));
-+}
-+
-+/*
-+ * Parse and perform an APPEND command.
-+ * The command has been parsed up to and including
-+ * the mailbox name.
-+ */
-+void cmd_append(char *tag, char *name)
-+{
-+    int r;
-+    char mailboxname[MAX_MAILBOX_PATH + 1];
-+    char *newserver;
-+    struct backend *s =3D NULL;
-+
-+    /* we want to pipeline this whole command through to the server that
-+       has name on it, and then do a noop on our current server */
-+    r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace, name,
-+						proxyd_userid, mailboxname);
-+
-+    if (!r) {
-+	r =3D mlookup(mailboxname, &newserver, NULL, NULL);
-+    }
-+    if (!r && supports_referrals) { =

-+	proxyd_refer(tag, newserver, name);
-+	/* Eat the argument */
-+	eatline(proxyd_in, prot_getc(proxyd_in));
-+	return;
-+    }
-+    if (!r) {
-+	s =3D proxyd_findserver(newserver);
-+	if (!s) r =3D IMAP_SERVER_UNAVAILABLE;
-+    }
-+    if (!r) {
-+	int is_active =3D 1;
-+	s->context =3D (void*) &is_active;
-+	prot_printf(s->out, "%s Append {%d+}\r\n%s ", tag, strlen(name), name);
-+	if (!(r =3D pipe_command(s, 16384))) {
-+	    pipe_until_tag(s, tag, 0);
-+	}
-+	s->context =3D NULL;
-+    } else {
-+	eatline(proxyd_in, prot_getc(proxyd_in));
-+    }
-+
-+    if (backend_current && backend_current !=3D s) {
-+	char mytag[128];
-+
-+	proxyd_gentag(mytag, sizeof(mytag));
-+	=

-+	prot_printf(backend_current->out, "%s Noop\r\n", mytag);
-+	pipe_until_tag(backend_current, mytag, 0);
-+    }
-+
-+    if (r) {
-+	prot_printf(proxyd_out, "%s NO %s\r\n", tag,
-+		    prot_error(proxyd_in) ? prot_error(proxyd_in) :
-+		    error_message(r));
-+    } else {
-+	/* we're allowed to reference last_result since the noop, if
-+	   sent, went to a different server */
-+	prot_printf(proxyd_out, "%s %s", tag, s->last_result.s);
-+    }
-+}
-+
-+/*
-+ * Perform a SELECT/EXAMINE/BBOARD command
-+ */
-+void cmd_select(char *tag, char *cmd, char *name)
-+{
-+    char mailboxname[MAX_MAILBOX_NAME+1];
-+    int r =3D 0;
-+    char *newserver;
-+    struct backend *backend_next =3D NULL;
-+
-+    if (cmd[0] =3D=3D 'B') {
-+	/* BBoard namespace is empty */
-+	r =3D IMAP_MAILBOX_NONEXISTENT;
-+    }
-+    else {
-+	r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace, name,
-+						    proxyd_userid, mailboxname);
-+    }
-+
-+    if (!r) r =3D mlookup(mailboxname, &newserver, NULL, NULL);
-+    if (!r && supports_referrals) { =

-+	proxyd_refer(tag, newserver, name);
-+	return;
-+    }
-+
-+    if (!r) {
-+	backend_next =3D proxyd_findserver(newserver);
-+	if (!backend_next) r =3D IMAP_SERVER_UNAVAILABLE;
-+    }
-+
-+    if (backend_current && backend_current !=3D backend_next) {
-+	char mytag[128];
-+
-+	/* switching servers; flush old server output */
-+	proxyd_gentag(mytag, sizeof(mytag));
-+	prot_printf(backend_current->out, "%s Unselect\r\n", mytag);
-+	/* do not fatal() here, because we don't really care about this
-+	 * server anymore anyway */
-+	pipe_until_tag(backend_current, mytag, 1);
-+    }
-+    backend_current =3D backend_next;
-+
-+    if (r) {
-+	prot_printf(proxyd_out, "%s NO %s\r\n", tag, error_message(r));
-+	return;
-+    }
-+
-+    prot_printf(backend_current->out, "%s %s {%d+}\r\n%s\r\n", tag, cmd, =

-+		strlen(name), name);
-+    switch (pipe_including_tag(backend_current, tag, 0)) {
-+    case PROXY_OK:
-+	proc_register("proxyd", proxyd_clienthost, proxyd_userid, mailboxname);
-+	syslog(LOG_DEBUG, "open: user %s opened %s on %s", proxyd_userid, name,
-+	       newserver);
-+	break;
-+    default:
-+	syslog(LOG_DEBUG, "open: user %s failed to open %s", proxyd_userid,
-+	       name);
-+	/* not successfully selected */
-+	backend_current =3D NULL;
-+	break;
-+    }
-+}
-+	  =

-+/*
-+ * Perform a CLOSE command
-+ */
-+void cmd_close(char *tag)
-+{
-+    assert(backend_current !=3D NULL);
-+    =

-+    prot_printf(backend_current->out, "%s Close\r\n", tag);
-+    /* xxx do we want this to say OK if the connection is gone?
-+     * saying NO is clearly wrong, hense the fatal request. */
-+    pipe_including_tag(backend_current, tag, 0);
-+    backend_current =3D NULL;
-+}
-+
-+/*
-+ * Perform an UNSELECT command -- for some support of IMAP proxy.
-+ * Just like close except no expunge.
-+ */
-+void cmd_unselect(char *tag)
-+{
-+    assert(backend_current !=3D NULL);
-+
-+    prot_printf(backend_current->out, "%s Unselect\r\n", tag);
-+    /* xxx do we want this to say OK if the connection is gone?
-+     * saying NO is clearly wrong, hense the fatal request. */
-+    pipe_including_tag(backend_current, tag, 0);
-+    backend_current =3D NULL;
-+}
-+
-+/*
-+ * Parse and perform a FETCH/UID FETCH command
-+ * The command has been parsed up to and including
-+ * the sequence
-+ */
-+void cmd_fetch(char *tag, char *sequence, int usinguid)
-+{
-+    char *cmd =3D usinguid ? "UID Fetch" : "Fetch";
-+
-+    assert(backend_current !=3D NULL);
-+
-+    prot_printf(backend_current->out, "%s %s %s ", tag, cmd, sequence);
-+    if (!pipe_command(backend_current, 65536)) {
-+	pipe_including_tag(backend_current, tag, 0);
-+    }
-+}
-+
-+/*
-+ * Perform a PARTIAL command
-+ */
-+void cmd_partial(char *tag, char *msgno, char *data, char *start, char *c=
ount)
-+{
-+    assert(backend_current !=3D NULL);
-+
-+    prot_printf(backend_current->out, "%s Partial %s %s %s %s\r\n",
-+		tag, msgno, data, start, count);
-+    pipe_including_tag(backend_current, tag, 0);
-+}
-+
-+/*
-+ * Parse and perform a STORE/UID STORE command
-+ * The command has been parsed up to and including
-+ * the FLAGS/+FLAGS/-FLAGS
-+ */
-+void cmd_store(char *tag, char *sequence, char *operation, int usinguid)
-+{
-+    const char *cmd =3D usinguid ? "UID Store" : "Store";
-+
-+    assert(backend_current !=3D NULL);
-+
-+    prot_printf(backend_current->out, "%s %s %s %s ",
-+		tag, cmd, sequence, operation);
-+    if (!pipe_command(backend_current, 65536)) {
-+	pipe_including_tag(backend_current, tag, 0);
-+    }
-+}
-+
-+void cmd_search(char *tag, int usinguid)
-+{
-+    const char *cmd =3D usinguid ? "UID Search" : "Search";
-+
-+    assert(backend_current !=3D NULL);
-+
-+    prot_printf(backend_current->out, "%s %s ", tag, cmd);
-+    if (!pipe_command(backend_current, 65536)) {
-+	pipe_including_tag(backend_current, tag, 0);
-+    }
-+}
-+
-+void cmd_sort(char *tag, int usinguid)
-+{
-+    char *cmd =3D usinguid ? "UID Sort" : "Sort";
-+
-+    assert(backend_current !=3D NULL);
-+
-+    prot_printf(backend_current->out, "%s %s ", tag, cmd);
-+    if (!pipe_command(backend_current, 65536)) {
-+	pipe_including_tag(backend_current, tag, 0);
-+    }
-+}
-+
-+void cmd_thread(char *tag, int usinguid)
-+{
-+    char *cmd =3D usinguid ? "UID Thread" : "Thread";
-+
-+    assert(backend_current !=3D NULL);
-+
-+    prot_printf(backend_current->out, "%s %s ", tag, cmd);
-+    if (!pipe_command(backend_current, 65536)) {
-+	pipe_including_tag(backend_current, tag, 0);
-+    }
-+}
-+
-+static int chomp(struct protstream *p, char *s)
-+{
-+    int c =3D prot_getc(p);
-+
-+    while (*s) {
-+	if (tolower(c) !=3D tolower(*s)) { break; }
-+	s++;
-+	c =3D prot_getc(p);
-+    }
-+    if (*s) {
-+	if (c !=3D EOF) prot_ungetc(c, p);
-+	c =3D EOF;
-+    }
-+    return c;
-+}
-+
-+/* read characters from 'p' until 'end' is seen */
-+static char *grab(struct protstream *p, char end)
-+{
-+    int alloc =3D BUFGROWSIZE, cur =3D 0;
-+    int c =3D -1;
-+    char *ret =3D (char *) xmalloc(alloc);
-+
-+    ret[0] =3D '\0';
-+    while ((c =3D prot_getc(p)) !=3D end) {
-+	if (c =3D=3D EOF) break;
-+	if (cur =3D=3D alloc - 1) {
-+	    alloc +=3D BUFGROWSIZE;
-+	    ret =3D xrealloc(ret, alloc);
-+
-+	}
-+	ret[cur++] =3D c;
-+    }
-+    if (cur) ret[cur] =3D '\0';
-+
-+    return ret;
-+}
-+
-+/* remove \Recent from the flags */
-+static char *editflags(char *flags)
-+{
-+    char *p;
-+
-+    p =3D flags;
-+    while ((p =3D strchr(p, '\\')) !=3D NULL) {
-+	if (!strncasecmp(p + 1, "recent", 6)) {
-+	    if (p[7] =3D=3D ' ') {
-+		/* shift everything over so that \recent vanishes */
-+		char *q;
-+		=

-+		q =3D p + 8;
-+		while (*q) {
-+		    *p++ =3D *q++;
-+		}
-+		*p =3D '\0';
-+	    } else if (p[7] =3D=3D '\0') {
-+		/* last flag in line */
-+		*p =3D '\0';
-+	    } else {
-+		/* not really \recent, i guess */
-+		p++;
-+	    }
-+	} else {
-+	    p++;
-+	}
-+    }
-+
-+    return flags;
-+}
-+
-+/*
-+ * Perform a COPY/UID COPY command
-+ */    =

-+void cmd_copy(char *tag, char *sequence, char *name, int usinguid)
-+{
-+    char *server, *acl;
-+    char *cmd =3D usinguid ? "UID Copy" : "Copy";
-+    struct backend *s =3D NULL;
-+    char mailboxname[MAX_MAILBOX_NAME+1];
-+    int r;
-+
-+    assert(backend_current !=3D NULL);
-+
-+    r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace, name,
-+						proxyd_userid, mailboxname);
-+    if (!r) r =3D mlookup(mailboxname, &server, &acl, NULL);
-+    if (!r) s =3D proxyd_findserver(server);
-+
-+    if (!s) {
-+	/* no such mailbox or other problem */
-+	r =3D mboxlist_createmailboxcheck(mailboxname, 0, 0, proxyd_userisadmin, =

-+					proxyd_userid, proxyd_authstate,
-+					NULL, NULL);
-+	if(!r && server) {
-+	    char *c;
-+	    c =3D strchr(server, '!');
-+	    if(c) *c =3D '\0';
-+	}
-+	prot_printf(proxyd_out, "%s NO %s%s\r\n", tag,
-+		    r =3D=3D 0 ? "[TRYCREATE] " : "", error_message(r));
-+    } else if (s =3D=3D backend_current) {
-+	/* this is the easy case */
-+	prot_printf(backend_current->out, "%s %s %s {%d+}\r\n%s\r\n",
-+		    tag, cmd, sequence, strlen(name), name);
-+	pipe_including_tag(backend_current, tag, 0);
-+    } else {
-+	char mytag[128];
-+	struct d {
-+	    char *idate;
-+	    char *flags;
-+	    unsigned int seqno, uid;
-+	    struct d *next;
-+	} *head, *p, *q;
-+	int c;
-+
-+	/* this is the hard case; we have to fetch the messages and append
-+	   them to the other mailbox */
-+
-+	/* find out what the flags & internaldate for this message are */
-+	proxyd_gentag(mytag, sizeof(mytag));
-+	prot_printf(backend_current->out, =

-+		    "%s %s %s (Flags Internaldate)\r\n", =

-+		    tag, usinguid ? "Uid Fetch" : "Fetch", sequence);
-+	head =3D (struct d *) xmalloc(sizeof(struct d));
-+	head->flags =3D NULL; head->idate =3D NULL;
-+	head->seqno =3D head->uid =3D 0;
-+	head->next =3D NULL;
-+	p =3D head;
-+	/* read all the responses into the linked list */
-+	for (/* each FETCH response */;;) {
-+	    unsigned int seqno =3D 0, uidno =3D 0;
-+	    char *flags =3D NULL, *idate =3D NULL;
-+
-+	    /* read a line */
-+	    c =3D prot_getc(backend_current->in);
-+	    if (c !=3D '*') break;
-+	    c =3D prot_getc(backend_current->in);
-+	    if (c !=3D ' ') { /* protocol error */ c =3D EOF; break; }
-+	    =

-+	    /* read seqno */
-+	    seqno =3D 0;
-+	    while (isdigit(c =3D prot_getc(backend_current->in))) {
-+		seqno *=3D 10;
-+		seqno +=3D c - '0';
-+	    }
-+	    if (seqno =3D=3D 0 || c !=3D ' ') {
-+		/* we suck and won't handle this case */
-+		c =3D EOF; break;
-+	    }
-+	    c =3D chomp(backend_current->in, "fetch (");
-+	    if (c =3D=3D EOF) {
-+		c =3D chomp(backend_current->in, "exists\r");
-+		if (c =3D=3D '\n') { /* got EXISTS response */
-+		    prot_printf(proxyd_out, "* %d EXISTS\r\n", seqno);
-+		    continue;
-+		}
-+	    }
-+	    if (c =3D=3D EOF) {
-+		/* XXX  the "exists" check above will eat "ex" */
-+		c =3D chomp(backend_current->in, "punge\r");
-+		if (c =3D=3D '\n') { /* got EXPUNGE response */
-+		    prot_printf(proxyd_out, "* %d EXPUNGE\r\n", seqno);
-+		    continue;
-+		}
-+	    }
-+	    if (c =3D=3D EOF) {
-+		c =3D chomp(backend_current->in, "recent\r");
-+		if (c =3D=3D '\n') { /* got RECENT response */
-+		    prot_printf(proxyd_out, "* %d RECENT\r\n", seqno);
-+		    continue;
-+		}
-+	    }
-+	    /* huh, don't get this response */
-+	    if (c =3D=3D EOF) break;
-+	    for (/* each fetch item */;;) {
-+		/* looking at the first character in an item */
-+		switch (c) {
-+		case 'f': case 'F': /* flags? */
-+		    c =3D chomp(backend_current->in, "lags");
-+		    if (c !=3D ' ') { c =3D EOF; }
-+		    else c =3D prot_getc(backend_current->in);
-+		    if (c !=3D '(') { c =3D EOF; }
-+		    else {
-+			flags =3D grab(backend_current->in, ')');
-+			c =3D prot_getc(backend_current->in);
-+		    }
-+		    break;
-+		case 'i': case 'I': /* internaldate? */
-+		    c =3D chomp(backend_current->in, "nternaldate");
-+		    if (c !=3D ' ') { c =3D EOF; }
-+		    else c =3D prot_getc(backend_current->in);
-+		    if (c !=3D '"') { c =3D EOF; }
-+		    else {
-+			idate =3D grab(backend_current->in, '"');
-+			c =3D prot_getc(backend_current->in);
-+		    }
-+		    break;
-+		case 'u': case 'U': /* uid */
-+		    c =3D chomp(backend_current->in, "id");
-+		    if (c !=3D ' ') { c =3D EOF; }
-+		    else {
-+			uidno =3D 0;
-+			while (isdigit(c =3D prot_getc(backend_current->in))) {
-+			    uidno *=3D 10;
-+			    uidno +=3D c - '0';
-+			}
-+		    }
-+		    break;
-+		default: /* hmm, don't like the smell of it */
-+		    c =3D EOF;
-+		    break;
-+		}
-+		/* looking at either SP seperating items or a RPAREN */
-+		if (c =3D=3D ' ') { c =3D prot_getc(backend_current->in); }
-+		else if (c =3D=3D ')') break;
-+		else { c =3D EOF; break; }
-+	    }
-+	    /* if c =3D=3D EOF we have either a protocol error or a situation
-+	       we can't handle, and we should die. */
-+	    if (c =3D=3D ')') c =3D prot_getc(backend_current->in);
-+	    if (c =3D=3D '\r') c =3D prot_getc(backend_current->in);
-+	    if (c !=3D '\n') { c =3D EOF; break; }
-+
-+	    /* if we're missing something, we should echo */
-+	    if (!flags || !idate) {
-+		char sep =3D '(';
-+		prot_printf(proxyd_out, "* %d FETCH ", seqno);
-+		if (uidno) {
-+		    prot_printf(proxyd_out, "%cUID %d", sep, uidno);
-+		    sep =3D ' ';
-+		}
-+		if (flags) {
-+		    prot_printf(proxyd_out, "%cFLAGS %s", sep, flags);
-+		    sep =3D ' ';
-+		}
-+		if (idate) {
-+		    prot_printf(proxyd_out, "%cINTERNALDATE %s", sep, flags);
-+		    sep =3D ' ';
-+		}
-+		prot_printf(proxyd_out, ")\r\n");
-+		continue;
-+	    }
-+
-+	    /* add to p->next */
-+	    p->next =3D xmalloc(sizeof(struct d));
-+	    p =3D p->next;
-+	    p->idate =3D idate;
-+	    p->flags =3D editflags(flags);
-+	    p->uid =3D uidno;
-+	    p->seqno =3D seqno;
-+	    p->next =3D NULL;
-+	}
-+	if (c !=3D EOF) {
-+	    prot_ungetc(c, backend_current->in);
-+
-+	    /* we should be looking at the tag now */
-+	    pipe_until_tag(backend_current, tag, 0);
-+	}
-+	if (c =3D=3D EOF) {
-+	    /* uh oh, we're not happy */
-+	    fatal("Lost connection to selected backend", EC_UNAVAILABLE);
-+	}
-+
-+	/* start the append */
-+	prot_printf(s->out, "%s Append {%d+}\r\n%s", tag, strlen(name), name);
-+	prot_printf(backend_current->out, "%s %s %s (Rfc822.peek)\r\n",
-+		    mytag, usinguid ? "Uid Fetch" : "Fetch", sequence);
-+	for (/* each FETCH response */;;) {
-+	    unsigned int seqno =3D 0, uidno =3D 0;
-+
-+	    /* read a line */
-+	    c =3D prot_getc(backend_current->in);
-+	    if (c !=3D '*') break;
-+	    c =3D prot_getc(backend_current->in);
-+	    if (c !=3D ' ') { /* protocol error */ c =3D EOF; break; }
-+	    =

-+	    /* read seqno */
-+	    seqno =3D 0;
-+	    while (isdigit(c =3D prot_getc(backend_current->in))) {
-+		seqno *=3D 10;
-+		seqno +=3D c - '0';
-+	    }
-+	    if (seqno =3D=3D 0 || c !=3D ' ') {
-+		/* we suck and won't handle this case */
-+		c =3D EOF; break;
-+	    }
-+	    c =3D chomp(backend_current->in, "fetch (");
-+	    if (c =3D=3D EOF) { /* not a fetch response */
-+		c =3D chomp(backend_current->in, "exists\r");
-+		if (c =3D=3D '\n') { /* got EXISTS response */
-+		    prot_printf(proxyd_out, "* %d EXISTS\r\n", seqno);
-+		    continue;
-+		}
-+	    }
-+	    if (c =3D=3D EOF) { /* not an exists response */
-+		/* XXX  the "exists" check above will eat "ex" */
-+		c =3D chomp(backend_current->in, "punge\r");
-+		if (c =3D=3D '\n') { /* got EXPUNGE response */
-+		    prot_printf(proxyd_out, "* %d EXPUNGE\r\n", seqno);
-+		    continue;
-+		}
-+	    }
-+	    if (c =3D=3D EOF) { /* not an exists response */
-+		c =3D chomp(backend_current->in, "recent\r");
-+		if (c =3D=3D '\n') { /* got RECENT response */
-+		    prot_printf(proxyd_out, "* %d RECENT\r\n", seqno);
-+		    continue;
-+		}
-+	    }
-+	    if (c =3D=3D EOF) {
-+                /* huh, don't get this response */
-+                break;
-+            }
-+	    /* find seqno in the list */
-+	    p =3D head;
-+	    while (p->next && seqno !=3D p->next->seqno) p =3D p->next;
-+	    if (!p->next) break;
-+	    q =3D p->next;
-+	    p->next =3D q->next;
-+	    for (/* each fetch item */;;) {
-+		int sz =3D 0;
-+
-+		switch (c) {
-+		case 'u': case 'U':
-+		    c =3D chomp(backend_current->in, "id");
-+		    if (c !=3D ' ') { c =3D EOF; }
-+		    else {
-+			uidno =3D 0;
-+			while (isdigit(c =3D prot_getc(backend_current->in))) {
-+			    uidno *=3D 10;
-+			    uidno +=3D c - '0';
-+			}
-+		    }
-+		    break;
-+
-+		case 'r': case 'R':
-+		    c =3D chomp(backend_current->in, "fc822");
-+		    if (c =3D=3D ' ') c =3D prot_getc(backend_current->in);
-+		    if (c !=3D '{') c =3D EOF;
-+		    else {
-+			sz =3D 0;
-+			while (isdigit(c =3D prot_getc(backend_current->in))) {
-+			    sz *=3D 10;
-+			    sz +=3D c - '0';
-+                            /* xxx overflow */
-+			}
-+		    }
-+		    if (c =3D=3D '}') c =3D prot_getc(backend_current->in);
-+		    if (c =3D=3D '\r') c =3D prot_getc(backend_current->in);
-+		    if (c !=3D '\n') c =3D EOF;
-+
-+		    if (c !=3D EOF) {
-+			/* append p to s->out */
-+			prot_printf(s->out, " (%s) \"%s\" {%d+}\r\n", =

-+				    q->flags, q->idate, sz);
-+			while (sz) {
-+			    char buf[2048];
-+			    int j =3D (sz > sizeof(buf) ? sizeof(buf) : sz);
-+
-+			    j =3D prot_read(backend_current->in, buf, j);
-+			    if(!j) break;
-+			    prot_write(s->out, buf, j);
-+			    sz -=3D j;
-+			}
-+			c =3D prot_getc(backend_current->in);
-+		    }
-+
-+		    break; /* end of case */
-+		default:
-+		    c =3D EOF;
-+		    break;
-+		}
-+		/* looking at either SP seperating items or a RPAREN */
-+		if (c =3D=3D ' ') { c =3D prot_getc(backend_current->in); }
-+		else if (c =3D=3D ')') break;
-+		else { c =3D EOF; break; }
-+	    }
-+
-+	    /* if c =3D=3D EOF we have either a protocol error or a situation
-+	       we can't handle, and we should die. */
-+	    if (c =3D=3D ')') c =3D prot_getc(backend_current->in);
-+	    if (c =3D=3D '\r') c =3D prot_getc(backend_current->in);
-+	    if (c !=3D '\n') { c =3D EOF; break; }
-+
-+	    /* free q */
-+	    free(q->idate);
-+	    free(q->flags);
-+	    free(q);
-+	}
-+	if (c !=3D EOF) {
-+	    char *appenduid, *b;
-+	    int res;
-+
-+	    /* pushback the first character of the tag we're looking at */
-+	    prot_ungetc(c, backend_current->in);
-+
-+	    /* nothing should be left in the linked list */
-+	    assert(head->next =3D=3D NULL);
-+
-+	    /* ok, finish the append; we need the UIDVALIDITY and UIDs
-+	       to return as part of our COPYUID response code */
-+	    prot_printf(s->out, "\r\n");
-+
-+	    /* should be looking at 'mytag' on 'backend_current', =

-+	       'tag' on 's' */
-+	    pipe_until_tag(backend_current, mytag, 0);
-+	    res =3D pipe_until_tag(s, tag, 0);
-+
-+	    if (res =3D=3D PROXY_OK) {
-+		int access =3D cyrus_acl_myrights(proxyd_authstate, acl);
-+
-+		if (access & ACL_READ) {
-+		    appenduid =3D strchr(s->last_result.s, '[');
-+		    /* skip over APPENDUID */
-+		    appenduid +=3D strlen("[appenduid ");
-+		    b =3D strchr(appenduid, ']');
-+		    *b =3D '\0';
-+		    prot_printf(proxyd_out, "%s OK [COPYUID %s] %s\r\n", tag,
-+				appenduid, error_message(IMAP_OK_COMPLETED));
-+		} else {
-+		    prot_printf(proxyd_out, "%s OK %s\r\n", tag,
-+				error_message(IMAP_OK_COMPLETED));
-+		}
-+	    } else {
-+		prot_printf(proxyd_out, "%s %s", tag, s->last_result.s);
-+	    }
-+	} else {
-+	    /* abort the append */
-+	    prot_printf(s->out, " {0}\r\n");
-+	    pipe_until_tag(backend_current, mytag, 0);
-+	    pipe_until_tag(s, tag, 0);
-+	    =

-+	    /* report failure */
-+	    prot_printf(proxyd_out, "%s NO inter-server COPY failed\r\n", tag);
-+	}
-+
-+	/* free dynamic memory */
-+	while (head) {
-+	    p =3D head;
-+	    head =3D head->next;
-+	    if (p->idate) free(p->idate);
-+	    if (p->flags) free(p->flags);
-+	    free(p);
-+	}
-+    }
-+}    =

-+
-+/*
-+ * Perform an EXPUNGE command
-+ * sequence =3D=3D NULL if this isn't a UID EXPUNGE
-+ */
-+void cmd_expunge(char *tag, char *sequence)
-+{
-+    assert(backend_current !=3D NULL);
-+
-+    if (sequence) {
-+	prot_printf(backend_current->out, "%s UID Expunge %s\r\n", tag,
-+		    sequence);
-+    } else {
-+	prot_printf(backend_current->out, "%s Expunge\r\n", tag);
-+    }
-+    pipe_including_tag(backend_current, tag, 0);
-+}    =

-+
-+/*
-+ * Perform a CREATE command
-+ */
-+void cmd_create(char *tag, char *name, char *server)
-+{
-+    struct backend *s =3D NULL;
-+    char mailboxname[MAX_MAILBOX_NAME+1];
-+    int r =3D 0, res;
-+    char *acl =3D NULL;
-+
-+    if (server && !proxyd_userisadmin) {
-+	r =3D IMAP_PERMISSION_DENIED;
-+    }
-+
-+    if (name[0] && name[strlen(name)-1] =3D=3D proxyd_namespace.hier_sep)=
 {
-+	/* We don't care about trailing hierarchy delimiters. */
-+	name[strlen(name)-1] =3D '\0';
-+    }
-+
-+    if (!r)
-+	r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace, name,
-+						    proxyd_userid, mailboxname);
-+
-+    if (!r && !server) {
-+	r =3D mboxlist_createmailboxcheck(mailboxname, 0, 0, proxyd_userisadmin,
-+					proxyd_userid, proxyd_authstate,
-+					&acl, &server);
-+	if(!r && server) {
-+	    char *c;
-+	    c =3D strchr(server, '!');
-+	    if(c) *c =3D '\0';
-+	}
-+    }
-+    if (!r && server) {
-+	s =3D proxyd_findserver(server);
-+	if (!s) r =3D IMAP_SERVER_UNAVAILABLE;
-+    }
-+    if (!r) {
-+	if (!CAPA(s, CAPA_MUPDATE)) {
-+	    /* reserve mailbox on MUPDATE */
-+	}
-+    }
-+
-+    if (!r) {
-+	/* ok, send the create to that server */
-+	prot_printf(s->out, "%s CREATE {%d+}\r\n%s\r\n", =

-+		    tag, strlen(name), name);
-+	res =3D pipe_including_tag(s, tag, 0);
-+	tag =3D "*";		/* can't send another tagged response */
-+	=

-+	if (!CAPA(s, CAPA_MUPDATE)) {
-+	    /* do MUPDATE create operations */
-+	}
-+	/* make sure we've seen the update */
-+	if (ultraparanoid && res =3D=3D PROXY_OK) kick_mupdate();
-+    }
-+    =

-+    if (r) prot_printf(proxyd_out, "%s NO %s\r\n", tag, error_message(r));
-+}
-+
-+/*
-+ * Perform a DELETE command
-+ */
-+void cmd_delete(char *tag, char *name)
-+{
-+    int r, res;
-+    char *server;
-+    struct backend *s =3D NULL;
-+    char mailboxname[MAX_MAILBOX_NAME+1];
-+
-+    r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace, name,
-+						proxyd_userid, mailboxname);
-+
-+    if (!r) r =3D mlookup(mailboxname, &server, NULL, NULL);
-+    if (!r && supports_referrals) { =

-+	proxyd_refer(tag, server, name);
-+	referral_kick =3D 1;
-+	return;
-+    }
-+
-+    if (!r) {
-+	s =3D proxyd_findserver(server);
-+	if (!s) r =3D IMAP_SERVER_UNAVAILABLE;
-+    }
-+
-+    if (!r) {
-+	prot_printf(s->out, "%s DELETE {%d+}\r\n%s\r\n", =

-+		    tag, strlen(name), name);
-+	res =3D pipe_including_tag(s, tag, 0);
-+	tag =3D "*";		/* can't send another tagged response */
-+
-+	if (!CAPA(s, CAPA_MUPDATE) && res =3D=3D PROXY_OK) {
-+	    /* do MUPDATE delete operations */
-+	}
-+
-+	/* make sure we've seen the update */
-+	if (ultraparanoid && res =3D=3D PROXY_OK) kick_mupdate();
-+    }
-+
-+    if (r) prot_printf(proxyd_out, "%s NO %s\r\n", tag, error_message(r));
-+}	=

-+
-+/*
-+ * Perform a RECONSTRUCT command
-+ */
-+void cmd_reconstruct(char *tag, char *name)
-+{
-+    int r =3D 0;
-+    char mailboxname[MAX_MAILBOX_NAME+1];
-+    char *server =3D NULL;
-+
-+    if(!proxyd_userisadmin) r =3D IMAP_PERMISSION_DENIED;
-+    else {
-+	r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace,
-+						    name,
-+						    proxyd_userid,
-+						    mailboxname);
-+    }
-+
-+    if(!r)
-+	r =3D mlookup(mailboxname, &server, NULL, NULL);
-+
-+    if(!r) {
-+	proxyd_refer(tag, server, name);
-+    } else {
-+	prot_printf(proxyd_out, "%s NO %s\r\n", tag, error_message(r));
-+    }
-+}	=

-+
-+/*
-+ * Perform a RENAME command
-+ */
-+void cmd_rename(char *tag, char *oldname, char *newname, char *partition)
-+{
-+    int r =3D 0, res;
-+    char *server;
-+    char oldmailboxname[MAX_MAILBOX_NAME+1];
-+    char newmailboxname[MAX_MAILBOX_NAME+1];
-+    struct backend *s =3D NULL;
-+    char *acl =3D NULL;
-+
-+    r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace, oldn=
ame,
-+						proxyd_userid, oldmailboxname);
-+    if (!r) (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace, ne=
wname,
-+						    proxyd_userid, newmailboxname);
-+    if (!r) r =3D mlookup(oldmailboxname, &server, &acl, NULL);
-+    if (!r) {
-+	s =3D proxyd_findserver(server);
-+	if (!s) r =3D IMAP_SERVER_UNAVAILABLE;
-+    }
-+
-+    /* Cross Server Rename */
-+    if (!r && partition) {
-+	char *destpart;
-+	=

-+	if(strcmp(oldname, newname)) {
-+	    prot_printf(proxyd_out,
-+			"%s NO Cross-server or cross-partition move w/rename not supported\r\n=
",
-+			tag);
-+	    return;
-+	}
-+
-+	/* dest partition? */
-+
-+	destpart =3D strchr(partition,'!');
-+	if(destpart) {
-+	    char newserver[MAX_MAILBOX_NAME+1];	    =

-+	    if(strlen(partition)>=3Dsizeof(newserver)) {
-+		prot_printf(proxyd_out,
-+			    "%s NO Partition name too long\r\n", tag);
-+		return;
-+	    }
-+	    strcpy(newserver,partition);
-+	    newserver[destpart-partition]=3D'\0';
-+	    destpart++;
-+
-+	    if(!strcmp(server, newserver)) {
-+		/* Same Server, different partition */
-+		/* xxx this would require administrative access to the
-+		 * backend, which we won't get */
-+		prot_printf(proxyd_out,
-+			    "%s NO Can't move across partitions via a proxy\r\n",
-+			    tag);
-+		return;
-+	    } else {
-+		/* Cross Server */
-+		/* <tag> XFER <name> <dest server> <dest partition> */
-+		prot_printf(s->out,
-+			    "%s XFER {%d+}\r\n%s {%d+}\r\n%s {%d+}\r\n%s\r\n", =

-+			    tag, strlen(oldname), oldname,
-+			    strlen(newserver), newserver,
-+			    strlen(destpart), destpart);
-+	    }
-+	    =

-+	} else {
-+	    /* <tag> XFER <name> <dest server> */
-+	    prot_printf(s->out, "%s XFER {%d+}\r\n%s {%d+}\r\n%s\r\n", =

-+			tag, strlen(oldname), oldname,
-+			strlen(partition), partition);
-+	}
-+	=

-+	res =3D pipe_including_tag(s, tag, 0);
-+
-+	/* make sure we've seen the update */
-+	if (ultraparanoid && res =3D=3D PROXY_OK) kick_mupdate();
-+
-+	return;
-+    }
-+
-+    if (!r) {
-+	if (!CAPA(s, CAPA_MUPDATE)) {
-+	    /* do MUPDATE create operations for new mailbox */
-+	}
-+
-+	prot_printf(s->out, "%s RENAME {%d+}\r\n%s {%d+}\r\n%s\r\n", =

-+		    tag, strlen(oldname), oldname,
-+		    strlen(newname), newname);
-+	res =3D pipe_including_tag(s, tag, 0);
-+	tag =3D "*";		/* can't send another tagged response */
-+	=

-+	if (!CAPA(s, CAPA_MUPDATE)) {
-+	    /* Activate/abort new mailbox in MUPDATE*/
-+	    /* delete old mailbox from MUPDATE */
-+	}
-+
-+	/* make sure we've seen the update */
-+	if (res =3D=3D PROXY_OK) kick_mupdate();
-+    }
-+
-+    if (r) prot_printf(proxyd_out, "%s NO %s\r\n", tag, error_message(r));
-+}
-+
-+/*
-+ * Perform a FIND command
-+ */
-+void cmd_find(char *tag, char *namespace, char *pattern)
-+{
-+    char *p;
-+    lcase(namespace);
-+
-+    for (p =3D pattern; *p; p++) {
-+	if (*p =3D=3D '%') *p =3D '?';
-+    }
-+
-+    if (!strcasecmp(namespace, "mailboxes")) {
-+	if (!backend_inbox) {
-+	    backend_inbox =3D proxyd_findinboxserver();
-+	}
-+
-+	if (backend_inbox) {
-+	    prot_printf(backend_inbox->out, =

-+			"%s Lsub \"\" {%d+}\r\n%s\r\n",
-+			tag, strlen(pattern), pattern);
-+	    pipe_lsub(backend_inbox, tag, 0, "MAILBOX");
-+	} else {		/* user doesn't have an INBOX */
-+	    /* noop */
-+	}
-+    } else if (!strcasecmp(namespace, "all.mailboxes")) {
-+	/* Translate any separators in pattern */
-+	mboxname_hiersep_tointernal(&proxyd_namespace, pattern,
-+				    config_virtdomains ?
-+				    strcspn(pattern, "@") : 0);
-+
-+	(*proxyd_namespace.mboxlist_findall)(&proxyd_namespace, pattern,
-+					     proxyd_userisadmin, proxyd_userid,
-+					     proxyd_authstate, mailboxdata,
-+					     NULL);
-+    } else if (!strcasecmp(namespace, "bboards")
-+	       || !strcasecmp(namespace, "all.bboards")) {
-+	;
-+    } else {
-+	prot_printf(proxyd_out, "%s BAD Invalid FIND subcommand\r\n", tag);
-+	return;
-+    }
-+
-+    if (backend_current) {
-+	char mytag[128];
-+
-+	proxyd_gentag(mytag, sizeof(mytag));
-+
-+	prot_printf(backend_current->out, "%s Noop\r\n", mytag);
-+	pipe_until_tag(backend_current, mytag, 0);
-+    }
-+
-+    prot_printf(proxyd_out, "%s OK %s\r\n", tag,
-+		error_message(IMAP_OK_COMPLETED));
-+}
-+
-+/*
-+ * Perform a LIST or LSUB command
-+ * LISTs we do locally
-+ * LSUBs we farm out
-+ */
-+void cmd_list(char *tag, int listopts, char *reference, char *pattern)
-+{
-+    char *buf =3D NULL;
-+    int patlen =3D 0;
-+    int reflen =3D 0;
-+    static int ignorereference =3D -1;
-+
-+    /* Ignore the reference argument?
-+       (the behavior in 1.5.10 & older) */
-+    if (ignorereference =3D=3D -1) {
-+	ignorereference =3D config_getswitch(IMAPOPT_IGNOREREFERENCE);
-+    }
-+
-+    /* Reset state in mstringdata */
-+    mstringdata(NULL, NULL, 0, 0);
-+    =

-+    if (!pattern[0] && !(listopts & LIST_LSUB)) {
-+	/* Special case: query top-level hierarchy separator */
-+	prot_printf(proxyd_out, "* LIST (\\Noselect) \"%c\" \"\"\r\n",
-+		    proxyd_namespace.hier_sep);
-+    } else if (listopts & (LIST_LSUB | LIST_SUBSCRIBED)) {
-+	/* do an LSUB command; contact our INBOX */
-+	if (!backend_inbox) {
-+	    backend_inbox =3D proxyd_findinboxserver();
-+	}
-+
-+	if (backend_inbox) {
-+	    prot_printf(backend_inbox->out, =

-+			"%s Lsub {%d+}\r\n%s {%d+}\r\n%s\r\n",
-+			tag, strlen(reference), reference,
-+			strlen(pattern), pattern);
-+	    pipe_lsub(backend_inbox, tag, 0, (listopts & LIST_LSUB) ? "LSUB" : "=
LIST");
-+	} else {		/* user doesn't have an INBOX */
-+	    /* noop */
-+	}
-+    } else {			/* do a LIST locally */
-+	/* Do we need to concatenate fields? */
-+	if (!ignorereference || pattern[0] =3D=3D proxyd_namespace.hier_sep) {
-+	    /* Either
-+	     * - name begins with dot
-+	     * - we're configured to honor the reference argument */
-+
-+	    /* Allocate a buffer, figure out how to stick the arguments
-+	       together, do it, then do that instead of using pattern. */
-+	    patlen =3D strlen(pattern);
-+	    reflen =3D strlen(reference);
-+	    =

-+	    buf =3D xmalloc(patlen + reflen + 1);
-+	    buf[0] =3D '\0';
-+
-+	    if (*reference) {
-+		/* check for LIST A. .B, change to LIST "" A.B */
-+		if (reference[reflen-1] =3D=3D proxyd_namespace.hier_sep &&
-+		    pattern[0] =3D=3D proxyd_namespace.hier_sep) {
-+		    reference[--reflen] =3D '\0';
-+		}
-+		strcpy(buf, reference);
-+	    }
-+	    strcat(buf, pattern);
-+	    pattern =3D buf;
-+	}
-+
-+	/* Translate any separators in pattern */
-+	mboxname_hiersep_tointernal(&proxyd_namespace, pattern,
-+ 				    config_virtdomains ?
-+ 				    strcspn(pattern, "@") : 0);
-+
-+	(*proxyd_namespace.mboxlist_findall)(&proxyd_namespace, pattern,
-+					     proxyd_userisadmin, proxyd_userid,
-+					     proxyd_authstate, listdata, NULL);
-+	listdata((char *)0, 0, 0, 0);
-+
-+	if (buf) free(buf);
-+    }
-+
-+    if (backend_current && (backend_current !=3D backend_inbox ||
-+			    !(listopts & (LIST_LSUB | LIST_SUBSCRIBED)))) {
-+	/* our Lsub would've done this if =

-+	   backend_current =3D=3D backend_inbox */
-+	char mytag[128];
-+
-+	proxyd_gentag(mytag, sizeof(mytag));
-+
-+	prot_printf(backend_current->out, "%s Noop\r\n", mytag);
-+	pipe_until_tag(backend_current, mytag, 0);
-+    }
-+
-+    prot_printf(proxyd_out, "%s OK %s\r\n", tag,
-+		error_message(IMAP_OK_COMPLETED));
-+}
-+  =

-+/*
-+ * Perform a SUBSCRIBE (add is nonzero) or
-+ * UNSUBSCRIBE (add is zero) command
-+ */
-+void cmd_changesub(char *tag, char *namespace, char *name, int add)
-+{
-+    char *cmd =3D add ? "Subscribe" : "Unsubscribe";
-+    int r =3D 0;
-+
-+    if (!backend_inbox) {
-+	backend_inbox =3D proxyd_findinboxserver();
-+    }
-+
-+    if (backend_inbox) {
-+	char mailboxname[MAX_MAILBOX_NAME+1];
-+
-+	if (add) {
-+	    r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace,
-+							name, proxyd_userid,
-+							mailboxname);
-+	    if(!r) r =3D mlookup(mailboxname, NULL, NULL, NULL);
-+
-+	    /* Doesn't exist on murder */
-+	    if(r) goto done;
-+	}
-+	=

-+	if (namespace) {
-+	    prot_printf(backend_inbox->out, =

-+			"%s %s {%d+}\r\n%s {%d+}\r\n%s\r\n", =

-+			tag, cmd, =

-+			strlen(namespace), namespace,
-+			strlen(name), name);
-+	} else {
-+	    prot_printf(backend_inbox->out, "%s %s {%d+}\r\n%s\r\n", =

-+			tag, cmd, =

-+			strlen(name), name);
-+	}
-+	pipe_including_tag(backend_inbox, tag, 0);
-+    } else {
-+	r =3D IMAP_SERVER_UNAVAILABLE;
-+    }
-+
-+ done:
-+    if(r) {
-+	prot_printf(proxyd_out, "%s NO %s: %s\r\n", tag,
-+		    add ? "Subscribe" : "Unsubscribe", error_message(r));
-+    }
-+}
-+
-+/*
-+ * Perform a GETACL command
-+ */
-+void cmd_getacl(const char *tag, const char *name)
-+{
-+    char mailboxname[MAX_MAILBOX_NAME+1];
-+    int r, access;
-+    char *acl;
-+    char *rights, *nextid;
-+
-+    r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace, name,
-+						proxyd_userid, mailboxname);
-+
-+    if (!r) r =3D mlookup(mailboxname, NULL, &acl, NULL);
-+
-+    if (!r) {
-+	access =3D cyrus_acl_myrights(proxyd_authstate, acl);
-+
-+	if (!(access & (ACL_READ|ACL_ADMIN)) &&
-+	    !proxyd_userisadmin &&
-+	    !mboxname_userownsmailbox(proxyd_userid, mailboxname)) {
-+	    r =3D (access & ACL_LOOKUP) ?
-+	      IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
-+	}
-+    }
-+    if (r) {
-+	prot_printf(proxyd_out, "%s NO %s\r\n", tag, error_message(r));
-+	return;
-+    }
-+    =

-+    prot_printf(proxyd_out, "* ACL ");
-+    printastring(name);
-+    =

-+    while (acl) {
-+	rights =3D strchr(acl, '\t');
-+	if (!rights) break;
-+	*rights++ =3D '\0';
-+	=

-+	nextid =3D strchr(rights, '\t');
-+	if (!nextid) break;
-+	*nextid++ =3D '\0';
-+	=

-+	prot_printf(proxyd_out, " ");
-+	printastring(acl);
-+	prot_printf(proxyd_out, " ");
-+	printastring(rights);
-+	acl =3D nextid;
-+    }
-+    prot_printf(proxyd_out, "\r\n");
-+    prot_printf(proxyd_out, "%s OK %s\r\n", tag,
-+		error_message(IMAP_OK_COMPLETED));
-+}
-+
-+/*
-+ * Perform a LISTRIGHTS command
-+ */
-+void cmd_listrights(char *tag, char *name, char *identifier)
-+{
-+    char mailboxname[MAX_MAILBOX_NAME+1];
-+    int r, rights;
-+    char *acl;
-+
-+    r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace, name,
-+						proxyd_userid, mailboxname);
-+
-+    if (!r) {
-+	r =3D mlookup(mailboxname, (char **)0, &acl, NULL);
-+    }
-+
-+    if (!r) {
-+	rights =3D cyrus_acl_myrights(proxyd_authstate, acl);
-+
-+	if (!rights && !proxyd_userisadmin &&
-+	    !mboxname_userownsmailbox(proxyd_userid, mailboxname)) {
-+	    r =3D IMAP_MAILBOX_NONEXISTENT;
-+	}
-+    }
-+
-+    if (!r) {
-+	struct auth_state *authstate =3D auth_newstate(identifier);
-+	char *canon_identifier;
-+	int canonidlen =3D 0;
-+	int implicit;
-+	char rightsdesc[100], optional[33];
-+
-+	if (global_authisa(authstate, IMAPOPT_ADMINS))
-+	    canon_identifier =3D identifier; /* don't canonify global admins */
-+	else
-+	    canon_identifier =3D canonify_userid(identifier, proxyd_userid, NULL=
);
-+	auth_freestate(authstate);
-+
-+	if (canon_identifier) canonidlen =3D strlen(canon_identifier);
-+
-+	if (!canon_identifier) {
-+	    implicit =3D 0;
-+	}
-+	else if (mboxname_userownsmailbox(canon_identifier, mailboxname)) {
-+	    /* identifier's personal mailbox */
-+	    implicit =3D config_implicitrights;
-+	}
-+	else if (mboxname_isusermailbox(mailboxname, 1)) {
-+	    /* anyone can post to an INBOX */
-+	    implicit =3D ACL_POST;
-+	}
-+	else {
-+	    implicit =3D 0;
-+	}
-+
-+	/* calculate optional rights */
-+	cyrus_acl_masktostr(implicit ^ (canon_identifier ? ACL_FULL : 0),
-+			    optional);
-+
-+	/* build the rights string */
-+	if (implicit) {
-+	    cyrus_acl_masktostr(implicit, rightsdesc);
-+	}
-+	else {
-+	    strcpy(rightsdesc, "\"\"");
-+	}
-+
-+	if (*optional) {
-+	    int i, n =3D strlen(optional);
-+	    char *p =3D rightsdesc + strlen(rightsdesc);
-+
-+	    for (i =3D 0; i < n; i++) {
-+		*p++ =3D ' ';
-+		*p++ =3D optional[i];
-+	    }
-+	    *p =3D '\0';
-+	}
-+
-+	prot_printf(proxyd_out, "* LISTRIGHTS ");
-+	printastring(name);
-+	prot_putc(' ', proxyd_out);
-+	printastring(identifier);
-+	prot_printf(proxyd_out, " %s", rightsdesc);
-+
-+	prot_printf(proxyd_out, "\r\n%s OK %s\r\n", tag,
-+		    error_message(IMAP_OK_COMPLETED));
-+	return;
-+    }
-+
-+    prot_printf(proxyd_out, "%s NO %s\r\n", tag, error_message(r));
-+}
-+
-+/*
-+ * Perform a MYRIGHTS command
-+ */
-+void cmd_myrights(const char *tag, const char *name)
-+{
-+    char mailboxname[MAX_MAILBOX_NAME+1];
-+    int r, rights =3D 0;
-+    char *acl;
-+    char str[ACL_MAXSTR];
-+
-+    r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace, name,
-+						proxyd_userid, mailboxname);
-+
-+    if (!r) {
-+	r =3D mlookup(mailboxname, (char **)0, &acl, NULL);
-+    }
-+
-+    if (!r) {
-+	rights =3D cyrus_acl_myrights(proxyd_authstate, acl);
-+
-+	/* Add in implicit rights */
-+	if (proxyd_userisadmin) {
-+	    rights |=3D ACL_LOOKUP|ACL_ADMIN;
-+	}
-+	else if (mboxname_userownsmailbox(proxyd_userid, mailboxname)) {
-+	    rights |=3D config_implicitrights;
-+	}
-+
-+	if (!rights) {
-+	    r =3D IMAP_MAILBOX_NONEXISTENT;
-+	}
-+    }
-+    if (r) {
-+	prot_printf(proxyd_out, "%s NO %s\r\n", tag, error_message(r));
-+	return;
-+    }
-+    =

-+    prot_printf(proxyd_out, "* MYRIGHTS ");
-+    printastring(name);
-+    prot_printf(proxyd_out, " ");
-+    printastring(cyrus_acl_masktostr(rights, str));
-+    prot_printf(proxyd_out, "\r\n%s OK %s\r\n", tag,
-+		error_message(IMAP_OK_COMPLETED));
-+}
-+
-+/*
-+ * Perform a SETACL command
-+ */
-+void cmd_setacl(char *tag, const char *name,
-+		const char *identifier, const char *rights)
-+{
-+    int r, res;
-+    char mailboxname[MAX_MAILBOX_NAME+1];
-+    char *server;
-+    struct backend *s =3D NULL;
-+    char *acl =3D NULL;
-+
-+    r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace, name,
-+						proxyd_userid, mailboxname);
-+    if (!r) r =3D mlookup(mailboxname, &server, &acl, NULL);
-+    if (!r) {
-+	s =3D proxyd_findserver(server);
-+	if (!s) r =3D IMAP_SERVER_UNAVAILABLE;
-+    }
-+
-+    if (!r && proxyd_userisadmin && supports_referrals) {
-+	/* They aren't an admin remotely, so let's refer them */
-+	proxyd_refer(tag, server, name);
-+	referral_kick =3D 1;
-+	return;
-+    } else if (!r) {
-+	if (rights) {
-+	    prot_printf(s->out, =

-+			"%s Setacl {%d+}\r\n%s {%d+}\r\n%s {%d+}\r\n%s\r\n",
-+			tag, strlen(name), name,
-+			strlen(identifier), identifier,
-+			strlen(rights), rights);
-+	} else {
-+	    prot_printf(s->out, =

-+			"%s Deleteacl {%d+}\r\n%s {%d+}\r\n%s\r\n",
-+			tag, strlen(name), name,
-+			strlen(identifier), identifier);
-+	}	    =

-+	res =3D pipe_including_tag(s, tag, 0);
-+	tag =3D "*";		/* can't send another tagged response */
-+	if (!CAPA(s, CAPA_MUPDATE) && res =3D=3D PROXY_OK) {
-+	    /* setup new ACL in MUPDATE */
-+	}
-+	/* make sure we've seen the update */
-+	if (ultraparanoid && res =3D=3D PROXY_OK) kick_mupdate();
-+    }
-+
-+    if (r) prot_printf(proxyd_out, "%s NO %s\r\n", tag, error_message(r));
-+}
-+
-+/*
-+ * Callback for (get|set)quota, to ensure that all of the
-+ * submailboxes are on the same server.
-+ */
-+static int quota_cb(char *name, int matchlen __attribute__((unused)),
-+		    int maycreate __attribute__((unused)), void *rock) =

-+{
-+    int r;
-+    char *this_server;
-+    const char *servername =3D (const char *)rock;
-+    =

-+    r =3D mlookup(name, &this_server, NULL, NULL);
-+    if(r) return r;
-+
-+    if(strcmp(servername, this_server)) {
-+	/* Not on same server as the root */
-+	return IMAP_NOT_SINGULAR_ROOT;
-+    } else {
-+	return PROXY_OK;
-+    }
-+}
-+
-+/*
-+ * Perform a GETQUOTA command
-+ */
-+void cmd_getquota(char *tag, char *name)
-+{
-+    int r;
-+    char *server_rock =3D NULL, *server_rock_tmp =3D NULL;
-+    char mailboxname[MAX_MAILBOX_NAME+1];
-+    char quotarootbuf[MAX_MAILBOX_NAME + 3];
-+
-+    if(!proxyd_userisadmin) r =3D IMAP_PERMISSION_DENIED;
-+    else {
-+	r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace,
-+						    name,
-+						    proxyd_userid,
-+						    mailboxname);
-+    }
-+
-+    if(!r)
-+	r =3D mlookup(mailboxname, &server_rock_tmp, NULL, NULL);
-+
-+    if(!r) {
-+	server_rock =3D xstrdup(server_rock_tmp);
-+
-+	snprintf(quotarootbuf, sizeof(quotarootbuf), "%s.*", mailboxname);
-+
-+	r =3D mboxlist_findall(&proxyd_namespace, quotarootbuf,
-+			     proxyd_userisadmin, proxyd_userid,
-+			     proxyd_authstate, quota_cb, server_rock);
-+    }
-+
-+    if (!r) {
-+	/* Do the referral */
-+	proxyd_refer(tag, server_rock, name);
-+	free(server_rock);
-+    } else {
-+	if(server_rock) free(server_rock);
-+	prot_printf(proxyd_out, "%s NO %s\r\n", tag, error_message(r));
-+    }
-+}
-+
-+/*
-+ * Perform a GETQUOTAROOT command
-+ */
-+void cmd_getquotaroot(char *tag, char *name)
-+{
-+    char mailboxname[MAX_MAILBOX_NAME+1];
-+    char *server;
-+    int r;
-+    struct backend *s =3D NULL;
-+
-+    r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace, name,
-+						proxyd_userid, mailboxname);
-+    if (!r) r =3D mlookup(mailboxname, &server, NULL, NULL);
-+
-+    if(proxyd_userisadmin) {
-+	/* If they are an admin, they won't retain that privledge if we
-+	 * proxy for them, so we need to refer them -- even if they haven't
-+	 * told us they're able to handle it. */
-+	proxyd_refer(tag, server, name);
-+    } else {
-+	if (!r) s =3D proxyd_findserver(server);
-+
-+	if (s) {
-+	    prot_printf(s->out, "%s Getquotaroot {%d+}\r\n%s\r\n",
-+			tag, strlen(name), name);
-+	    pipe_including_tag(s, tag, 0);
-+	} else {
-+	    r =3D IMAP_SERVER_UNAVAILABLE;
-+	}
-+
-+	if (r) {
-+	    prot_printf(proxyd_out, "%s NO %s\r\n", tag, error_message(r));
-+	    return;
-+	}
-+    }
-+}
-+
-+/*
-+ * Parse and perform a SETQUOTA command
-+ * The command has been parsed up to the resource list
-+ */
-+void cmd_setquota(char *tag, char *quotaroot)
-+{
-+    int r;
-+    char c;
-+    char *p;
-+    static struct buf arg;
-+    int badresource =3D 0;
-+    char *server_rock =3D NULL, *server_rock_tmp =3D NULL;
-+    char mailboxname[MAX_MAILBOX_NAME+1];
-+    char quotarootbuf[MAX_MAILBOX_NAME + 3];
-+
-+    /* First ensure the validity of the command */
-+    c =3D prot_getc(proxyd_in);
-+    if (c !=3D '(') goto badlist;
-+
-+    /* xxx maybe we don't want to be this stringant on what types
-+     * of quota we allow to be set, since we will just be doing a referral
-+     * anyway... */
-+    c =3D getword(proxyd_in, &arg);
-+    if (c !=3D ')' || arg.s[0] !=3D '\0') {
-+	for (;;) {
-+	    if (c !=3D ' ') goto badlist;
-+	    if (strcasecmp(arg.s, "storage") !=3D 0) badresource =3D 1;
-+	    c =3D getword(proxyd_in, &arg);
-+	    if (c !=3D ' ' && c !=3D ')') goto badlist;
-+	    if (arg.s[0] =3D=3D '\0') goto badlist;
-+	    /* We are just syntax checking here, no need to save the value */
-+	    for (p =3D arg.s; *p; p++) {
-+		if (!isdigit((int) *p)) goto badlist;
-+	    }
-+	    if (c =3D=3D ')') break;
-+	}
-+    }
-+    c =3D prot_getc(proxyd_in);
-+    if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+    if (c !=3D '\n') {
-+	prot_printf(proxyd_out,
-+		    "%s BAD Unexpected extra arguments to SETQUOTA\r\n", tag);
-+	eatline(proxyd_in, c);
-+	return;
-+    }
-+
-+    if(badresource) r =3D IMAP_UNSUPPORTED_QUOTA;
-+    else if(!proxyd_userisadmin) r =3D IMAP_PERMISSION_DENIED;
-+    else {
-+	r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace,
-+						    quotaroot,
-+						    proxyd_userid,
-+						    mailboxname);
-+    }
-+
-+    if(!r)
-+	r =3D mlookup(mailboxname, &server_rock_tmp, NULL, NULL);
-+
-+    if(!r) {
-+	server_rock =3D xstrdup(server_rock_tmp);
-+
-+	snprintf(quotarootbuf, sizeof(quotarootbuf), "%s.*", mailboxname);
-+
-+	r =3D mboxlist_findall(&proxyd_namespace, quotarootbuf,
-+			     proxyd_userisadmin, proxyd_userid,
-+			     proxyd_authstate, quota_cb, server_rock);
-+    }
-+
-+    if (!r) {
-+	/* Do the referral */
-+	proxyd_refer(tag, server_rock, quotaroot);
-+	free(server_rock);
-+    } else {
-+	if(server_rock) free(server_rock);
-+	prot_printf(proxyd_out, "%s NO %s\r\n", tag, error_message(r));
-+    }
-+
-+    return;
-+
-+ badlist:
-+    prot_printf(proxyd_out, "%s BAD Invalid quota list in Setquota\r\n", =
tag);
-+    eatline(proxyd_in, c);
-+}
-+
-+#ifdef HAVE_SSL
-+/*
-+ * this implements the STARTTLS command, as described in RFC 2595.
-+ * one caveat: it assumes that no external layer is currently present.
-+ * if a client executes this command, information about the external
-+ * layer that was passed on the command line is disgarded. this should
-+ * be fixed.
-+ */
-+/* imaps - weather this is an imaps transaction or not */
-+void cmd_starttls(char *tag, int imaps)
-+{
-+    int result;
-+    int *layerp;
-+    sasl_ssf_t ssf;
-+    char *auth_id;
-+    =

-+    /* SASL and openssl have different ideas about whether ssf is signed =
*/
-+    layerp =3D (int *) &(ssf);
-+
-+    if (proxyd_starttls_done =3D=3D 1)
-+    {
-+	prot_printf(proxyd_out, "%s NO %s\r\n", tag, =

-+		    "TLS already active");
-+	return;
-+    }
-+
-+    result=3Dtls_init_serverengine("imap",
-+				 5,        /* depth to verify */
-+				 !imaps,   /* can client auth? */
-+				 !imaps);  /* TLSv1 only? */
-+
-+    if (result =3D=3D -1) {
-+
-+	syslog(LOG_ERR, "error initializing TLS");
-+
-+	if (imaps =3D=3D 0)
-+	    prot_printf(proxyd_out, "%s NO %s\r\n", =

-+			tag, "Error initializing TLS");
-+	else
-+	    fatal("tls_init() failed", EC_CONFIG);
-+
-+	return;
-+    }
-+
-+    if (imaps =3D=3D 0)
-+    {
-+	prot_printf(proxyd_out, "%s OK %s\r\n", tag,
-+		    "Begin TLS negotiation now");
-+	/* must flush our buffers before starting tls */
-+	prot_flush(proxyd_out);
-+    }
-+  =

-+    result=3Dtls_start_servertls(0, /* read */
-+			       1, /* write */
-+			       layerp,
-+			       &auth_id,
-+			       &tls_conn);
-+
-+    /* if error */
-+    if (result=3D=3D-1) {
-+	if (imaps =3D=3D 0)	{
-+	    prot_printf(proxyd_out, "%s NO Starttls failed\r\n", tag);
-+	    syslog(LOG_NOTICE, "STARTTLS failed: %s", proxyd_clienthost);
-+	    return;
-+	} else {
-+	    syslog(LOG_NOTICE, "imaps failed: %s", proxyd_clienthost);
-+	    fatal("tls_start_servertls() failed", EC_TEMPFAIL);
-+	    return;
-+	}
-+    }
-+
-+    /* tell SASL about the negotiated layer */
-+    result =3D sasl_setprop(proxyd_saslconn, SASL_SSF_EXTERNAL, &ssf);
-+    if (result !=3D SASL_OK) {
-+	fatal("sasl_setprop() failed: cmd_starttls()", EC_TEMPFAIL);
-+    }
-+    saslprops.ssf =3D ssf;
-+
-+    result =3D sasl_setprop(proxyd_saslconn, SASL_AUTH_EXTERNAL, auth_id);
-+    if (result !=3D SASL_OK) {
-+       fatal("sasl_setprop() failed: cmd_starttls()", EC_TEMPFAIL);
-+    }
-+    if(saslprops.authid) {
-+	free(saslprops.authid);
-+	saslprops.authid =3D NULL;
-+    }
-+    if(auth_id)
-+        saslprops.authid =3D xstrdup(auth_id);
-+
-+    /* tell the prot layer about our new layers */
-+    prot_settls(proxyd_in, tls_conn);
-+    prot_settls(proxyd_out, tls_conn);
-+
-+    proxyd_starttls_done =3D 1;
-+}
-+#else
-+void cmd_starttls(char *tag, int imaps)
-+{
-+    fatal("cmd_starttls() executed, but starttls isn't implemented!",
-+	  EC_SOFTWARE);
-+}
-+#endif /* HAVE_SSL */
-+
-+/*
-+ * Parse and perform a STATUS command
-+ * The command has been parsed up to the attribute list
-+ */
-+void cmd_status(char *tag, char *name)
-+{
-+    char mailboxname[MAX_MAILBOX_NAME+1];
-+    int r;
-+    char *server;
-+    struct backend *s =3D NULL;
-+
-+    r =3D (*proxyd_namespace.mboxname_tointernal)(&proxyd_namespace, name,
-+						proxyd_userid, mailboxname);
-+
-+    if (!r) r =3D mlookup(mailboxname, &server, NULL, NULL);
-+    if (!r && supports_referrals
-+	&& config_getswitch(IMAPOPT_PROXYD_ALLOW_STATUS_REFERRAL)) { =

-+	proxyd_refer(tag, server, name);
-+	/* Eat the argument */
-+	eatline(proxyd_in, prot_getc(proxyd_in));
-+	return;
-+    }
-+
-+    if (!r) s =3D proxyd_findserver(server);
-+    if (!r && !s) r =3D IMAP_SERVER_UNAVAILABLE;
-+    if (!r) {
-+	prot_printf(s->out, "%s Status {%d+}\r\n%s ", tag,
-+		    strlen(name), name);
-+	if (!pipe_command(s, 65536)) {
-+	    pipe_until_tag(s, tag, 0);
-+	}
-+	if (backend_current && s !=3D backend_current) {
-+	    char mytag[128];
-+	    =

-+	    proxyd_gentag(mytag, sizeof(mytag));
-+
-+	    prot_printf(backend_current->out, "%s Noop\r\n", mytag);
-+	    pipe_until_tag(backend_current, mytag, 0);
-+	}
-+    } else {
-+	eatline(proxyd_in, prot_getc(proxyd_in));
-+    }
-+
-+    if (!r) {
-+	prot_printf(proxyd_out, "%s %s", tag, s->last_result.s);
-+    } else {
-+	prot_printf(proxyd_out, "%s NO %s\r\n", tag, error_message(r));
-+    }
-+}
-+
-+#ifdef ENABLE_X_NETSCAPE_HACK
-+/*
-+ * Reply to Netscape's crock with a crock of my own
-+ */
-+void
-+cmd_netscape(tag)
-+    char *tag;
-+{
-+    const char *url;
-+    /* so tempting, and yet ... */
-+    /* url =3D "http://random.yahoo.com/ryl/"; */
-+    url =3D config_getstring(IMAPOPT_NETSCAPEURL);
-+
-+    /* I only know of three things to reply with: */
-+    prot_printf(proxyd_out,
-+"* OK [NETSCAPE] Carnegie Mellon Cyrus IMAP proxy\r\n* VERSION %s\r\n",
-+		CYRUS_VERSION);
-+    prot_printf(proxyd_out,
-+		"* ACCOUNT-URL %s\r\n%s OK %s\r\n",
-+		url, tag, error_message(IMAP_OK_COMPLETED));
-+
-+    /* no tagged response?!? */
-+}
-+#endif /* ENABLE_X_NETSCAPE_HACK */
-+
-+/* Callback for cmd_namespace to be passed to mboxlist_findall.
-+ * For each top-level mailbox found, print a bit of the response
-+ * if it is a shared namespace.  The rock is used as an integer in
-+ * order to ensure the namespace response is correct on a server with
-+ * no shared namespace.
-+ */
-+static int namespacedata(char *name, int matchlen __attribute__((unused)),
-+			 int maycreate __attribute__((unused)), void *rock)
-+{
-+    int* sawone =3D (int*) rock;
-+
-+    if (!name) {
-+	return 0;
-+    }
-+    =

-+    if ((!strncasecmp(name, "INBOX", 5) && (!name[5] || name[5] =3D=3D '.=
'))) {
-+	/* The user has a "personal" namespace. */
-+	sawone[NAMESPACE_INBOX] =3D 1;
-+    } else if (mboxname_isusermailbox(name, 0)) {
-+	/* The user can see the "other users" namespace. */
-+	sawone[NAMESPACE_USER] =3D 1;
-+    } else {
-+	/* The user can see the "shared" namespace. */
-+	sawone[NAMESPACE_SHARED] =3D 1;
-+    }
-+
-+    return 0;
-+}
-+
-+/*
-+ * Print out a response to the NAMESPACE command defined by
-+ * RFC 2342.
-+ */
-+void cmd_namespace(tag)
-+    char* tag;
-+{
-+    int sawone[3] =3D {0, 0, 0};
-+    char pattern[2] =3D {'%','\0'};
-+
-+    /* now find all the exciting toplevel namespaces -
-+     * we're using internal names here
-+     */
-+    mboxlist_findall(NULL, pattern, proxyd_userisadmin, proxyd_userid,
-+		     proxyd_authstate, namespacedata, (void*) sawone);
-+
-+    prot_printf(proxyd_out, "* NAMESPACE");
-+    if (sawone[NAMESPACE_INBOX]) {
-+	prot_printf(proxyd_out, " ((\"%s\" \"%c\"))",
-+		    proxyd_namespace.prefix[NAMESPACE_INBOX],
-+		    proxyd_namespace.hier_sep);
-+    } else {
-+	prot_printf(proxyd_out, " NIL");
-+    }
-+    if (sawone[NAMESPACE_USER]) {
-+	prot_printf(proxyd_out, " ((\"%s\" \"%c\"))",
-+		    proxyd_namespace.prefix[NAMESPACE_USER],
-+		    proxyd_namespace.hier_sep);
-+    } else {
-+	prot_printf(proxyd_out, " NIL");
-+    }
-+    if (sawone[NAMESPACE_SHARED]) {
-+	prot_printf(proxyd_out, " ((\"%s\" \"%c\"))",
-+		    proxyd_namespace.prefix[NAMESPACE_SHARED],
-+		    proxyd_namespace.hier_sep);
-+    } else {
-+	prot_printf(proxyd_out, " NIL");
-+    }
-+    prot_printf(proxyd_out, "\r\n");
-+
-+    prot_printf(proxyd_out, "%s OK %s\r\n", tag,
-+		error_message(IMAP_OK_COMPLETED));
-+}
-+
-+/*
-+ * Print 's' as a quoted-string or literal (but not an atom)
-+ */
-+void
-+printstring(s)
-+const char *s;
-+{
-+    const char *p;
-+    int len =3D 0;
-+
-+    /* Look for any non-QCHAR characters */
-+    for (p =3D s; *p && len < 1024; p++) {
-+	len++;
-+	if (*p & 0x80 || *p =3D=3D '\r' || *p =3D=3D '\n'
-+	    || *p =3D=3D '\"' || *p =3D=3D '%' || *p =3D=3D '\\') break;
-+    }
-+
-+    /* if it's too long, literal it */
-+    if (*p || len >=3D 1024) {
-+	prot_printf(proxyd_out, "{%u}\r\n%s", strlen(s), s);
-+    } else {
-+	prot_printf(proxyd_out, "\"%s\"", s);
-+    }
-+}
-+
-+/*
-+ * Print 's' as an atom, quoted-string, or literal
-+ */
-+void printastring(const char *s)
-+{
-+    const char *p;
-+    int len =3D 0;
-+
-+    if (imparse_isatom(s)) {
-+	prot_printf(proxyd_out, "%s", s);
-+	return;
-+    }
-+
-+    /* Look for any non-QCHAR characters */
-+    for (p =3D s; *p && len < 1024; p++) {
-+	len++;
-+	if (*p & 0x80 || *p =3D=3D '\r' || *p =3D=3D '\n'
-+	    || *p =3D=3D '\"' || *p =3D=3D '%' || *p =3D=3D '\\') break;
-+    }
-+
-+    /* if it's too long, literal it */
-+    if (*p || len >=3D 1024) {
-+	prot_printf(proxyd_out, "{%u}\r\n%s", strlen(s), s);
-+    } else {
-+	prot_printf(proxyd_out, "\"%s\"", s);
-+    }
-+}
-+
-+/*
-+ * Issue a MAILBOX untagged response
-+ */
-+static int mailboxdata(char *name, =

-+		       int matchlen __attribute__((unused)), =

-+		       int maycreate __attribute__((unused)), =

-+		       void* rock __attribute__((unused)))
-+{
-+    char mboxname[MAX_MAILBOX_PATH+1];
-+
-+    (*proxyd_namespace.mboxname_toexternal)(&proxyd_namespace, name,
-+					    proxyd_userid, mboxname);
-+    prot_printf(proxyd_out, "* MAILBOX %s\r\n", mboxname);
-+    return 0;
-+}
-+
-+/*
-+ * Issue a LIST or LSUB untagged response
-+ */
-+static void mstringdata(cmd, name, matchlen, maycreate)
-+char *cmd;
-+char *name;
-+int matchlen;
-+int maycreate;
-+{
-+    static char lastname[MAX_MAILBOX_PATH+1];
-+    static int lastnamedelayed =3D 0;
-+    static int lastnamenoinferiors =3D 0;
-+    static int sawuser =3D 0;
-+    int lastnamehassub =3D 0;
-+    int c;
-+    char mboxname[MAX_MAILBOX_PATH+1];
-+
-+    /* We have to reset the sawuser flag before each list command.
-+     * Handle it as a dirty hack.
-+     */
-+    if (cmd =3D=3D NULL) {
-+	sawuser =3D 0;
-+	return;
-+    }
-+    =

-+    if (lastnamedelayed) {
-+	if (name && strncmp(lastname, name, strlen(lastname)) =3D=3D 0 &&
-+	    name[strlen(lastname)] =3D=3D '.') {
-+	    lastnamehassub =3D 1;
-+	}
-+	prot_printf(proxyd_out, "* %s (%s) \"%c\" ", cmd,
-+		    lastnamenoinferiors ? "\\Noinferiors" :
-+		    lastnamehassub ? "\\HasChildren" : "\\HasNoChildren",
-+		    proxyd_namespace.hier_sep);
-+	(*proxyd_namespace.mboxname_toexternal)(&proxyd_namespace, lastname,
-+						proxyd_userid, mboxname);
-+	printstring(mboxname);
-+	prot_printf(proxyd_out, "\r\n");
-+	lastnamedelayed =3D lastnamenoinferiors =3D 0;
-+    }
-+
-+    /* Special-case to flush any final state */
-+    if (!name) {
-+	lastname[0] =3D '\0';
-+	return;
-+    }
-+
-+    /* Suppress any output of a partial match */
-+    if ((name[matchlen]
-+	 && strncmp(lastname, name, matchlen) =3D=3D 0
-+	 && (lastname[matchlen] =3D=3D '\0' || lastname[matchlen] =3D=3D '.'))) {
-+	return;
-+    }
-+	=

-+    /*
-+     * We can get a partial match for "user" multiple times with
-+     * other matches inbetween.  Handle it as a special case
-+     */
-+    if (matchlen =3D=3D 4 && strncasecmp(name, "user", 4) =3D=3D 0) {
-+	if (sawuser) return;
-+	sawuser =3D 1;
-+    }
-+
-+    strcpy(lastname, name);
-+    lastname[matchlen] =3D '\0';
-+
-+    if (!name[matchlen]) {
-+	lastnamedelayed =3D 1;
-+	if (!maycreate) lastnamenoinferiors =3D 1;
-+	return;
-+    }
-+
-+    c =3D name[matchlen];
-+    if (c) name[matchlen] =3D '\0';
-+    prot_printf(proxyd_out, "* %s (%s) \"%c\" ", cmd,
-+		c ? "\\HasChildren \\Noselect" : "",
-+		proxyd_namespace.hier_sep);
-+    (*proxyd_namespace.mboxname_toexternal)(&proxyd_namespace, name,
-+					    proxyd_userid, mboxname);
-+    printstring(mboxname);
-+    prot_printf(proxyd_out, "\r\n");
-+    if (c) name[matchlen] =3D c;
-+    return;
-+}
-+
-+/*
-+ * Issue a LIST untagged response
-+ */
-+static int listdata(char *name, int matchlen, int maycreate,
-+		    void *rock __attribute__((unused)))
-+{
-+    mstringdata("LIST", name, matchlen, maycreate);
-+    return 0;
-+}
-+
-+/*
-+ * Parse annotate fetch data.
-+ *
-+ * This is a generic routine which parses just the annotation data.
-+ * Any surrounding command text must be parsed elsewhere, ie,
-+ * GETANNOTATION, FETCH.
-+ */
-+
-+int getannotatefetchdata(char *tag,
-+			 struct strlist **entries, struct strlist **attribs)
-+{
-+    int c;
-+    static struct buf arg;
-+
-+    *entries =3D *attribs =3D NULL;
-+
-+    c =3D prot_getc(proxyd_in);
-+    if (c =3D=3D EOF) {
-+	prot_printf(proxyd_out,
-+		    "%s BAD Missing annotation entry\r\n", tag);
-+	goto baddata;
-+    }
-+    else if (c =3D=3D '(') {
-+	/* entry list */
-+	do {
-+	    c =3D getqstring(proxyd_in, proxyd_out, &arg);
-+	    if (c =3D=3D EOF) {
-+		prot_printf(proxyd_out,
-+			    "%s BAD Missing annotation entry\r\n", tag);
-+		goto baddata;
-+	    }
-+
-+	    /* add the entry to the list */
-+	    appendstrlist(entries, arg.s);
-+
-+	} while (c =3D=3D ' ');
-+
-+	if (c !=3D ')') {
-+	    prot_printf(proxyd_out,
-+			"%s BAD Missing close paren in annotation entry list \r\n",
-+			tag);
-+	    goto baddata;
-+	}
-+
-+	c =3D prot_getc(proxyd_in);
-+    }
-+    else {
-+	/* single entry -- add it to the list */
-+	prot_ungetc(c, proxyd_in);
-+	c =3D getqstring(proxyd_in, proxyd_out, &arg);
-+	if (c =3D=3D EOF) {
-+	    prot_printf(proxyd_out,
-+			"%s BAD Missing annotation entry\r\n", tag);
-+	    goto baddata;
-+	}
-+
-+	appendstrlist(entries, arg.s);
-+    }
-+
-+    if (c !=3D ' ' || (c =3D prot_getc(proxyd_in)) =3D=3D EOF) {
-+	prot_printf(proxyd_out,
-+		    "%s BAD Missing annotation attribute(s)\r\n", tag);
-+	goto baddata;
-+    }
-+
-+    if (c =3D=3D '(') {
-+	/* attrib list */
-+	do {
-+	    c =3D getnstring(proxyd_in, proxyd_out, &arg);
-+	    if (c =3D=3D EOF) {
-+		prot_printf(proxyd_out,
-+			    "%s BAD Missing annotation attribute(s)\r\n", tag);
-+		goto baddata;
-+	    }
-+
-+	    /* add the attrib to the list */
-+	    appendstrlist(attribs, arg.s);
-+
-+	} while (c =3D=3D ' ');
-+
-+	if (c !=3D ')') {
-+	    prot_printf(proxyd_out,
-+			"%s BAD Missing close paren in "
-+			"annotation attribute list\r\n", tag);
-+	    goto baddata;
-+	}
-+
-+	c =3D prot_getc(proxyd_in);
-+    }
-+    else {
-+	/* single attrib */
-+	prot_ungetc(c, proxyd_in);
-+	c =3D getqstring(proxyd_in, proxyd_out, &arg);
-+	    if (c =3D=3D EOF) {
-+		prot_printf(proxyd_out,
-+			    "%s BAD Missing annotation attribute\r\n", tag);
-+		goto baddata;
-+	    }
-+
-+	appendstrlist(attribs, arg.s);
-+   }
-+
-+    return c;
-+
-+  baddata:
-+    if (c !=3D EOF) prot_ungetc(c, proxyd_in);
-+    return EOF;
-+}
-+
-+/*
-+ * Parse annotate store data.
-+ *
-+ * This is a generic routine which parses just the annotation data.
-+ * Any surrounding command text must be parsed elsewhere, ie,
-+ * SETANNOTATION, STORE, APPEND.
-+ */
-+
-+int getannotatestoredata(char *tag, struct entryattlist **entryatts)
-+{
-+    int c;
-+    static struct buf entry, attrib, value;
-+    struct attvaluelist *attvalues =3D NULL;
-+
-+    *entryatts =3D NULL;
-+
-+    do {
-+	/* get entry */
-+	c =3D getqstring(proxyd_in, proxyd_out, &entry);
-+	if (c =3D=3D EOF) {
-+	    prot_printf(proxyd_out,
-+			"%s BAD Missing annotation entry\r\n", tag);
-+	    goto baddata;
-+	}
-+
-+	/* parse att-value list */
-+	if (c !=3D ' ' || (c =3D prot_getc(proxyd_in)) !=3D '(') {
-+	    prot_printf(proxyd_out,
-+			"%s BAD Missing annotation attribute-values list\r\n",
-+			tag);
-+	    goto baddata;
-+	}
-+
-+	do {
-+	    /* get attrib */
-+	    c =3D getqstring(proxyd_in, proxyd_out, &attrib);
-+	    if (c =3D=3D EOF) {
-+		prot_printf(proxyd_out,
-+			    "%s BAD Missing annotation attribute\r\n", tag);
-+		goto baddata;
-+	    }
-+
-+	    /* get value */
-+	    if (c !=3D ' ' ||
-+		(c =3D getnstring(proxyd_in, proxyd_out, &value)) =3D=3D EOF) {
-+		prot_printf(proxyd_out,
-+			    "%s BAD Missing annotation value\r\n", tag);
-+		goto baddata;
-+	    }
-+
-+	    /* add the attrib-value pair to the list */
-+	    appendattvalue(&attvalues, attrib.s, value.s);
-+
-+	} while (c =3D=3D ' ');
-+
-+	if (c !=3D ')') {
-+	    prot_printf(proxyd_out,
-+			"%s BAD Missing close paren in annotation "
-+			"attribute-values list\r\n", tag);
-+	    goto baddata;
-+	}
-+
-+	/* add the entry to the list */
-+	appendentryatt(entryatts, entry.s, attvalues);
-+	attvalues =3D NULL;
-+
-+	c =3D prot_getc(proxyd_in);
-+
-+    } while (c =3D=3D ' ');
-+
-+    return c;
-+
-+  baddata:
-+    if (attvalues) freeattvalues(attvalues);
-+    if (c !=3D EOF) prot_ungetc(c, proxyd_in);
-+    return EOF;
-+}
-+
-+/*
-+ * Output an entry/attribute-value list response.
-+ *
-+ * This is a generic routine which outputs just the annotation data.
-+ * Any surrounding response text must be output elsewhere, ie,
-+ * GETANNOTATION, FETCH. =

-+ */
-+void annotate_response(struct entryattlist *l)
-+{
-+    int islist; /* do we have more than one entry? */
-+
-+    if (!l) return;
-+
-+    islist =3D (l->next !=3D NULL);
-+
-+    if (islist) prot_printf(proxyd_out, "(");
-+
-+    while (l) {
-+	prot_printf(proxyd_out, "\"%s\"", l->entry);
-+
-+	/* do we have attributes?  solicited vs. unsolicited */
-+	if (l->attvalues) {
-+	    struct attvaluelist *av =3D l->attvalues;
-+
-+	    prot_printf(proxyd_out, " (");
-+	    while (av) {
-+		prot_printf(proxyd_out, "\"%s\" ", av->attrib);
-+		if (!strcasecmp(av->value, "NIL"))
-+		    prot_printf(proxyd_out, "NIL");
-+		else
-+		    prot_printf(proxyd_out, "\"%s\"", av->value);
-+
-+		if ((av =3D av->next) =3D=3D NULL)
-+		    prot_printf(proxyd_out, ")");
-+		else
-+		    prot_printf(proxyd_out, " ");
-+	    }
-+	}
-+	if ((l =3D l->next) !=3D NULL)
-+	    prot_printf(proxyd_out, " ");
-+    }
-+
-+    if (islist) prot_printf(proxyd_out, ")");
-+}
-+
-+/*
-+ * Perform a GETANNOTATION command
-+ *
-+ * The command has been parsed up to the entries
-+ */    =

-+void cmd_getannotation(char *tag, char *mboxpat)
-+{
-+    int c, r =3D 0;
-+    struct strlist *entries =3D NULL, *attribs =3D NULL;
-+
-+    c =3D getannotatefetchdata(tag, &entries, &attribs);
-+    if (c =3D=3D EOF) {
-+	eatline(proxyd_in, c);
-+	return;
-+    }
-+
-+    /* check for CRLF */
-+    if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+    if (c !=3D '\n') {
-+	prot_printf(proxyd_out,
-+		    "%s BAD Unexpected extra arguments to Getannotation\r\n",
-+		    tag);
-+	eatline(proxyd_in, c);
-+	goto freeargs;
-+    }
-+
-+    r =3D annotatemore_fetch(mboxpat, entries, attribs, &proxyd_namespace,
-+			   proxyd_userisadmin, proxyd_userid,
-+			   proxyd_authstate, proxyd_out);
-+
-+    if (r) {
-+	prot_printf(proxyd_out, "%s NO %s\r\n", tag, error_message(r));
-+    } else {
-+	prot_printf(proxyd_out, "%s OK %s\r\n",
-+		    tag, error_message(IMAP_OK_COMPLETED));
-+    }
-+    =

-+  freeargs:
-+    if (entries) freestrlist(entries);
-+    if (attribs) freestrlist(attribs);
-+
-+    return;
-+}
-+
-+/*
-+ * Perform a SETANNOTATION command
-+ *
-+ * The command has been parsed up to the entry-att list
-+ */    =

-+void cmd_setannotation(char *tag, char *mboxpat __attribute__((unused)))
-+{
-+    int c, r =3D 0;
-+    struct entryattlist *entryatts =3D NULL;
-+
-+    c =3D getannotatestoredata(tag, &entryatts);
-+    if (c =3D=3D EOF) {
-+	eatline(proxyd_in, c);
-+	return;
-+    }
-+
-+    /* check for CRLF */
-+    if (c =3D=3D '\r') c =3D prot_getc(proxyd_in);
-+    if (c !=3D '\n') {
-+	prot_printf(proxyd_out,
-+		    "%s BAD Unexpected extra arguments to Setannotation\r\n",
-+		    tag);
-+	eatline(proxyd_in, c);
-+	goto freeargs;
-+    }
-+
-+    r =3D annotatemore_store(mboxpat,
-+			   entryatts, &proxyd_namespace, proxyd_userisadmin,
-+			   proxyd_userid, proxyd_authstate);
-+
-+    if (r) {
-+	prot_printf(proxyd_out, "%s NO %s\r\n", tag, error_message(r));
-+    } else {
-+	prot_printf(proxyd_out, "%s OK %s\r\n", tag,
-+		    error_message(IMAP_OK_COMPLETED));
-+    }
-+
-+  freeargs:
-+    if (entryatts) freeentryatts(entryatts);
-+    return;
-+}
-+
-+/* Proxy GETANNOTATION commands to backend */
-+int annotate_fetch_proxy(const char *server, const char *mbox_pat,
-+			 struct strlist *entry_pat,
-+			 struct strlist *attribute_pat) =

-+{
-+    struct backend *be;
-+    struct strlist *l;
-+    char mytag[128];
-+    =

-+    assert(server && mbox_pat && entry_pat && attribute_pat);
-+    =

-+    be =3D proxyd_findserver(server);    =

-+    if(!be) return IMAP_SERVER_UNAVAILABLE;
-+
-+    /* Send command to remote */
-+    proxyd_gentag(mytag, sizeof(mytag));
-+    prot_printf(be->out, "%s GETANNOTATION \"%s\" (", mytag, mbox_pat);
-+    for(l=3Dentry_pat;l;l=3Dl->next) {
-+	prot_printf(be->out, "\"%s\"%s", l->s, l->next ? " " : "");
-+    }
-+    prot_printf(be->out, ") (");
-+    for(l=3Dattribute_pat;l;l=3Dl->next) {
-+	prot_printf(be->out, "\"%s\"%s", l->s, l->next ? " " : "");
-+    }
-+    prot_printf(be->out, ")\r\n");
-+    prot_flush(be->out);
-+
-+    /* Pipe the results.  Note that backend-current may also pipe us other
-+       messages. */
-+    pipe_until_tag(be, mytag, 0);
-+
-+    return 0;
-+}
-+
-+/* Proxy SETANNOTATION commands to backend */
-+int annotate_store_proxy(const char *server, const char *mbox_pat,
-+			 struct entryattlist *entryatts)
-+{
-+    struct backend *be;
-+    struct entryattlist *e;
-+    struct attvaluelist *av;
-+    char mytag[128];
-+    =

-+    assert(server && mbox_pat && entryatts);
-+    =

-+    be =3D proxyd_findserver(server);    =

-+    if(!be) return IMAP_SERVER_UNAVAILABLE;
-+
-+    /* Send command to remote */
-+    proxyd_gentag(mytag, sizeof(mytag));
-+    prot_printf(be->out, "%s SETANNOTATION \"%s\" (", mytag, mbox_pat);
-+    for (e =3D entryatts; e; e =3D e->next) {
-+	prot_printf(be->out, "\"%s\" (", e->entry);
-+
-+	for (av =3D e->attvalues; av; av =3D av->next) {
-+	    prot_printf(be->out, "\"%s\" \"%s\"%s", av->attrib, av->value,
-+			av->next ? " " : "");
-+	}
-+	prot_printf(be->out, ")");
-+	if (e->next) prot_printf(be->out, " ");
-+    }
-+    prot_printf(be->out, ")\r\n");
-+    prot_flush(be->out);
-+
-+    /* Pipe the results.  Note that backend-current may also pipe us other
-+       messages. */
-+    pipe_until_tag(be, mytag, 0);
-+
-+    return 0;
-+}
-+
-+/* Reset the given sasl_conn_t to a sane state */
-+static int reset_saslconn(sasl_conn_t **conn) =

-+{
-+    int ret;
-+    sasl_security_properties_t *secprops =3D NULL;
-+
-+    sasl_dispose(conn);
-+    /* do initialization typical of service_main */
-+    ret =3D sasl_server_new("imap", config_servername,
-+                         NULL, NULL, NULL,
-+                         NULL, 0, conn);
-+    if(ret !=3D SASL_OK) return ret;
-+
-+    if(saslprops.ipremoteport)
-+       ret =3D sasl_setprop(*conn, SASL_IPREMOTEPORT,
-+                          saslprops.ipremoteport);
-+    if(ret !=3D SASL_OK) return ret;
-+    =

-+    if(saslprops.iplocalport)
-+       ret =3D sasl_setprop(*conn, SASL_IPLOCALPORT,
-+                          saslprops.iplocalport);
-+    if(ret !=3D SASL_OK) return ret;
-+    =

-+    secprops =3D mysasl_secprops(SASL_SEC_NOPLAINTEXT);
-+    ret =3D sasl_setprop(*conn, SASL_SEC_PROPS, secprops);
-+    if(ret !=3D SASL_OK) return ret;
-+    /* end of service_main initialization excepting SSF */
-+
-+    /* If we have TLS/SSL info, set it */
-+    if(saslprops.ssf) {
-+       ret =3D sasl_setprop(*conn, SASL_SSF_EXTERNAL, &saslprops.ssf);
-+    } else {
-+       ret =3D sasl_setprop(*conn, SASL_SSF_EXTERNAL, &extprops_ssf);
-+    }
-+    if(ret !=3D SASL_OK) return ret;
-+
-+    if(saslprops.authid) {
-+       ret =3D sasl_setprop(*conn, SASL_AUTH_EXTERNAL, saslprops.authid);
-+       if(ret !=3D SASL_OK) return ret;
-+    }
-+    /* End TLS/SSL Info */
-+
-+    return SASL_OK;
-+}
 diff -urNad cyrus-imapd-2.2.13~/imap/version.h cyrus-imapd-2.2.13/imap/ver=
sion.h
---- cyrus-imapd-2.2.13~/imap/version.h	2007-06-16 15:05:06.000000000 +0100
-+++ cyrus-imapd-2.2.13/imap/version.h	2007-06-22 16:48:05.000000000 +0100
+--- cyrus-imapd-2.2.13~/imap/version.h	2007-06-22 17:04:30.000000000 +0100
++++ cyrus-imapd-2.2.13/imap/version.h	2007-06-22 17:16:52.000000000 +0100
 @@ -55,7 +55,7 @@
  =

  /* CAPABILITIES are now defined here, not including sasl ones */
@@ -5256,8 +41,8 @@
  	"CHILDREN MULTIAPPEND BINARY " \
  	"SORT THREAD=3DORDEREDSUBJECT THREAD=3DREFERENCES " \
 diff -urNad cyrus-imapd-2.2.13~/lib/imapoptions cyrus-imapd-2.2.13/lib/ima=
poptions
---- cyrus-imapd-2.2.13~/lib/imapoptions	2007-06-22 16:47:43.000000000 +0100
-+++ cyrus-imapd-2.2.13/lib/imapoptions	2007-06-22 16:48:05.000000000 +0100
+--- cyrus-imapd-2.2.13~/lib/imapoptions	2007-06-22 17:16:22.000000000 +0100
++++ cyrus-imapd-2.2.13/lib/imapoptions	2007-06-22 17:16:52.000000000 +0100
 @@ -653,6 +653,10 @@
     connections that these referrals would cause, thus resulting in a high=
er
     authentication load on the respective backend server. */
@@ -5269,890 +54,3 @@
  { "proxyservers", NULL, STRING }
  /* A list of users and groups that are allowed to proxy for other
     users, seperated by spaces.  Any user listed in this will be
-diff -urNad cyrus-imapd-2.2.13~/lib/imapoptions.orig cyrus-imapd-2.2.13/li=
b/imapoptions.orig
---- cyrus-imapd-2.2.13~/lib/imapoptions.orig	1970-01-01 01:00:00.000000000=
 +0100
-+++ cyrus-imapd-2.2.13/lib/imapoptions.orig	2007-06-22 16:47:43.000000000 =
+0100
-@@ -0,0 +1,883 @@
-+# things inside of C comments get copied to the manpage
-+# things starting with # are ignored
-+
-+/* .\" -*- nroff -*-
-+.TH IMAPD.CONF 5 "Project Cyrus" CMU
-+.\" =

-+.\" Copyright (c) 1998-2000 Carnegie Mellon University.  All rights reser=
ved.
-+.\"
-+.\" Redistribution and use in source and binary forms, with or without
-+.\" modification, are permitted provided that the following conditions
-+.\" are met:
-+.\"
-+.\" 1. Redistributions of source code must retain the above copyright
-+.\"    notice, this list of conditions and the following disclaimer. =

-+.\"
-+.\" 2. Redistributions in binary form must reproduce the above copyright
-+.\"    notice, this list of conditions and the following disclaimer in
-+.\"    the documentation and/or other materials provided with the
-+.\"    distribution.
-+.\"
-+.\" 3. The name "Carnegie Mellon University" must not be used to
-+.\"    endorse or promote products derived from this software without
-+.\"    prior written permission. For permission or any other legal
-+.\"    details, please contact  =

-+.\"      Office of Technology Transfer
-+.\"      Carnegie Mellon University
-+.\"      5000 Forbes Avenue
-+.\"      Pittsburgh, PA  15213-3890
-+.\"      (412) 268-4387, fax: (412) 268-7395
-+.\"      tech-transfer at andrew.cmu.edu
-+.\"
-+.\" 4. Redistributions of any form whatsoever must retain the following
-+.\"    acknowledgment:
-+.\"    "This product includes software developed by Computing Services
-+.\"     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
-+.\"
-+.\" CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
-+.\" THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-+.\" AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
-+.\" FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
-+.\" AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
-+.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+.\" =

-+.\" $Id: imapoptions,v 1.36 2006/03/30 15:49:58 murch Exp $
-+.SH NAME
-+imapd.conf \- IMAP configuration file
-+.SH DESCRIPTION
-+\fB/etc/imapd.conf\fR =

-+is the configuration file for the Cyrus IMAP server.  It defines
-+local parameters for IMAP. =

-+.PP
-+Each line of the \fB/etc/imapd.conf\fR file has the form
-+.IP
-+\fIoption\fR: \fIvalue\fR
-+.PP
-+where \fIoption\fR is the name of the configuration option being set
-+and \fIvalue\fR is the value that the configuration option is being
-+set to.
-+.PP
-+Blank lines and lines beginning with ``#'' are ignored.
-+.PP
-+For boolean and enumerated options, the values ``yes'', ``on'', ``t'',
-+``true'' and ``1'' turn the option on, the values ``no'', ``off'',
-+``f'', ``false'' and ``0'' turn the option off.
-+.SH FIELD DESCRIPTIONS
-+.PP
-+The sections below detail options that can be placed in the
-+\fB/etc/imapd.conf\fR file, and show each option's default value.
-+Some options have no default value, these are listed with
-+``<no default>''.  Some options default to the empty string, these
-+are listed with ``<none>''.
-+*/
-+
-+# OPTIONS
-+
-+{ "admins", "", STRING }
-+/* The list of userids with administrative rights.  Separate each userid
-+   with a space.  Sites using Kerberos authentication may use
-+   separate "admin" instances.
-+.PP
-+   Note that accounts used by users should not be administrators.
-+   Administrative accounts should not receive mail.  That is, if user
-+   "jbRo" is a user reading mail, he should not also be in the admins lin=
e.
-+   Some problems may occur otherwise, most notably the ability of
-+   administrators to create top-level mailboxes visible to users,
-+   but not writable by users. */
-+
-+{ "afspts_localrealms", NULL, STRING }
-+/* The list of realms which are to be treated as local, and thus stripped
-+   during identifier canoicalization (for the AFSPTS ptloader module).
-+   This is different from loginrealms in that it occurs later in the
-+   authorization process (as the user id is canonified for PTS lookup) */
-+
-+{ "afspts_mycell", NULL, STRING }
-+/* Cell to use for AFS PTS lookups.  Defaults to the local cell. */
-+
-+{ "allowallsubscribe", 0, SWITCH }
-+/* Allow subscription to nonexistent mailboxes.  This option is
-+   typically used on backend servers in a Murder so that users can
-+   subscribe to mailboxes that don't reside on their "home" server.
-+   This option can also be used as a workaround for IMAP clients which
-+   don't play well with nonexistent or unselectable mailboxes (eg.
-+   Microsoft Outlook). */
-+
-+{ "allowanonymouslogin", 0, SWITCH }
-+/* Permit logins by the user "anonymous" using any password.  Also
-+   allows use of the SASL ANONYMOUS mechanism. */
-+
-+{ "allowapop", 1, SWITCH }
-+/* Allow use of the POP3 APOP authentication command.
-+.PP
-+  Note that this command requires that SASL is compiled with APOP
-+  support, that the plaintext passwords are available in a SASL auxprop
-+  backend (eg. sasldb), and that the system can provide enough entropy
-+  (eg. from /dev/urandom) to create a challenge in the banner. */
-+
-+{ "allownewnews", 0, SWITCH }
-+/* Allow use of the NNTP NEWNEWS command.
-+.PP
-+  Note that this is a very expensive command and should only be
-+  enabled when absolutely necessary. */
-+
-+{ "allowplaintext", 1, SWITCH }
-+/* Allow the use of cleartext passwords on the wire. */
-+   =

-+{ "allowusermoves", 0, SWITCH }
-+/* Allow moving user accounts (with associated meta-data) via RENAME
-+   or XFER.
-+.PP
-+  Note that measures should be taken to make sure that the user being
-+  moved is not logged in, and can not login during the move.  Failure
-+  to do so may result in the user's meta-data (seen state,
-+  subscriptions, etc) being corrupted or out of date. */
-+   =

-+{ "altnamespace", 0, SWITCH }
-+/* Use the alternate IMAP namespace, where personal folders reside at the
-+   same level in the hierarchy as INBOX.
-+.PP
-+   This option ONLY applies where interaction takes place with the
-+   client/user.  Currently this is limited to the IMAP protocol (imapd)
-+   and Sieve scripts (lmtpd).  This option does NOT apply to admin tools
-+   such as cyradm (admins ONLY), reconstruct, quota, etc., NOR does it
-+   affect LMTP delivery of messages directly to mailboxes via
-+   plus-addressing. */
-+
-+{ "annotation_db", "skiplist", STRINGLIST("berkeley", "berkeley-hash", "s=
kiplist")}
-+/* The cyrusdb backend to use for mailbox annotations. */
-+
-+{ "auth_mech", "unix", STRINGLIST("unix", "pts", "krb", "krb5")}
-+/* The authorization mechanism to use. */
-+
-+{ "autocreatequota", 0, INT }
-+/* If nonzero, normal users may create their own IMAP accounts by
-+   creating the mailbox INBOX.  The user's quota is set to the value
-+   if it is positive, otherwise the user has unlimited quota. */
-+
-+{ "berkeley_cachesize", 512, INT }
-+/* Size (in kilobytes) of the shared memory buffer pool (cache) used
-+   by the berkeley environment.  The minimum allowed value is 20.  The
-+   maximum allowed value is 4194303 (4GB). */
-+
-+{ "berkeley_locks_max", 50000, INT }
-+/* Maximum number of locks to be held or requested in the berkeley
-+   environment. */
-+
-+{ "berkeley_txns_max", 100, INT }
-+/* Maximum number of transactions to be supported in the berkeley
-+   environment. */
-+
-+{ "client_timeout", 10, INT }
-+/* Number of seconds to wait before returning a timeout failure when
-+   performing a client connection (e.g. in a murder enviornment) */
-+
-+{ "configdirectory", NULL, STRING }
-+/* The pathname of the IMAP configuration directory.  This field is
-+   required. */
-+
-+{ "debug_command", NULL, STRING }
-+/* Debug command to be used by processes started with -D option.  The str=
ing
-+   is a C format string that gets 3 options: the first is the name of the
-+   executable (without path).  The second is the pid (integer) and the th=
ird
-+   is the service ID.  Example: /usr/local/bin/gdb /usr/cyrus/bin/%s %d */
-+
-+{ "defaultacl", "anyone lrs", STRING }
-+/* The Access Control List (ACL) placed on a newly-created (non-user)
-+   mailbox that does not have a parent mailbox. */
-+
-+{ "defaultdomain", NULL, STRING }
-+/* The default domain for virtual domain support */
-+
-+{ "defaultpartition", "default", STRING }
-+/* The partition name used by default for new mailboxes. */
-+
-+{ "deleteright", "c", STRING }
-+/* The right that a user needs to delete a mailbox. */
-+
-+{ "duplicate_db", "berkeley-nosync", STRINGLIST("berkeley", "berkeley-nos=
ync", "berkeley-hash", "berkeley-hash-nosync", "skiplist")}
-+/* The cyrusdb backend to use for the duplicate delivery suppression
-+   and sieve. */
-+
-+{ "duplicatesuppression", 1, SWITCH }
-+/* If enabled, lmtpd will suppress delivery of a message to a mailbox if
-+   a message with the same message-id (or resent-message-id) is recorded
-+   as having already been delivered to the mailbox.  Records the mailbox
-+   and message-id/resent-message-id of all successful deliveries. */
-+
-+{ "foolstupidclients", 0, SWITCH }
-+/* If enabled, only list the personal namespace when a LIST "*" is perfor=
med.
-+   (it changes the request to a LIST "INBOX*" */
-+
-+{ "force_sasl_client_mech", NULL, STRING }
-+/* Force preference of a given SASL mechanism for client side operations
-+   (e.g. murder enviornments).  This is separate from (and overridden by)
-+   the ability to use the <host shortname>_mechs option to set prefered
-+   mechanisms for a specific host */
-+
-+{ "fulldirhash", 0, SWITCH }
-+/* If enabled, uses an improved directory hashing scheme which hashes
-+   the entire username instead of using just the first letter.  This
-+   changes hash algorithm used for quota and user directories and if
-+   \fIhashimapspool\fR is enabled, the entire mail spool.
-+.PP
-+   Note that this option can NOT be changed on a live system.  The
-+   server must be quiesced and then the directories moved with the
-+   \fBrehash\fR utility. */
-+
-+{ "hashimapspool", 0, SWITCH }
-+/* If enabled, the partitions will also be hashed, in addition to the
-+   hashing done on configuration directories.  This is recommended if
-+   one partition has a very bushy mailbox tree. */
-+
-+# Commented out - there's no such thing as "hostname_mechs", but we need
-+# this for the man page
-+# { "hostname_mechs", NULL, STRING }
-+/* Force a particuar list of SASL mechanisms to be used when authenticati=
ng
-+   to the backend server hostname (where hostname is the short hostname of
-+   the server in question). If it is not specified it will query the serv=
er
-+   for available mechanisms and pick one to use. - Cyrus Murder */
-+
-+# Commented out - there's no such thing as "hostname_password", but we ne=
ed
-+# this for the man page
-+# { "hostname_password", NULL, STRING }
-+/* The password to use for authentication to the backend server hostname
-+   (where hostname is the short hostname of the server) - Cyrus Murder */
-+
-+{ "idlesocket", "{configdirectory}/socket/idle", STRING }
-+/* Unix domain socket that idled listens on. */
-+
-+{ "ignorereference", 0, SWITCH }
-+/* For backwards compatibility with Cyrus 1.5.10 and earlier -- ignore
-+  the reference argument in LIST or LSUB commands. */
-+
-+{ "imapidlepoll", 60, INT }
-+/* The interval (in seconds) for polling the mailbox for changes while
-+   running the IDLE command.  This option is used when idled can not
-+   be contacted or when polling is used exclusively.  The minimum
-+   value is 1.  A value of 0 will disable polling (and disable IDLE if
-+   polling is the only method available). */
-+
-+{ "imapidresponse", 1, SWITCH }
-+/* If enabled, the server responds to an ID command with a parameter =

-+   list containing: version, vendor, support-url, os, os-version,
-+   command, arguments, environment.  Otherwise the server returns NIL. */
-+
-+{ "imapmagicplus", 0, SWITCH }
-+/* Only list a restricted set of mailboxes via IMAP by using
-+   userid+namespace syntax as the authentication/authorization id.
-+   Using userid+ (with an empty namespace) will list only subscribed
-+   mailboxes. */ =

-+
-+{ "implicit_owner_rights", "lca", STRING }
-+/* The implicit Access Control List (ACL) for the owner of a mailbox. */
-+
-+# Commented out - there's no such thing as "@include", but we need
-+# this for the man page
-+# { "@include", NULL, STRING }
-+/* Directive which includes the specified file as part of the
-+   configuration.  If the path to the file is not absolute, CYRUS_PATH
-+   is prepended. */
-+
-+{ "ldap_authz", NULL, STRING }
-+/* SASL authorization ID for the LDAP server */
-+
-+{ "ldap_base", "", STRING }
-+/* Contains the LDAP base dn for the LDAP ptloader module */
-+
-+{ "ldap_bind_dn", NULL, STRING }
-+/* Bind DN for the connection to the LDAP server (simple bind).
-+   Do not use for anonymous simple binds */
-+
-+{ "ldap_deref", "never", STRINGLIST("search", "find", "always", "never") }
-+/* Specify how aliases dereferencing is handled during search. */
-+
-+{ "ldap_filter", "(uid=3D%u)", STRING }
-+/* Specify a filter that searches user identifiers.  The following tokens=
 can be
-+   used in the filter string:
-+
-+   %%   =3D %
-+   %u   =3D user
-+   %U   =3D user portion of %u (%U =3D test when %u =3D test at domain.tld)
-+   %d   =3D domain portion of %u if available (%d =3D domain.tld when %u =
=3D
-+          %test at domain.tld), otherwise same as %r
-+   %D   =3D user dn.  (use when ldap_member_method: filter)
-+   %1-9 =3D domain tokens (%1 =3D tld, %2 =3D domain when %d =3D domain.t=
ld)
-+
-+   ldap_filter is not used when ldap_sasl is enabled. */
-+
-+{ "ldap_group_base", "", STRING }
-+/* LDAP base dn for ldap_group_filter. */
-+
-+{ "ldap_group_filter", "(cn=3D%u)", STRING }
-+/* Specify a filter that searches for group identifiers.
-+   See ldap_filter for more options. */ =

-+
-+{ "ldap_group_scope", "sub", STRINGLIST("sub", "one", "base") }
-+/* Specify search scope for ldap_group_filter. */
-+
-+{ "ldap_id", NULL, STRING }
-+/* SASL authentication ID for the LDAP server */
-+
-+{ "ldap_mech", NULL, STRING }
-+/* SASL mechanism for LDAP authentication */
-+
-+{ "ldap_member_attribute", NULL, STRING }
-+/* See ldap_member_method. */
-+
-+{ "ldap_member_base", "", STRING }
-+/* LDAP base dn for ldap_member_filter. */
-+
-+{ "ldap_member_filter", "(member=3D%D)", STRING }
-+/* Specify a filter for "ldap_member_method: filter".  =

-+   See ldap_filter for more options. */ =

-+
-+{ "ldap_member_method", "attribute", STRINGLIST("attribute", "filter") }
-+/* Specify a group method.  The "attribute" method retrieves groups from =

-+   a multi-valued attribute specified in ldap_member_attribute.  =

-+
-+   The "filter" method uses a filter, specified by ldap_member_filter, to=
 find
-+   groups; ldap_member_attribute is a single-value attribute group name. =
*/
-+
-+{ "ldap_member_scope", "sub", STRINGLIST("sub", "one", "base") }
-+/* Specify search scope for ldap_member_filter. */
-+
-+{ "ldap_password", NULL, STRING }
-+/* Password for the connection to the LDAP server (SASL and simple bind).=
  =

-+   Do not use for anonymous simple binds */
-+
-+{ "ldap_realm", NULL, STRING }
-+/* SASL realm for LDAP authentication */
-+
-+{ "ldap_referrals", 0, SWITCH }
-+/* Specify whether or not the client should follow referrals. */
-+
-+{ "ldap_restart", 1, SWITCH }
-+/* Specify whether or not LDAP I/O operations are automatically restarted
-+   if they abort prematurely. */
-+
-+{ "ldap_sasl", 1, SWITCH }
-+/* Use SASL for LDAP binds in the LDAP PTS module. */
-+
-+{ "ldap_sasl_authc", NULL, STRING }
-+/* Depricated.  Use ldap_id */
-+
-+{ "ldap_sasl_authz", NULL, STRING }
-+/* Depricated.  Use ldap_authz */
-+
-+{ "ldap_sasl_mech", NULL, STRING }
-+/* Depricated.  Use ldap_mech */
-+
-+{ "ldap_sasl_password", NULL, STRING }
-+/* Depricated.  User ldap_password */
-+
-+{ "ldap_sasl_realm", NULL, STRING }
-+/* Depricated.  Use ldap_realm */
-+
-+{ "ldap_scope", "sub", STRINGLIST("sub", "one", "base") }
-+/* Specify search scope. */
-+
-+{ "ldap_servers", "ldap://localhost/", STRING }
-+/* Depricated.  Use ldap_uri */
-+
-+{ "ldap_size_limit", 1, INT }
-+/* Specify a number of entries for a search request to return. */
-+
-+{ "ldap_start_tls", 0, SWITCH }
-+/* Use StartTLS extended operation.  Do not use ldaps: ldap_uri when
-+   this option is enabled. */
-+
-+{ "ldap_time_limit", 5, INT }
-+/* Specify a number of seconds for a search request to complete. */
-+
-+{ "ldap_timeout", 5, INT }
-+/* Specify a number of seconds a search can take before timing out. */
-+
-+{ "ldap_tls_cacert_dir", NULL, STRING }
-+/* Path to directory with CA (Certificate Authority) certificates. */
-+
-+{ "ldap_tls_cacert_file", NULL, STRING }
-+/* File containing CA (Certificate Authority) certificate(s). */
-+
-+{ "ldap_tls_cert", NULL, STRING }
-+/* File containing the client certificate. */
-+
-+{ "ldap_tls_check_peer", 0, SWITCH }
-+/* Require and verify server certificate.  If this option is yes,
-+   you must specify ldap_tls_cacert_file or ldap_tls_cacert_dir. */
-+
-+{ "ldap_tls_ciphers", NULL, STRING }
-+/* List of SSL/TLS ciphers to allow.  The format of the string is
-+   described in ciphers(1). */
-+
-+{ "ldap_tls_key", NULL, STRING }
-+/* File containing the private client key. */
-+
-+{ "ldap_uri", NULL, STRING }
-+/* Contains a list of the URLs of all the LDAP servers when using the
-+   LDAP PTS module. */
-+
-+{ "ldap_version", 3, INT }
-+/* Specify the LDAP protocol version.  If ldap_start_tls and/or
-+   ldap_use_sasl are enabled, ldap_version will be automatiacally
-+   set to 3. */
-+
-+{ "lmtp_downcase_rcpt", 0, SWITCH }
-+/* If enabled, lmtpd will convert the recipient address to lowercase
-+   (up to a '+' character, if present). */
-+
-+{ "lmtp_over_quota_perm_failure", 0, SWITCH }
-+/* If enabled, lmtpd returns a permanent failure code when a user's
-+   mailbox is over quota.  By default, the failure is temporary,
-+   causing the MTA to queue the message and retry later. */
-+
-+{ "lmtpsocket", "{configdirectory}/socket/lmtp", STRING }
-+/* Unix domain socket that lmtpd listens on, used by deliver(8). This sho=
uld
-+   match the path specified in cyrus.conf(5). */
-+
-+# xxx how does this tie into virtual domains?
-+{ "loginrealms", "", STRING }
-+/* The list of remote realms whose users may authenticate using cross-rea=
lm
-+   authentication identifiers.  Seperate each realm name by a space.  (A
-+   cross-realm identity is considered any identity returned by SASL
-+   with an "@" in it.). */
-+
-+{ "loginuseacl", 0, SWITCH }
-+/* If enabled, any authentication identity which has \fBa\fR rights on a
-+   user's INBOX may log in as that user. */
-+
-+{ "logtimestamps", 0, SWITCH }
-+/* Include notations in the protocol telemetry logs indicating the number=
 of
-+   seconds since the last command or response. */
-+
-+{ "mailnotifier", NULL, STRING }
-+/* Notifyd(8) method to use for "MAIL" notifications.  If not set, "MAIL"
-+   notifications are disabled. */
-+
-+{ "maxmessagesize", 0, INT }
-+/* Maximum incoming LMTP message size.  If non-zero, lmtpd will reject
-+   messages larger than \fImaxmessagesize\fR bytes.  If set to 0, this
-+   will allow messages of any size (the default). */
-+
-+{ "mboxlist_db", "skiplist", STRINGLIST("flat", "berkeley", "berkeley-has=
h", "skiplist")}
-+/* The cyrusdb backend to use for the mailbox list. */
-+
-+# xxx badly worded
-+{ "mupdate_connections_max", 128, INT }
-+/* The max number of connections that a mupdate process will allow, this
-+   is related to the number of file descriptors in the mupdate process.
-+   Beyond this number connections will be immedately issued a BYE respons=
e. */
-+
-+{ "mupdate_authname", NULL, STRING }
-+/* The SASL username (Authentication Name) to use when authenticating to =
the
-+   mupdate server (if needed). */
-+
-+{ "mupdate_password", NULL, STRING }
-+/* The SASL password (if needed) to use when authenticating to the
-+   mupdate server. */
-+
-+{ "mupdate_port", 3905, INT }
-+/* The port of the mupdate server for the Cyrus Murder */
-+
-+{ "mupdate_realm", NULL, STRING }
-+/* The SASL realm (if needed) to use when authenticating to the mupdate
-+   server. */
-+
-+{ "mupdate_retry_delay", 20, INT }
-+/* The base time to wait between connection retries to the mupdate server=
. */
-+
-+{ "mupdate_server", NULL, STRING }
-+/* The mupdate server for the Cyrus Murder */
-+
-+{ "mupdate_workers_start", 5, INT }
-+/* The number of mupdate worker threads to start */
-+
-+{ "mupdate_workers_minspare", 2, INT }
-+/* The minimum number of idle mupdate worker threads */
-+
-+{ "mupdate_workers_maxspare", 10, INT }
-+/* The maximum number of idle mupdate worker threads */
-+
-+{ "mupdate_workers_max", 50, INT }
-+/* The maximum number of mupdate worker threads (overall) */
-+
-+{ "mupdate_username", "", STRING }
-+/* The SASL username (Authorization Name) to use when authenticating to
-+   the mupdate server */
-+
-+{ "netscapeurl", "http://asg.web.cmu.edu/cyrus/imapd/netscape-admin.html"=
, STRING }
-+/* If enabled at compile time, this specifies a URL to reply when
-+   Netscape asks the server where the mail administration HTTP server
-+   is.  The default is a site at CMU with a hopefully informative
-+   message; administrators should set this to a local resource with
-+   some information of greater use. */
-+
-+{ "newsmaster", "news", STRING }
-+/* Userid that is used for checking access controls when executing
-+   Usenet control messages.  For instance, to allow articles to be
-+   automatically deleted by cancel messages, give the "news" user
-+   the 'd' right on the desired mailboxes.  To allow newsgroups to be =

-+   automatically created, deleted and renamed by the corresponding
-+   control messages, give the "news" user the 'c' right on the desired
-+   mailbox hierarchies. */
-+
-+{ "newspeer", NULL, STRING }
-+/* A list of whitespace-separated news server specifications to which
-+   articles should be fed.  Each server specification is a string of
-+   the form [user[:pass]@]host[:port][/wildmat] where 'host' is the fully
-+   qualified hostname of the server, 'port' is the port on which the
-+   server is listening, 'user' and 'pass' are the authentication
-+   credentials and 'wildmat' is a pattern that specifies which groups
-+   should be fed.  If no 'port' is specified, port 119 is used.  If
-+   no 'wildmat' is specified, all groups are fed.  If 'user' is specified
-+   (even if empty), then the NNTP POST command will be used to feed
-+   the article to the server, otherwise the IHAVE command will be
-+   used.
-+.br
-+.sp
-+   A '@' may be used in place of '!' in the wildmat to prevent feeding
-+   articles cross-posted to the given group, otherwise cross-posted
-+   articles are fed if any part of the wildmat matches.  For example,
-+   the string "peer.example.com:*,!control.*, at local.*" would feed all
-+   groups except control messages and local groups to
-+   peer.example.com.  In the case of cross-posting to local groups,
-+   these articles would not be fed. */
-+
-+{ "newspostuser", NULL, STRING }
-+/* Userid used to deliver usenet articles to newsgroup folders
-+   (usually via lmtp2nntp).  For example, if set to "post", email sent
-+   to "post+comp.mail.imap" would be delivered to the "comp.mail.imap"
-+   folder.
-+.br
-+.sp
-+   When set, the Cyrus NNTP server will add a \fITo:\fR header to each
-+   incoming usenet article.  This \fITo:\fR header will contain email
-+   delivery addresses corresponding to each newsgroup in the
-+   \fINewsgroups:\fR header.  By default, a \fITo:\fR header is not
-+   added to usenet articles. */
-+
-+{ "newsprefix", NULL, STRING }
-+/* Prefix to be prepended to newsgroup names to make the corresponding
-+   IMAP mailbox names. */
-+
-+{ "notifysocket", "{configdirectory}/socket/notify", STRING }
-+/* Unix domain socket that the mail notification daemon listens on. */
-+
-+# Commented out - there's no such thing as "partition-name", but we need
-+# this for the man page
-+# { "partition-name", NULL, STRING }
-+/* The pathname of the partition \fIname\fR.  At least one field, for the
-+   partition named in the \fBdefaultpartition\fR option, is required.
-+   For example, if the value of the \fBdefaultpartion\fR option is
-+   \fBdefault\fR, then the \fBpartition-default\fR field is required. */
-+
-+{ "plaintextloginpause", 0, INT }
-+/* Number of seconds to pause after a successful plaintext login.  For
-+   systems that support strong authentication, this permits users to  =

-+   perceive a cost of using plaintext passwords.  (This does not
-+   affect the use of PLAIN in SASL authentications.) */
-+
-+{ "plaintextloginalert", NULL, STRING }
-+/* Message to send to client after a successful plaintext login. */
-+
-+{ "popexpiretime", -1, INT }
-+/* The number of days advertised as being the minimum a message may be
-+   left on the POP server before it is deleted (via the CAPA command,
-+   defined in the POP3 Extension Mechanism, which some clients may
-+   support).  "NEVER", the default, may be specified with a negative
-+   number.  The Cyrus POP3 server never deletes mail, no matter what  =

-+   the value of this parameter is.  However, if a site implements a =

-+   less liberal policy, it needs to change this parameter
-+   accordingly. */
-+
-+{ "popminpoll", 0, INT }
-+/* Set the minimum amount of time the server forces users to wait
-+   between successive POP logins, in minutes. */ =

-+
-+{ "poppollpadding", 1, INT }
-+/* Create a softer minimum poll restriction.  Allows \fIpoppollpadding\fR
-+   connections before the minpoll restriction is triggered.  Additionally,
-+   one padding entry is recovered every \fIpopminpoll\fR minutes.
-+   This allows for the occasional polling rate faster than popminpoll, =

-+   (i.e. for clients that require a send/recieve to send mail) but still =

-+   enforces the rate long-term.  Default is 1 (disabled).
-+.br
-+.sp
-+   The easiest way to think of it is a queue of past connections, with one
-+   slot being filled for every connection, and one slot being cleared =

-+   every \fIpopminpoll\fR minutes. When the queue is full, the user
-+   will not be able to check mail again until a slot is cleared.  If the =

-+   user waits a sufficent amount of time, they will get back many or all
-+   of the slots. */
-+
-+{ "poptimeout", 10, INT }
-+/* Set the length of the POP server's inactivity autologout timer,    =

-+   in minutes.  The minimum value is 10, the default. */
-+
-+{ "popuseacl", 0, SWITCH }
-+/* Enforce IMAP ACLs in the pop server.  Due to the nature of the POP3
-+   protocol, the only rights which are used by the pop server are 'r'
-+   and 'd' for the owner of the mailbox.  The 'r' right allows the
-+   user to open the mailbox and list/retrieve messages.  The 'd' right
-+   allows the user to delete messages. */
-+
-+{ "postmaster", "postmaster", STRING }
-+/* Username that is used as the 'From' address in rejection MDNs produced
-+   by sieve. */
-+   =

-+{ "postspec", NULL, STRING }
-+
-+{ "postuser", "", STRING }
-+/* Userid used to deliver messages to shared folders.  For example, if
-+   set to "bb", email sent to "bb+shared.blah" would be delivered to
-+   the "shared.blah" folder.  By default, an email address of
-+   "+shared.blah" would be used. */ =

-+
-+{ "proxy_authname", "proxy", STRING }
-+/* The authentication name to use when authenticating to a backend server
-+   in the Cyrus Murder. */
-+
-+{ "proxy_password", NULL, STRING }
-+/* The default password to use when authenticating to a backend server
-+   in the Cyrus Murder.  May be overridden on a host-specific basis using
-+   the hostname_password option. */
-+
-+{ "proxy_realm", NULL, STRING }
-+/* The authentication realm to use when authenticating to a backend server
-+   in the Cyrus Murder */
-+
-+{ "proxyd_allow_status_referral", 0, SWITCH }
-+/* Set to true to allow proxyd to issue referrals to clients that support=
 it
-+   when answering the STATUS command.  This is disabled by default since
-+   some clients issue many STATUS commands in a row, and do not cache the
-+   connections that these referrals would cause, thus resulting in a high=
er
-+   authentication load on the respective backend server. */
-+
-+{ "proxyservers", NULL, STRING }
-+/* A list of users and groups that are allowed to proxy for other
-+   users, seperated by spaces.  Any user listed in this will be
-+   allowed to login for any other user: use with caution. */ =

-+
-+{ "pts_module", "afskrb", STRINGLIST("afskrb", "ldap") }
-+/* The PTS module to use. */
-+
-+{ "ptloader_sock", NULL, STRING }
-+/* Unix domain socket that ptloader listens on.
-+   (defaults to configdir/ptclient/ptsock) */
-+
-+{ "ptscache_db", "berkeley", STRINGLIST("berkeley", "berkeley-hash", "ski=
plist")}
-+/* The cyrusdb backend to use for the pts cache. */
-+
-+{ "ptscache_timeout", 10800, INT }
-+/* The timeout (in seconds) for the PTS cache database when using the
-+   auth_krb_pts authorization method (default: 3 hours). */
-+
-+{ "ptskrb5_convert524", 1, SWITCH }
-+/* When using the AFSKRB ptloader module with Kerberos 5 canonicalization,
-+   do the final 524 conversion to get a n AFS style name (using '.' inste=
ad
-+   of '/', and using short names */
-+
-+{ "ptskrb5_strip_default_realm", 1, SWITCH }
-+/* When using the AFSKRB ptloader module with Kerberos 5 canonicalization,
-+   strip the default realm from the userid (this does not affect the stri=
pping
-+   of realms specified by the afspts_localrealms option) */
-+
-+{ "quota_db", "quotalegacy", STRINGLIST("flat", "berkeley", "berkeley-has=
h", "skiplist", "quotalegacy")}
-+/* The cyrusdb backend to use for quotas. */
-+
-+{ "quotawarn", 90, INT }
-+/* The percent of quota utilization over which the server generates
-+   warnings. */
-+
-+{ "quotawarnkb", 0, INT }
-+/* The maximum amount of free space (in kB) in which to give a quota
-+   warning (if this value is 0, or if the quota is smaller than this
-+   amount, than warnings are always given). */
-+
-+{ "reject8bit", 0, SWITCH }
-+/* If enabled, lmtpd rejects messages with 8-bit characters in the
-+   headers.  Otherwise, 8-bit characters are changed to `X'.  (A
-+   proper soultion to non-ASCII characters in headers is offered by  =

-+   RFC 2047 and its predecessors.) */
-+
-+{ "rfc2046_strict", 0, SWITCH }
-+/* If enabled, imapd will be strict (per RFC 2046) when matching MIME
-+   boundary strings.  This means that boundaries containing other
-+   boundaries as substrings will be treated as identical.  Since
-+   enabling this option will break some messages created by Eudora 5.1
-+   (and earlier), it is recommended that it be left disabled unless
-+   there is good reason to do otherwise. */
-+
-+{ "rfc3028_strict", 1, SWITCH }
-+/* If enabled, Sieve will be strict (per RFC 3028) with regards to
-+   which headers are allowed to be used in address and envelope tests.
-+   This means that only those headers which are defined to contain addres=
ses
-+   will be allowed in address tests and only "to" and "from" will be
-+   allowed in envelope tests.  When disabled, ANY grammatically correct h=
eader
-+   will be allowed. */
-+
-+# Commented out - used by libsasl
-+# { "sasl_auto_transition", 0, SWITCH }
-+/* If enabled, the SASL library will automatically create authentication
-+   secrets when given a plaintext password.  See the SASL documentation. =
*/
-+
-+{ "sasl_maximum_layer", 256, INT }
-+/* Maximum SSF (security strength factor) that the server will allow a
-+   client to negotiate. */
-+
-+{ "sasl_minimum_layer", 0, INT }
-+/* The minimum SSF that the server will allow a client to negotiate.
-+   A value of 1 requires integrity protection; any higher value  =

-+   requires some amount of encryption. */
-+
-+# Commented out - used by libsasl
-+# { "sasl_option", 0, STRING }
-+/* Any SASL option can be set by preceeding it with "sasl_".  This
-+   file overrides the SASL configuration file. */
-+
-+# Commented out - used by libsasl
-+# { "sasl_pwcheck_method", NULL, STRING }
-+/* The mechanism used by the server to verify plaintext passwords. =

-+   Possible values include "auxprop", "saslauthd", and "pwcheck". */
-+
-+{ "seenstate_db", "skiplist", STRINGLIST("flat", "berkeley", "berkeley-ha=
sh", "skiplist")}
-+/* The cyrusdb backend to use for the seen state. */
-+
-+{ "sendmail", "/usr/lib/sendmail", STRING }
-+/* The pathname of the sendmail executable.  Sieve invokes sendmail
-+   for sending rejections, redirects and vacation responses. */
-+
-+{ "servername", NULL, STRING }
-+/* This is the hostname visible in the greeting messages of the POP,
-+   IMAP and LMTP daemons. If it is unset, then the result returned
-+   from gethostname(2) is used. */
-+   =

-+{ "sharedprefix", "Shared Folders", STRING }
-+/* If using the alternate IMAP namespace, the prefix for the shared
-+   namespace.  The hierarchy delimiter will be automatically appended. */
-+
-+{ "sieve_maxscriptsize", 32, INT }
-+/* Maximum size (in kilobytes) any sieve script can be, enforced at
-+   submission by timsieved(8). */
-+
-+{ "sieve_maxscripts", 5, INT }
-+/* Maximum number of sieve scripts any user may have, enforced at
-+   submission by timsieved(8). */
-+   =

-+{ "sievedir", "/usr/sieve", STRING }
-+/* If sieveusehomedir is false, this directory is searched for Sieve
-+   scripts. */
-+
-+{ "sievenotifier", NULL, STRING }
-+/* Notifyd(8) method to use for "SIEVE" notifications.  If not set, "SIEV=
E"
-+   notifications are disabled.
-+.PP
-+   This method is only used when no method is specified in the script. */
-+
-+{ "sieveusehomedir", 0, SWITCH }
-+/* If enabled, lmtpd will look for Sieve scripts in user's home
-+   directories: ~user/.sieve. */
-+
-+{ "singleinstancestore", 1, SWITCH }
-+/* If enabled, imapd, lmtpd and nntpd attempt to only write one copy
-+   of a message per partition and create hard links, resulting in a
-+   potentially large disk savings. */
-+
-+{ "skiplist_unsafe", 0, SWITCH }
-+/* If enabled, this option forces the skiplist cyrusdb backend to
-+   not sync writes to the disk.  Enabling this option is NOT RECOMMENDED.=
 */
-+
-+{ "soft_noauth", 1, SWITCH }
-+/* If enabled, lmtpd returns temporary failures if the client does not
-+   successfully authenticate.  Otherwise lmtpd returns permanant failures
-+   (causing the mail to bounce immediately). */
-+
-+{ "srvtab", "", STRING }
-+/* The pathname of \fIsrvtab\fR file containing the server's private
-+   key.  This option is passed to the SASL library and overrides its
-+   default setting. */
-+
-+{ "subscription_db", "flat", STRINGLIST("flat", "berkeley", "berkeley-has=
h", "skiplist")}
-+/* The cyrusdb backend to use for the subscriptions list. */
-+
-+{ "syslog_prefix", NULL, STRING }
-+/* String to be appended to the process name in syslog entries. */
-+
-+{ "temp_path", "/tmp", STRING }
-+/* The pathname to store temporary files in */
-+
-+{ "timeout", 30, INT }   =

-+/* The length of the IMAP server's inactivity autologout timer,       =

-+   in minutes.  The minimum value is 30, the default. */
-+
-+{ "tls_ca_file", NULL, STRING }
-+/* File containing one or more Certificate Authority (CA) certificates. */
-+
-+{ "tls_ca_path", NULL, STRING }
-+/* Path to directory with certificates of CAs.  This directory must
-+   have filenames with the hashed value of the certificate (see
-+   openssl(XXX)). */
-+
-+{ "tlscache_db", "berkeley-nosync", STRINGLIST("berkeley", "berkeley-nosy=
nc", "berkeley-hash", "berkeley-hash-nosync", "skiplist")}
-+/* The cyrusdb backend to use for the TLS cache. */
-+
-+{ "tls_cert_file", NULL, STRING }
-+/* File containing the certificate presented for server authentication
-+   during STARTTLS.  A value of "disabled" will disable SSL/TLS. */
-+
-+{ "tls_cipher_list", "DEFAULT", STRING }
-+/* The list of SSL/TLS ciphers to allow.  The format of the string is
-+   described in ciphers(1). */
-+
-+{ "tls_key_file", NULL, STRING }
-+/* File containing the private key belonging to the server
-+   certificate.  A value of "disabled" will disable SSL/TLS. */
-+
-+{ "tls_require_cert", 0, SWITCH }
-+/* Require a client certificate for ALL services (imap, pop3, lmtp, sieve=
). */
-+
-+{ "tls_session_timeout", 1440, INT }
-+/* The length of time (in minutes) that a TLS session will be cached
-+   for later reuse.  The maximum value is 1440 (24 hours), the
-+   default.  A value of 0 will disable session caching. */
-+
-+{ "umask", "077", STRING }
-+/* The umask value used by various Cyrus IMAP programs. */
-+
-+{ "username_tolower", 1, SWITCH }
-+/* Convert usernames to all lowercase before login/authenticate.  This
-+   is useful with authentication backends which ignore case during
-+   username lookups (such as LDAP).  */
-+
-+{ "userprefix", "Other Users", STRING }
-+/* If using the alternate IMAP namespace, the prefix for the other users
-+   namespace.  The hierarchy delimiter will be automatically appended. */
-+
-+# xxx badly worded
-+{ "unix_group_enable", 1, SWITCH }
-+/* Should we look up groups when using auth_unix (disable this if you are
-+   not using groups in ACLs for your IMAP server, and you are using auth_=
unix
-+   with a backend (such as LDAP) that can make getgrent() calls very
-+   slow) */
-+
-+{ "unixhierarchysep", 0, SWITCH }
-+/* Use the UNIX separator character '/' for delimiting levels of
-+   mailbox hierarchy.  The default is to use the netnews separator
-+   character '.'. */
-+
-+{ "virtdomains", "off", ENUM("off", "userid", "on") }
-+/* Enable virtual domain support.  If enabled, the user's domain will
-+   be determined by splitting a fully qualified userid at the last '@'
-+   or '%' symbol.  If the userid is unqualified, and the virtdomains
-+   option is set to "on", then the domain will be determined by doing
-+   a reverse lookup on the IP address of the incoming network
-+   interface, otherwise the user is assumed to be in the default
-+   domain (if set). */
-+
-+/*
-+.SH SEE ALSO
-+.PP
-+\fBimapd(8)\fR, \fBpop3d(8)\fR, \fBnntpd(8)\fR, \fBlmtpd(8)\fR,
-+\fBtimsieved(8)\fR, \fBidled(8)\fR, \fBnotifyd(8)\fR,
-+\fBdeliver(8)\fR, \fBmaster(8)\fR, \fBciphers(1)\fR
-+*/




More information about the Pkg-Cyrus-imapd-Debian-devel mailing list