a6d65f
--- cyrus-imapd-2.3.13/notifyd/notifyd.c.autocreate	2008-03-24 20:59:32.000000000 +0100
a6d65f
+++ cyrus-imapd-2.3.13/notifyd/notifyd.c	2009-01-13 11:14:09.000000000 +0100
a6d65f
@@ -96,7 +96,7 @@
a6d65f
 
a6d65f
 #define NOTIFY_MAXSIZE 8192
a6d65f
 
a6d65f
-int do_notify()
a6d65f
+static int do_notify()
a6d65f
 {
a6d65f
     struct sockaddr_un sun_data;
a6d65f
     socklen_t sunlen = sizeof(sun_data);
a6d65f
--- cyrus-imapd-2.3.13/notifyd/Makefile.in.autocreate	2008-03-24 20:59:32.000000000 +0100
a6d65f
+++ cyrus-imapd-2.3.13/notifyd/Makefile.in	2009-01-13 11:14:09.000000000 +0100
a6d65f
@@ -71,10 +71,11 @@
a6d65f
 SERVICE=../master/service.o
a6d65f
 
a6d65f
 IMAP_LIBS = @IMAP_LIBS@ @LIB_RT@
a6d65f
+SIEVE_LIBS = @SIEVE_LIBS@
a6d65f
 IMAP_COM_ERR_LIBS = @IMAP_COM_ERR_LIBS@
a6d65f
 LIB_WRAP = @LIB_WRAP@
a6d65f
 LIBS = @ZEPHYR_LIBS@ @LIBS@ $(IMAP_COM_ERR_LIBS)
a6d65f
-DEPLIBS=../imap/mutex_fake.o ../imap/libimap.a ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
a6d65f
+DEPLIBS=../imap/mutex_fake.o ../imap/libimap.a $(SIEVE_LIBS) ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
a6d65f
 
a6d65f
 PURIFY=/usr/local/bin/purify
a6d65f
 PUREOPT=-best-effort
a6d65f
--- cyrus-imapd-2.3.13/imap/mboxlist.c.autocreate	2008-10-08 17:47:08.000000000 +0200
a6d65f
+++ cyrus-imapd-2.3.13/imap/mboxlist.c	2009-01-13 11:14:09.000000000 +0100
a6d65f
@@ -83,6 +83,12 @@
a6d65f
 #include "quota.h"
a6d65f
 #include "sync_log.h"
a6d65f
 
a6d65f
+#ifdef USE_SIEVE
a6d65f
+extern int autoadd_sieve(char *userid, 
a6d65f
+		const char *source_script);
a6d65f
+#endif
d0d307
+
d0d307
+
a6d65f
 #define DB config_mboxlist_db
a6d65f
 #define SUBDB config_subscription_db
a6d65f
 
a6d65f
@@ -100,11 +106,29 @@
a6d65f
 static int mboxlist_changequota(const char *name, int matchlen, int maycreate,
a6d65f
 				void *rock);
a6d65f
 
a6d65f
+static int mboxlist_autochangesub(char *name, int matchlen, int maycreate,
a6d65f
+			      void *rock);
cf58a5
+
a6d65f
+static int mboxlist_autosubscribe_sharedfolders(struct namespace *namespace,
a6d65f
+                        char *userid, char *auth_userid,
a6d65f
+                        struct auth_state *auth_state);
d0d307
+
a6d65f
 struct change_rock {
a6d65f
     struct quota *quota;
a6d65f
     struct txn **tid;
a6d65f
 };
a6d65f
 
a6d65f
+/*
a6d65f
+ * Struct needed to be passed as void *rock to
a6d65f
+ * mboxlist_autochangesub();
a6d65f
+ */
a6d65f
+struct changesub_rock_st {
a6d65f
+        char *userid;
a6d65f
+        char *auth_userid;
a6d65f
+        struct auth_state *auth_state;
a6d65f
+};
d0d307
+
d0d307
+
a6d65f
 #define FNAME_SUBSSUFFIX ".sub"
a6d65f
 
a6d65f
 /*
a6d65f
@@ -3383,3 +3407,349 @@
a6d65f
 
a6d65f
     return(config_delete_mode == IMAP_ENUM_DELETE_MODE_DELAYED);
a6d65f
 }
d0d307
+
a6d65f
+/*
a6d65f
+ * Automatically subscribe user to *ALL* shared folders,
a6d65f
+ * one has permissions to be subscribed to.
a6d65f
+ * INBOX subfolders are excluded.
a6d65f
+ */
a6d65f
+static int mboxlist_autochangesub(char *name, int matchlen, int maycreate,
a6d65f
+                        void *rock) {
d0d307
+
a6d65f
+  struct changesub_rock_st *changesub_rock = (struct changesub_rock_st *) rock;
a6d65f
+  char *userid = changesub_rock->userid;
a6d65f
+  char *auth_userid = changesub_rock->auth_userid;
a6d65f
+  struct auth_state *auth_state = changesub_rock->auth_state;
a6d65f
+  int r;
d0d307
+
d0d307
+
a6d65f
+  if((strlen(name) == 5 && !strncmp(name, "INBOX", 5)) || /* Exclude INBOX */
a6d65f
+     (strlen(name) > 5  && !strncmp(name, "INBOX.",6)) || /* Exclude INBOX subfolders */
a6d65f
+     (strlen(name) > 4  && !strncmp(name, "user.", 5)))   /* Exclude other users' folders */
a6d65f
+	  return 0;
d0d307
+
a6d65f
+     
a6d65f
+  r = mboxlist_changesub(name, userid, auth_state, 1, 0);
d0d307
+
a6d65f
+  if (r) {
a6d65f
+      syslog(LOG_WARNING,
a6d65f
+             "autosubscribe: User %s to folder %s, subscription failed: %s",
a6d65f
+             auth_userid, name, error_message(r));
a6d65f
+  } else {
a6d65f
+      syslog(LOG_NOTICE,
a6d65f
+             "autosubscribe: User %s to folder %s, subscription succeeded",
a6d65f
+             auth_userid, name);
a6d65f
+  }
d0d307
+
a6d65f
+  return 0;
a6d65f
+}
d0d307
+
a6d65f
+#define SEP '|'
d0d307
+
a6d65f
+/*
a6d65f
+ * Automatically subscribe user to a shared folder.
a6d65f
+ * Subscription is done successfully, if the shared
a6d65f
+ * folder exists and the user has the necessary 
a6d65f
+ * permissions.
a6d65f
+ */
a6d65f
+static int mboxlist_autosubscribe_sharedfolders(struct namespace *namespace,
a6d65f
+                        char *userid, char *auth_userid,
a6d65f
+                        struct auth_state *auth_state) {
a6d65f
+        
a6d65f
+    const char *sub ;
a6d65f
+    char *p, *q, *next_sub;
a6d65f
+    char folder[MAX_MAILBOX_NAME+1], name[MAX_MAILBOX_NAME+1], mailboxname[MAX_MAILBOX_NAME+1];
a6d65f
+    int len;
a6d65f
+    int r = 0;
a6d65f
+    int subscribe_all_sharedfolders = 0;
d0d307
+
a6d65f
+    subscribe_all_sharedfolders = config_getswitch(IMAPOPT_AUTOSUBSCRIBE_ALL_SHAREDFOLDERS);
d0d307
+
a6d65f
+    /*
a6d65f
+     * If subscribeallsharedfolders is set to yes in imapd.conf, then
a6d65f
+     * subscribe user to every shared folder one has the apropriate 
a6d65f
+     * permissions.
a6d65f
+     */
a6d65f
+    if(subscribe_all_sharedfolders) {
a6d65f
+       char pattern[MAX_MAILBOX_PATH+1];
a6d65f
+       struct changesub_rock_st changesub_rock;
d0d307
+
a6d65f
+       strcpy(pattern, "*");
a6d65f
+       changesub_rock.userid = userid;
a6d65f
+       changesub_rock.auth_userid = auth_userid;
a6d65f
+       changesub_rock.auth_state = auth_state;
d0d307
+
a6d65f
+       r = mboxlist_findall(namespace, pattern, 0, userid,
a6d65f
+                            auth_state, mboxlist_autochangesub, &changesub_rock);
d0d307
+
a6d65f
+       return r;
a6d65f
+    }
d0d307
+
a6d65f
+    if ((sub=config_getstring(IMAPOPT_AUTOSUBSCRIBESHAREDFOLDERS)) == NULL)
a6d65f
+       return r;
d0d307
+
a6d65f
+    next_sub = (char *) sub;
a6d65f
+    while (*next_sub) {
a6d65f
+        for (p = next_sub ; isspace((int) *p) || *p == SEP ; p++);
a6d65f
+        for (next_sub = p ; *next_sub && *next_sub != SEP ; next_sub++);
a6d65f
+        for (q = next_sub ; q > p && (isspace((int) *q) || *q == SEP || !*q) ; q--);
a6d65f
+        if (!*p ) continue;
d0d307
+
a6d65f
+        len = q - p + 1;
a6d65f
+        /* Check for folder length */
a6d65f
+        if (len  > sizeof(folder)-1)
a6d65f
+                continue;
d0d307
+
a6d65f
+        if (!r) {
a6d65f
+                strncpy(folder, p, len);
a6d65f
+                folder[len] = '\0';
d0d307
+
a6d65f
+               strlcpy(name, namespace->prefix[NAMESPACE_SHARED], sizeof(name));
a6d65f
+               len = strlcat(name, folder, sizeof(name));
d0d307
+
a6d65f
+               r = (namespace->mboxname_tointernal) (namespace, name, userid,
a6d65f
+                                                                  mailboxname);
a6d65f
+       }
a6d65f
+                                                                  
a6d65f
+        if (!r)
a6d65f
+               r = mboxlist_changesub(mailboxname, userid, auth_state, 1, 0);
d0d307
+
a6d65f
+        if (!r) {
a6d65f
+                syslog(LOG_NOTICE, "autosubscribe: User %s to %s succeeded", 
a6d65f
+                       userid, folder);
a6d65f
+        } else {
a6d65f
+                syslog(LOG_WARNING, "autosubscribe: User %s to %s failed: %s", 
a6d65f
+                       userid, folder, error_message(r));
a6d65f
+                r = 0;
a6d65f
+        }
a6d65f
+    }
d0d307
+
a6d65f
+    return r;
a6d65f
+}
d0d307
+
d0d307
+
d0d307
+
a6d65f
+int mboxlist_autocreateinbox(struct namespace *namespace,
a6d65f
+                        char *userid,
a6d65f
+                        struct auth_state *auth_state,
a6d65f
+                        char *mailboxname, int autocreatequota) {
a6d65f
+    char name [MAX_MAILBOX_NAME+1];
a6d65f
+    char folder [MAX_MAILBOX_NAME+1];
a6d65f
+    char *auth_userid = NULL;
a6d65f
+    char *partition = NULL;
a6d65f
+    const char *crt;
a6d65f
+    const char *sub;
a6d65f
+    char *p, *q, *next_crt, *next_sub;
a6d65f
+    int len;
a6d65f
+    int r = 0;
a6d65f
+    int numcrt = 0;
a6d65f
+    int numsub = 0;
a6d65f
+#ifdef USE_SIEVE
a6d65f
+    const char *source_script;
a6d65f
+#endif
d0d307
+
d0d307
+
d0d307
+
a6d65f
+    auth_userid = auth_canonuser(auth_state);
a6d65f
+    if (auth_userid == NULL) {
a6d65f
+         /*
a6d65f
+          * Couldn't get cannon userid
a6d65f
+          */
a6d65f
+          syslog(LOG_ERR,
a6d65f
+                 "autocreateinbox: Could not get canonified userid for user %s", userid);
a6d65f
+          return IMAP_PARTITION_UNKNOWN;
a6d65f
+    }
d0d307
+
a6d65f
+    /* Added this for debug information. */
a6d65f
+    syslog(LOG_DEBUG, "autocreateinbox: autocreate inbox for user %s was called", auth_userid);
d0d307
+
a6d65f
+   /*
a6d65f
+    * While this is not needed for admins
a6d65f
+    * and imap_admins accounts, it would be
a6d65f
+    * better to separate *all* admins and
a6d65f
+    * proxyservers from normal accounts
a6d65f
+    * (accounts that have mailboxes).
a6d65f
+    * UOA Specific note(1): Even if we do not
a6d65f
+    * exclude these servers-classes here,
a6d65f
+    * UOA specific code, will neither return
a6d65f
+    * role, nor create INBOX, because none of these
a6d65f
+    * administrative accounts belong to  the
a6d65f
+    * mailRecipient objectclass, or have imapPartition.
a6d65f
+    * UOA Specific note(2): Another good reason for doing
a6d65f
+    * this, is to prevent the code, from getting into
a6d65f
+    * cyrus_ldap.c because of the continues MSA logins to LMTPd.
a6d65f
+    */
d0d307
+
a6d65f
+   /*
a6d65f
+    * admins and the coresponding imap
a6d65f
+    * service, had already been excluded.
a6d65f
+    */
d0d307
+
a6d65f
+   /*
a6d65f
+    * Do we really need group membership
a6d65f
+    * for admins or service_admins?
a6d65f
+    */
a6d65f
+    if (global_authisa(auth_state, IMAPOPT_ADMINS)) return 0;
cf58a5
+
a6d65f
+   /*
a6d65f
+    * Do we really need group membership
a6d65f
+    * for proxyservers?
a6d65f
+    */
a6d65f
+    if (global_authisa(auth_state, IMAPOPT_PROXYSERVERS)) return 0;
d0d307
+
a6d65f
+    /* 
a6d65f
+     * Check if user belongs to the autocreate_users group. This option
a6d65f
+     * controls for whom the mailbox may be automatically created. Default
a6d65f
+     * value for this option is 'anyone'. So, if not declared, all mailboxes
a6d65f
+     * will be created.
a6d65f
+     */
a6d65f
+    if (!global_authisa(auth_state, IMAPOPT_AUTOCREATE_USERS)) {
a6d65f
+	    syslog(LOG_DEBUG, "autocreateinbox: User %s does not belong to the autocreate_users. No mailbox is created",
a6d65f
+			    auth_userid);
a6d65f
+	    return IMAP_MAILBOX_NONEXISTENT;
a6d65f
+    }
d0d307
+
a6d65f
+#if 0
a6d65f
+        /*
a6d65f
+         * Get Partition info or return.
a6d65f
+         * (Here you should propably use
a6d65f
+         * you own "get_partition(char *userid)"
a6d65f
+         * function. Otherwise all new INBOXes will be
a6d65f
+         * created into whatever partition has been declared
a6d65f
+         * as default in your imapd.conf)
a6d65f
+         */
d0d307
+
a6d65f
+        partition = get_partition(userid);
a6d65f
+        if (partition == NULL) {
a6d65f
+            /*
a6d65f
+             * Couldn't get partition info
a6d65f
+             */
a6d65f
+            syslog(LOG_ERR,
a6d65f
+                   "Could not get imapPartition info for user %s", userid);
a6d65f
+            return IMAP_PARTITION_UNKNOWN;
a6d65f
+        }
a6d65f
+#endif
cf58a5
+
a6d65f
+    r = mboxlist_createmailbox(mailboxname, MAILBOX_FORMAT_NORMAL, NULL,
a6d65f
+                                      1, userid, auth_state, 0, 0, 0);
a6d65f
+
a6d65f
+    if (!r && autocreatequota > 0)
a6d65f
+        r = mboxlist_setquota(mailboxname, autocreatequota, 0);
a6d65f
+
a6d65f
+    if (!r)
a6d65f
+        r = mboxlist_changesub(mailboxname, userid,
a6d65f
+                              auth_state, 1, 1);
a6d65f
+
a6d65f
+    if (!r) {
a6d65f
+       syslog(LOG_NOTICE, "autocreateinbox: User %s, INBOX was successfully created in partition %s", 
a6d65f
+               auth_userid, partition == NULL ? "default" : partition);
a6d65f
+    } else {
a6d65f
+       syslog(LOG_ERR, "autocreateinbox: User %s, INBOX failed. %s", 
a6d65f
+               auth_userid, error_message(r));
a6d65f
+    }
a6d65f
+
a6d65f
+#if 0
a6d65f
+    /* Allocated from get_partition, and not needed any more */
a6d65f
+    free_partition(partition);
a6d65f
+#endif
a6d65f
+
a6d65f
+    if (r) return r;
a6d65f
+
a6d65f
+    /* INBOX's subfolders */
a6d65f
+    if ((crt=config_getstring(IMAPOPT_AUTOCREATEINBOXFOLDERS)))
a6d65f
+        sub=config_getstring(IMAPOPT_AUTOSUBSCRIBEINBOXFOLDERS);
a6d65f
+
a6d65f
+    /* Roll through crt */
a6d65f
+    next_crt = (char *) crt;
a6d65f
+    while (next_crt!=NULL && *next_crt) {
a6d65f
+          for (p = next_crt ; isspace((int) *p) || *p == SEP ; p++);
a6d65f
+          for (next_crt = p ; *next_crt && *next_crt != SEP ; next_crt++);
a6d65f
+          for (q = next_crt ; q > p && (isspace((int) *q) || *q == SEP || !*q); q--);
a6d65f
+
a6d65f
+          if (!*p) continue;
a6d65f
+
a6d65f
+          len = q - p + 1;
a6d65f
+
a6d65f
+          /* First time we check for length */
a6d65f
+          if (len > sizeof(folder) - 5)
a6d65f
+              r = IMAP_MAILBOX_BADNAME;
a6d65f
+
a6d65f
+          if (!r) {
a6d65f
+                  strncpy(folder, p, len);
a6d65f
+                  folder[len] = '\0';
a6d65f
+
a6d65f
+                  strlcpy(name, namespace->prefix[NAMESPACE_INBOX], sizeof(name));
a6d65f
+                  len = strlcat(name, folder, sizeof(name));
a6d65f
+          }
a6d65f
+
a6d65f
+          if (!r)
a6d65f
+            r = (namespace->mboxname_tointernal) (namespace, name, userid,
a6d65f
+                                                 mailboxname);
a6d65f
+          if (!r)
a6d65f
+             r = mboxlist_createmailbox(mailboxname, MAILBOX_FORMAT_NORMAL, NULL,
a6d65f
+                                            1, userid, auth_state, 0, 0, 0);
a6d65f
+
a6d65f
+          if (!r) {
a6d65f
+            numcrt++;
a6d65f
+            syslog(LOG_NOTICE, "autocreateinbox: User %s, subfolder %s creation succeeded.", 
a6d65f
+               auth_userid, name);
a6d65f
+         } else {
a6d65f
+             syslog(LOG_WARNING, "autocreateinbox: User %s, subfolder %s creation failed. %s", 
a6d65f
+               auth_userid, name, error_message(r));
a6d65f
+             r=0;
a6d65f
+             continue;
a6d65f
+          }
a6d65f
+
a6d65f
+          /* Roll through sub */
a6d65f
+          next_sub = (char *) sub;
a6d65f
+          while (next_sub!=NULL && *next_sub) {
a6d65f
+                for (p = next_sub ; isspace((int) *p) || *p == SEP ; p++);
a6d65f
+                for (next_sub = p ; *next_sub && *next_sub != SEP ; next_sub++);
a6d65f
+                for (q = next_sub ; q > p && (isspace((int) *q) || *q == SEP || !*q) ; q--);
a6d65f
+                if (!*p ) continue;
a6d65f
+
a6d65f
+                len = q - p + 1;
a6d65f
+
a6d65f
+                if (len != strlen(folder) || strncmp(folder, p, len))
a6d65f
+                    continue;
a6d65f
+
a6d65f
+                r = mboxlist_changesub(mailboxname, userid, auth_state, 1, 1);
a6d65f
+
a6d65f
+               if (!r) {
a6d65f
+                   numsub++;
a6d65f
+                   syslog(LOG_NOTICE,"autocreateinbox: User %s, subscription to %s succeeded",
a6d65f
+                       auth_userid, name);
a6d65f
+               } else
a6d65f
+                    syslog(LOG_WARNING, "autocreateinbox: User %s, subscription to  %s failed. %s",
a6d65f
+                       auth_userid, name, error_message(r));
a6d65f
+
a6d65f
+                break;
a6d65f
+         }
a6d65f
+    }
a6d65f
+
a6d65f
+    if (crt!=NULL && *crt)
a6d65f
+       syslog(LOG_INFO, "User %s, Inbox subfolders, created %d, subscribed %d", 
a6d65f
+               auth_userid, numcrt, numsub);
a6d65f
+
a6d65f
+    /*
a6d65f
+     * Check if shared folders are available for subscription.
a6d65f
+     */
a6d65f
+    mboxlist_autosubscribe_sharedfolders(namespace, userid, auth_userid, auth_state);
a6d65f
+
a6d65f
+#ifdef USE_SIEVE
a6d65f
+    /*
a6d65f
+     * Here the autocreate sieve script feature is iniated from.
a6d65f
+     */
a6d65f
+    source_script = config_getstring(IMAPOPT_AUTOCREATE_SIEVE_SCRIPT);
a6d65f
+ 
a6d65f
+    if (source_script) {
a6d65f
+        if (!autoadd_sieve(userid, source_script))
a6d65f
+            syslog(LOG_NOTICE, "autocreate_sieve: User %s, default sieve script creation succeeded", auth_userid);
a6d65f
+        else
a6d65f
+            syslog(LOG_WARNING, "autocreate_sieve: User %s, default sieve script creation failed", auth_userid);
a6d65f
+    }
a6d65f
+#endif
a6d65f
+
a6d65f
+    return r;
a6d65f
+}
a6d65f
+
a6d65f
--- cyrus-imapd-2.3.13/imap/autosieve.c.autocreate	2009-01-13 11:14:09.000000000 +0100
a6d65f
+++ cyrus-imapd-2.3.13/imap/autosieve.c	2009-01-13 11:14:09.000000000 +0100
Tomas Janousek 686149
@@ -0,0 +1,590 @@
d0d307
+#include <stdio.h>
d0d307
+#include <stdlib.h>
d0d307
+#include <string.h>
d0d307
+
d0d307
+#ifdef HAVE_UNISTD_H
d0d307
+#include <unistd.h>
d0d307
+#endif
d0d307
+
d0d307
+#include <errno.h>
d0d307
+#include <sys/types.h>
d0d307
+#include <sys/stat.h>
d0d307
+#include <sys/uio.h>
d0d307
+#include <fcntl.h>
d0d307
+#include <ctype.h>
d0d307
+#include <time.h>
d0d307
+#include <syslog.h>
d0d307
+#include <com_err.h>
d0d307
+#include <config.h>
d0d307
+
d0d307
+#include "global.h"
d0d307
+#include "util.h"
Tomas Janousek 686149
+#include "xmalloc.h"
Tomas Janousek 686149
+#include "xstrlcpy.h"
Tomas Janousek 686149
+#include "xstrlcat.h"
d0d307
+#include "mailbox.h"
d0d307
+#include "imap_err.h"
d0d307
+#include "sieve_interface.h"
d0d307
+#include "script.h"
d0d307
+
d0d307
+#define TIMSIEVE_FAIL 	-1
d0d307
+#define TIMSIEVE_OK 	0
d0d307
+#define MAX_FILENAME	1024
d0d307
+
d0d307
+static int get_script_name(char *sievename, size_t buflen, const char *filename);
d0d307
+static int get_script_dir(char *sieve_script_dir, size_t buflen, char *userid, const char *sieve_dir);
d0d307
+int autoadd_sieve(char *userid, const char *source_script);
d0d307
+
Tomas Janousek 686149
+//static void fatal(const char *s, int code);
d0d307
+static void foo(void);
d0d307
+static int sieve_notify(void *ac __attribute__((unused)),
d0d307
+                        void *interp_context __attribute__((unused)),
d0d307
+                        void *script_context __attribute__((unused)),
d0d307
+                        void *message_context __attribute__((unused)),
d0d307
+                        const char **errmsg __attribute__((unused)));
d0d307
+static int mysieve_error(int lineno, const char *msg,
d0d307
+                  void *i __attribute__((unused)), void *s);
d0d307
+static int is_script_parsable(FILE *stream, char **errstr, sieve_script_t **ret);
d0d307
+
d0d307
+
d0d307
+sieve_vacation_t vacation2 = {
d0d307
+    0,                          /* min response */
d0d307
+    0,                          /* max response */
d0d307
+    (sieve_callback *) &foo,    /* autorespond() */
d0d307
+    (sieve_callback *) &foo     /* send_response() */
d0d307
+};
d0d307
+
d0d307
+
d0d307
+/*
d0d307
+ * Find the name of the sieve script
d0d307
+ * given the source script and compiled script names
d0d307
+ */
d0d307
+static int get_script_name(char *sievename, size_t buflen, const char *filename)
d0d307
+{
d0d307
+  char *p;
d0d307
+  int r;
d0d307
+
d0d307
+  p = strrchr(filename, '/');
d0d307
+  if (p == NULL)
d0d307
+      p = (char *) filename;
d0d307
+  else
d0d307
+      p++;
d0d307
+
d0d307
+  r = strlcpy(sievename, p, buflen) - buflen;
d0d307
+  return (r >= 0 || r == -buflen ? 1 : 0);
d0d307
+}
d0d307
+
d0d307
+
d0d307
+/*
d0d307
+ * Find the directory where the sieve scripts of the user
d0d307
+ * reside
d0d307
+ */
d0d307
+static int get_script_dir(char *sieve_script_dir, size_t buflen, char *userid, const char *sieve_dir)
d0d307
+{
d0d307
+    char *user = NULL, *domain = NULL;
d0d307
+
d0d307
+    /* Setup the user and the domain */
d0d307
+    if(config_virtdomains && (domain = strchr(userid, '@'))) {
d0d307
+        user = (char *) xmalloc((domain - userid +1) * sizeof(char));
d0d307
+        strlcpy(user, userid, domain - userid + 1);
d0d307
+        domain++;
d0d307
+    } else
d0d307
+        user = userid;
d0d307
+
d0d307
+    /*  Find the dir path where the sieve scripts of the user will reside */   
d0d307
+    if (config_virtdomains && domain) {
d0d307
+         if(snprintf(sieve_script_dir, buflen, "%s%s%c/%s/%c/%s/",
Tomas Janousek 14dc34
+              sieve_dir, FNAME_DOMAINDIR, dir_hash_c(domain, config_fulldirhash), domain, dir_hash_c(user,config_fulldirhash), user) >= buflen) {
d0d307
+                 free(user);
d0d307
+                 return 1;
d0d307
+ 	 }
d0d307
+    } else {
d0d307
+         if(snprintf(sieve_script_dir, buflen, "%s/%c/%s/", 
Tomas Janousek 14dc34
+     	      sieve_dir, dir_hash_c(user,config_fulldirhash), user) >= buflen) 
d0d307
+                 return 1;
d0d307
+    }
d0d307
+
d0d307
+    /* Free the xmalloced user memory, reserved above */
d0d307
+    if(user != userid)
d0d307
+        free(user);
d0d307
+
d0d307
+    return 0;
d0d307
+}
d0d307
+
d0d307
+int autoadd_sieve(char *userid, const char *source_script)
d0d307
+{   
d0d307
+    sieve_script_t *s = NULL;
d0d307
+    bytecode_info_t *bc = NULL;
d0d307
+    char *err = NULL;
d0d307
+    FILE *in_stream, *out_fp;
d0d307
+    int out_fd, in_fd, r, k;
d0d307
+    int do_compile = 0;
d0d307
+    const char *sieve_dir = NULL;
d0d307
+    const char *compiled_source_script = NULL;
d0d307
+    char sievename[MAX_FILENAME];
d0d307
+    char sieve_script_name[MAX_FILENAME];
d0d307
+    char sieve_script_dir[MAX_FILENAME];
d0d307
+    char sieve_bcscript_name[MAX_FILENAME];
d0d307
+    char sieve_default[MAX_FILENAME];
d0d307
+    char sieve_tmpname[MAX_FILENAME];
d0d307
+    char sieve_bctmpname[MAX_FILENAME];
d0d307
+    char sieve_bclink_name[MAX_FILENAME];
d0d307
+    char buf[4096];
d0d307
+    mode_t oldmask;
d0d307
+    struct stat statbuf;
d0d307
+
d0d307
+    /* We don't support using the homedirectory, like timsieved */
d0d307
+    if (config_getswitch(IMAPOPT_SIEVEUSEHOMEDIR)) {
d0d307
+        syslog(LOG_WARNING,"autocreate_sieve: autocreate_sieve does not work with sieveusehomedir option in imapd.conf");
d0d307
+        return 1;
d0d307
+    }
d0d307
+
d0d307
+    /* Check if sievedir is defined in imapd.conf */
d0d307
+    if(!(sieve_dir = config_getstring(IMAPOPT_SIEVEDIR))) { 
d0d307
+        syslog(LOG_WARNING, "autocreate_sieve: sievedir option is not defined. Check imapd.conf");
d0d307
+        return 1;
d0d307
+    }
d0d307
+
d0d307
+    /* Check if autocreate_sieve_compiledscript is defined in imapd.conf */
d0d307
+    if(!(compiled_source_script  = config_getstring(IMAPOPT_AUTOCREATE_SIEVE_COMPILEDSCRIPT))) {
d0d307
+        syslog(LOG_WARNING, "autocreate_sieve: autocreate_sieve_compiledscript option is not defined. Compiling it");
d0d307
+        do_compile = 1;
d0d307
+    }
d0d307
+
d0d307
+    if(get_script_dir(sieve_script_dir, sizeof(sieve_script_dir), userid, sieve_dir)) {
d0d307
+        syslog(LOG_WARNING, "autocreate_sieve: Cannot find sieve scripts directory");
d0d307
+        return 1;
d0d307
+    }
d0d307
+
d0d307
+    if (get_script_name(sievename, sizeof(sievename), source_script)) {
d0d307
+        syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve script %s", source_script);
d0d307
+        return 1;
d0d307
+    }
d0d307
+
d0d307
+    if(snprintf(sieve_tmpname, sizeof(sieve_tmpname), "%s%s.script.NEW",sieve_script_dir, sievename) >= sizeof(sieve_tmpname)) {
d0d307
+        syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
d0d307
+        return 1;
d0d307
+    }
d0d307
+    if(snprintf(sieve_bctmpname, sizeof(sieve_bctmpname), "%s%s.bc.NEW",sieve_script_dir, sievename) >= sizeof(sieve_bctmpname)) {
d0d307
+        syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
d0d307
+        return 1;
d0d307
+    }    
d0d307
+    if(snprintf(sieve_script_name, sizeof(sieve_script_name), "%s%s.script",sieve_script_dir, sievename) >= sizeof(sieve_script_name)) {
d0d307
+        syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
d0d307
+        return 1;
d0d307
+    }
d0d307
+    if(snprintf(sieve_bcscript_name, sizeof(sieve_bcscript_name), "%s%s.bc",sieve_script_dir, sievename) >= sizeof(sieve_bcscript_name)) {
d0d307
+        syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
d0d307
+        return 1;
d0d307
+    }
d0d307
+    if(snprintf(sieve_default, sizeof(sieve_default), "%s%s",sieve_script_dir,"defaultbc") >= sizeof(sieve_default)) {
d0d307
+        syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
d0d307
+        return 1;
d0d307
+    }
d0d307
+    if(snprintf(sieve_bclink_name, sizeof(sieve_bclink_name), "%s.bc", sievename) >= sizeof(sieve_bclink_name))  {
d0d307
+        syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
d0d307
+        return 1;
d0d307
+    }
d0d307
+
d0d307
+    /* Check if a default sieve filter alrady exists */
d0d307
+    if(!stat(sieve_default,&statbuf)) {
d0d307
+        syslog(LOG_WARNING,"autocreate_sieve: Default sieve script already exists");
d0d307
+        fclose(in_stream);
d0d307
+        return 1;
d0d307
+    }
d0d307
+
d0d307
+    /* Open the source script. if there is a problem with that exit */
d0d307
+    in_stream = fopen(source_script, "r");
d0d307
+    if(!in_stream) {
d0d307
+        syslog(LOG_WARNING,"autocreate_sieve: Unable to open sieve script %s. Check permissions",source_script);
d0d307
+        return 1;
d0d307
+    }
d0d307
+    
d0d307
+    
d0d307
+    /* 
d0d307
+     * At this point we start the modifications of the filesystem 
d0d307
+     */
d0d307
+
d0d307
+    /* Create the directory where the sieve scripts will reside */
d0d307
+    r = cyrus_mkdir(sieve_script_dir, 0755);
d0d307
+    if(r == -1) {
d0d307
+        /* If this fails we just leave */
d0d307
+        syslog(LOG_WARNING,"autocreate_sieve: Unable to create directory %s. Check permissions",sieve_script_name);
d0d307
+        return 1;
d0d307
+    }
d0d307
+
d0d307
+    /*
d0d307
+     * We open the file that will be used as the bc file. If this file exists, overwrite it 
d0d307
+     * since something bad has happened. We open the file here so that this error checking is
d0d307
+     * done before we try to open the rest of the files to start copying etc. 
d0d307
+     */
d0d307
+    out_fd = open(sieve_bctmpname, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
d0d307
+    if(out_fd < 0) {
d0d307
+        if(errno == EEXIST) {
d0d307
+            syslog(LOG_WARNING,"autocreate_sieve: File %s already exists. Probaly left over. Ignoring",sieve_bctmpname);
d0d307
+        } else if (errno == EACCES) {
d0d307
+            syslog(LOG_WARNING,"autocreate_sieve: No access to create file %s. Check permissions",sieve_bctmpname);
d0d307
+            fclose(in_stream);
d0d307
+            return 1;
d0d307
+        } else {
d0d307
+            syslog(LOG_WARNING,"autocreate_sieve: Unable to create %s. Unknown error",sieve_bctmpname);
d0d307
+            fclose(in_stream);
d0d307
+            return 1;
d0d307
+        }
d0d307
+    }
d0d307
+
d0d307
+    if(!do_compile && compiled_source_script && (in_fd = open(compiled_source_script, O_RDONLY)) != -1) {
d0d307
+        while((r = read(in_fd, buf, sizeof(buf))) > 0) {
d0d307
+            if((k=write(out_fd, buf,r)) < 0) {
d0d307
+                syslog(LOG_WARNING, "autocreate_sieve: Error writing to file: %s, error: %d", sieve_bctmpname, errno);
d0d307
+                close(out_fd);
d0d307
+                close(in_fd);
d0d307
+                fclose(in_stream);
d0d307
+                unlink(sieve_bctmpname);
d0d307
+                return 1;
d0d307
+           }
d0d307
+        } 
d0d307
+
d0d307
+        if(r == 0) { /* EOF */
d0d307
+            close(out_fd);
d0d307
+            close(in_fd);
d0d307
+        } else if (r < 0) {
d0d307
+            syslog(LOG_WARNING, "autocreate_sieve: Error reading compiled script file: %s. Will try to compile it", 
d0d307
+                           compiled_source_script);
d0d307
+            close(in_fd);
d0d307
+            do_compile = 1;
d0d307
+            if(lseek(out_fd, 0, SEEK_SET)) {
d0d307
+                syslog(LOG_WARNING, "autocreate_sieve: Major IO problem. Aborting");
d0d307
+                return 1;
d0d307
+            }
d0d307
+        }
d0d307
+        close(in_fd);
d0d307
+    } else {
d0d307
+        if(compiled_source_script)
d0d307
+              syslog(LOG_WARNING,"autocreate_sieve: Problem opening compiled script file: %s. Compiling it", compiled_source_script);
d0d307
+        do_compile = 1;
d0d307
+    }
d0d307
+
d0d307
+
d0d307
+    /* Because we failed to open a precompiled bc sieve script, we compile one */
d0d307
+    if(do_compile) {
d0d307
+       if(is_script_parsable(in_stream,&err, &s) == TIMSIEVE_FAIL) {
d0d307
+            if(err && *err) {
d0d307
+               syslog(LOG_WARNING,"autocreate_sieve: Error while parsing script %s.",err);
d0d307
+               free(err);
d0d307
+            } else
d0d307
+                syslog(LOG_WARNING,"autocreate_sieve: Error while parsing script");
d0d307
+    
d0d307
+            unlink(sieve_bctmpname);
d0d307
+            fclose(in_stream);
d0d307
+            close(out_fd);
d0d307
+            return 1;
d0d307
+        }
d0d307
+
d0d307
+        /* generate the bytecode */
d0d307
+        if(sieve_generate_bytecode(&bc, s) == TIMSIEVE_FAIL) {
d0d307
+            syslog(LOG_WARNING,"autocreate_sieve: problem compiling sieve script");
d0d307
+            /* removing the copied script and cleaning up memory */
d0d307
+            unlink(sieve_bctmpname);
d0d307
+            sieve_script_free(&s);
d0d307
+            fclose(in_stream);
d0d307
+            close(out_fd);
d0d307
+            return 1;
d0d307
+        }
d0d307
+
d0d307
+        if(sieve_emit_bytecode(out_fd, bc) == TIMSIEVE_FAIL) {
d0d307
+            syslog(LOG_WARNING,"autocreate_sieve: problem emiting sieve script");
d0d307
+            /* removing the copied script and cleaning up memory */
d0d307
+            unlink(sieve_bctmpname);
d0d307
+            sieve_free_bytecode(&bc);
d0d307
+            sieve_script_free(&s);
d0d307
+            fclose(in_stream);
d0d307
+            close(out_fd);
d0d307
+            return 1;
d0d307
+        }
d0d307
+
d0d307
+        /* clean up the memory */
d0d307
+        sieve_free_bytecode(&bc);
d0d307
+        sieve_script_free(&s);
d0d307
+    }
d0d307
+
d0d307
+    close(out_fd);
d0d307
+    rewind(in_stream);
d0d307
+
d0d307
+    /* Copy the initial script */
d0d307
+    oldmask = umask(077);
d0d307
+    if((out_fp = fopen(sieve_tmpname, "w")) == NULL) {
d0d307
+        syslog(LOG_WARNING,"autocreate_sieve: Unable to open %s destination sieve script", sieve_tmpname);
d0d307
+        unlink(sieve_bctmpname);
d0d307
+        umask(oldmask);
d0d307
+        fclose(in_stream);
d0d307
+        return 1;
d0d307
+    }
d0d307
+    umask(oldmask);
d0d307
+
d0d307
+    while((r = fread(buf,sizeof(char), sizeof(buf), in_stream))) {
d0d307
+        if( fwrite(buf,sizeof(char), r, out_fp) != r) {
d0d307
+            syslog(LOG_WARNING,"autocreate_sieve: Problem writing to sieve script file: %s",sieve_tmpname);
d0d307
+            fclose(out_fp);
d0d307
+            unlink(sieve_tmpname);
d0d307
+            unlink(sieve_bctmpname);
d0d307
+            fclose(in_stream);
d0d307
+            return 1;
d0d307
+        }
d0d307
+    }
d0d307
+    
d0d307
+    if(feof(in_stream)) {
d0d307
+        fclose(out_fp);
d0d307
+    } else { /* ferror */
d0d307
+        fclose(out_fp);
d0d307
+        unlink(sieve_tmpname);
d0d307
+        unlink(sieve_bctmpname);
d0d307
+        fclose(in_stream);
d0d307
+        return 1;
d0d307
+    }
d0d307
+
d0d307
+    /* Renaming the necessary stuff */
d0d307
+    if(rename(sieve_tmpname, sieve_script_name)) {
d0d307
+        unlink(sieve_tmpname);
d0d307
+        unlink(sieve_bctmpname);
d0d307
+        return 1;
d0d307
+    }
d0d307
+
d0d307
+    if(rename(sieve_bctmpname, sieve_bcscript_name)) {
d0d307
+        unlink(sieve_bctmpname);
d0d307
+        unlink(sieve_bcscript_name);
d0d307
+        return 1;
d0d307
+    }
d0d307
+
d0d307
+    /* end now with the symlink */
d0d307
+    if(symlink(sieve_bclink_name, sieve_default)) {
d0d307
+        if(errno != EEXIST) {
d0d307
+            syslog(LOG_WARNING, "autocreate_sieve: problem making the default link.");
d0d307
+            /* Lets delete the files */
d0d307
+            unlink(sieve_script_name);
d0d307
+            unlink(sieve_bcscript_name);
d0d307
+        }
d0d307
+    }
d0d307
+
d0d307
+    /* 
d0d307
+     * If everything has succeeded AND we have compiled the script AND we have requested
d0d307
+     * to generate the global script so that it is not compiled each time then we create it.
d0d307
+     */
d0d307
+    if(do_compile && 
d0d307
+          config_getswitch(IMAPOPT_GENERATE_COMPILED_SIEVE_SCRIPT)) {
d0d307
+
d0d307
+        if(!compiled_source_script) {
d0d307
+            syslog(LOG_WARNING, "autocreate_sieve: To save a compiled sieve script, autocreate_sieve_compiledscript must have been defined in imapd.conf");
d0d307
+            return 0;
d0d307
+        }
d0d307
+
d0d307
+        if(snprintf(sieve_tmpname, sizeof(sieve_tmpname), "%s.NEW", compiled_source_script) >= sizeof(sieve_tmpname))
d0d307
+            return 0;
d0d307
+
d0d307
+        /*
d0d307
+         * Copy everything from the newly created bc sieve sieve script.
d0d307
+         */
d0d307
+        if((in_fd = open(sieve_bcscript_name, O_RDONLY))<0) {
d0d307
+            return 0;
d0d307
+        }
d0d307
+
d0d307
+        if((out_fd = open(sieve_tmpname, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
d0d307
+            if(errno == EEXIST) {
d0d307
+               /* Someone is already doing this so just bail out. */
d0d307
+               syslog(LOG_WARNING, "autocreate_sieve: %s already exists. Some other instance processing it, or it is left over", sieve_tmpname);
d0d307
+                close(in_fd);
d0d307
+                return 0; 
d0d307
+            } else if (errno == EACCES) {
d0d307
+                syslog(LOG_WARNING,"autocreate_sieve: No access to create file %s. Check permissions",sieve_tmpname);
d0d307
+                close(in_fd);
d0d307
+                return 0;
d0d307
+            } else {
d0d307
+                syslog(LOG_WARNING,"autocreate_sieve: Unable to create %s",sieve_tmpname);
d0d307
+                close(in_fd);
d0d307
+                return 0;
d0d307
+            }
d0d307
+        }
d0d307
+
d0d307
+        while((r = read(in_fd, buf, sizeof(buf))) > 0) {
d0d307
+            if((k = write(out_fd,buf,r)) < 0) {
d0d307
+                syslog(LOG_WARNING, "autocreate_sieve: Error writing to file: %s, error: %d", sieve_tmpname, errno);
d0d307
+                close(out_fd);
d0d307
+                close(in_fd);
d0d307
+                unlink(sieve_tmpname);
d0d307
+                return 0;
d0d307
+           }
d0d307
+        }
d0d307
+
d0d307
+        if(r == 0 ) { /*EOF */
d0d307
+            close(out_fd);
d0d307
+            close(in_fd);
d0d307
+        } else if (r < 0) {
d0d307
+                syslog(LOG_WARNING, "autocreate_sieve: Error writing to file: %s, error: %d", sieve_tmpname, errno);
d0d307
+                close(out_fd);
d0d307
+                close(in_fd);
d0d307
+                unlink(sieve_tmpname);
d0d307
+                return 0;
d0d307
+        }
d0d307
+
d0d307
+        /* Rename the temporary created sieve script to its final name. */
d0d307
+        if(rename(sieve_tmpname, compiled_source_script)) {
d0d307
+            if(errno != EEXIST) {
d0d307
+               unlink(sieve_tmpname);
d0d307
+               unlink(compiled_source_script);
d0d307
+        }
d0d307
+            return 0;
d0d307
+        }
d0d307
+
d0d307
+        syslog(LOG_NOTICE, "autocreate_sieve: Compiled sieve script was successfully saved in %s", compiled_source_script);
d0d307
+    }
d0d307
+
d0d307
+    return 0;
d0d307
+}
d0d307
+
Tomas Janousek 686149
+/*static void fatal(const char *s, int code)
d0d307
+{   
d0d307
+    printf("Fatal error: %s (%d)\r\n", s, code);
d0d307
+    exit(1);
Tomas Janousek 686149
+}*/
d0d307
+
d0d307
+/* to make larry's stupid functions happy :) */
d0d307
+static void foo(void)
d0d307
+{
d0d307
+    fatal("stub function called", 0);
d0d307
+}
d0d307
+
d0d307
+static int sieve_notify(void *ac __attribute__((unused)),
d0d307
+                        void *interp_context __attribute__((unused)),
d0d307
+                        void *script_context __attribute__((unused)),
d0d307
+                        void *message_context __attribute__((unused)),
d0d307
+                        const char **errmsg __attribute__((unused)))
d0d307
+{
d0d307
+    fatal("stub function called", 0);
d0d307
+    return SIEVE_FAIL;
d0d307
+}
d0d307
+
d0d307
+static int mysieve_error(int lineno, const char *msg,
d0d307
+                  void *i __attribute__((unused)), void *s)
d0d307
+{
d0d307
+    char buf[1024];
d0d307
+    char **errstr = (char **) s;
d0d307
+
d0d307
+    snprintf(buf, 80, "line %d: %s\r\n", lineno, msg);
d0d307
+    *errstr = (char *) xrealloc(*errstr, strlen(*errstr) + strlen(buf) + 30);
d0d307
+    syslog(LOG_DEBUG, "%s", buf);
d0d307
+    strcat(*errstr, buf);
d0d307
+
d0d307
+    return SIEVE_OK;
d0d307
+}
d0d307
+
d0d307
+/* end the boilerplate */
d0d307
+
d0d307
+/* returns TRUE or FALSE */
d0d307
+int is_script_parsable(FILE *stream, char **errstr, sieve_script_t **ret)
d0d307
+{
d0d307
+    sieve_interp_t *i;
d0d307
+    sieve_script_t *s;
d0d307
+    int res;
d0d307
+
d0d307
+    res = sieve_interp_alloc(&i, NULL);
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        syslog(LOG_WARNING, "sieve_interp_alloc() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    res = sieve_register_redirect(i, (sieve_callback *) &foo;;
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        syslog(LOG_WARNING, "sieve_register_redirect() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+    res = sieve_register_discard(i, (sieve_callback *) &foo;;
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        syslog(LOG_WARNING, "sieve_register_discard() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+    res = sieve_register_reject(i, (sieve_callback *) &foo;;
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        syslog(LOG_WARNING, "sieve_register_reject() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+    res = sieve_register_fileinto(i, (sieve_callback *) &foo;;
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        syslog(LOG_WARNING, "sieve_register_fileinto() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+    res = sieve_register_keep(i, (sieve_callback *) &foo;;
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        syslog(LOG_WARNING, "sieve_register_keep() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    res = sieve_register_imapflags(i, NULL);
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        syslog(LOG_WARNING, "sieve_register_imapflags() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    res = sieve_register_size(i, (sieve_get_size *) &foo;;
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        syslog(LOG_WARNING, "sieve_register_size() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    res = sieve_register_header(i, (sieve_get_header *) &foo;;
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        syslog(LOG_WARNING, "sieve_register_header() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    res = sieve_register_envelope(i, (sieve_get_envelope *) &foo;;
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        syslog(LOG_WARNING, "sieve_register_envelope() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    res = sieve_register_vacation(i, &vacation2);
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        syslog(LOG_WARNING, "sieve_register_vacation() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    res = sieve_register_notify(i, &sieve_notify);
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        syslog(LOG_WARNING, "sieve_register_notify() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    res = sieve_register_parse_error(i, &mysieve_error);
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        syslog(LOG_WARNING, "sieve_register_parse_error() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    rewind(stream);
d0d307
+
d0d307
+    *errstr = (char *) xmalloc(20 * sizeof(char));
d0d307
+    strcpy(*errstr, "script errors:\r\n");
d0d307
+
d0d307
+    res = sieve_script_parse(i, stream, errstr, &s);
d0d307
+
d0d307
+    if (res == SIEVE_OK) {
d0d307
+        if(ret) {
d0d307
+            *ret = s;
d0d307
+        } else {
d0d307
+            sieve_script_free(&s);
d0d307
+        }
d0d307
+        free(*errstr);
d0d307
+        *errstr = NULL;
d0d307
+    }
d0d307
+
d0d307
+    /* free interpreter */
d0d307
+    sieve_interp_free(&i);
d0d307
+
d0d307
+    return (res == SIEVE_OK) ? TIMSIEVE_OK : TIMSIEVE_FAIL;
d0d307
+}
d0d307
+
d0d307
+/*
d0d307
+ * Btw the initial date of this patch is Sep, 02 2004 which is the birthday of
d0d307
+ * Pavlos. Author of cyrusmaster. So consider this patch as his birthday present
d0d307
+ */
d0d307
+
a6d65f
--- cyrus-imapd-2.3.13/imap/mboxlist.h.autocreate	2008-03-24 18:09:18.000000000 +0100
a6d65f
+++ cyrus-imapd-2.3.13/imap/mboxlist.h	2009-01-13 11:14:09.000000000 +0100
a6d65f
@@ -212,4 +212,8 @@
a6d65f
 int mboxlist_abort(struct txn *tid);
a6d65f
 
a6d65f
 int mboxlist_delayed_delete_isenabled(void);
a6d65f
+int mboxlist_autocreateinbox(struct namespace *namespace,char *userid,
a6d65f
+                       struct auth_state *auth_state, char *mailboxname, 
a6d65f
+                       int autocreatequota);
a6d65f
+
a6d65f
 #endif
a6d65f
--- cyrus-imapd-2.3.13/imap/compile_sieve.c.autocreate	2009-01-13 11:14:09.000000000 +0100
a6d65f
+++ cyrus-imapd-2.3.13/imap/compile_sieve.c	2009-01-13 11:14:09.000000000 +0100
Tomas Janousek 686149
@@ -0,0 +1,365 @@
d0d307
+/* This tool compiles the sieve script from a command
d0d307
+line so that it can be used wby the autoadd patch */
d0d307
+#include <stdio.h>
d0d307
+#include <stdlib.h>
d0d307
+
d0d307
+#include <config.h>
d0d307
+#include <string.h>
d0d307
+#ifdef HAVE_UNISTD_H
d0d307
+#include <unistd.h>
d0d307
+#endif
d0d307
+#include <errno.h>
d0d307
+#include <sys/types.h>
d0d307
+#include <sys/stat.h>
d0d307
+#include <sys/uio.h>
d0d307
+#include <fcntl.h>
d0d307
+#include <ctype.h>
d0d307
+#include <time.h>
d0d307
+#include <com_err.h>
d0d307
+
d0d307
+#include "global.h"
d0d307
+
d0d307
+#include "util.h"
Tomas Janousek 686149
+#include "xmalloc.h"
Tomas Janousek 686149
+#include "xstrlcpy.h"
Tomas Janousek 686149
+#include "xstrlcat.h"
d0d307
+#include "mailbox.h"
d0d307
+#include "imap_err.h"
d0d307
+#include "sieve_interface.h"
d0d307
+#include "script.h"
d0d307
+
d0d307
+#include <pwd.h>
d0d307
+
d0d307
+#define TIMSIEVE_FAIL 		-1
d0d307
+#define TIMSIEVE_OK 		0
d0d307
+#define MAX_FILENAME_SIZE	100
d0d307
+
d0d307
+/* Needed by libconfig */
d0d307
+const int config_need_data = 0;
d0d307
+
d0d307
+static int is_script_parsable(FILE *stream, char **errstr, sieve_script_t **ret);
d0d307
+
Tomas Janousek 686149
+/*static void fatal(const char *s, int code)
d0d307
+{   
d0d307
+    printf("Fatal error: %s (%d)\r\n", s, code);
d0d307
+
d0d307
+    exit(1);
Tomas Janousek 686149
+}*/
d0d307
+
d0d307
+void usage(void)
d0d307
+{
d0d307
+    fprintf(stderr,
d0d307
+            "Usage:\n\tcompile_sieve [-C <altconfig>] [-i <infile> -o <outfile>]\n");
d0d307
+    exit(-1);
d0d307
+}
d0d307
+
d0d307
+
d0d307
+int main (int argc, char **argv)
d0d307
+{   
d0d307
+
d0d307
+    sieve_script_t *s = NULL;
d0d307
+    bytecode_info_t *bc = NULL;
d0d307
+    char *err = NULL;
d0d307
+    FILE *in_stream;
Tomas Janousek 686149
+    int  out_fd, opt;
d0d307
+    char *source_script = NULL;
d0d307
+    char *compiled_source_script = NULL;
d0d307
+    char *alt_config = NULL;
d0d307
+    extern char *optarg;
d0d307
+    char sieve_tmpname[MAX_MAILBOX_NAME+1];
d0d307
+
d0d307
+    if (geteuid() == 0) fatal("must run as the Cyrus user", EC_USAGE);
d0d307
+
d0d307
+    while((opt = getopt(argc, argv, "C:i:o:")) != EOF) {
d0d307
+        switch (opt) {
d0d307
+            case 'C': /* alt config file */
d0d307
+	        alt_config =  optarg;
d0d307
+	        break;
d0d307
+	    case 'i': /* input script file */
d0d307
+		source_script = optarg;
d0d307
+		break;
d0d307
+	    case 'o': /* output script file */
d0d307
+		compiled_source_script = optarg;
d0d307
+		break;
d0d307
+	    default:
d0d307
+	        usage();
d0d307
+		break;
d0d307
+	}
d0d307
+    }
d0d307
+
d0d307
+    if(source_script && !compiled_source_script) {
d0d307
+	    fprintf(stderr, "No output file was defined\n");
d0d307
+	    usage();
d0d307
+    } else if (!source_script && compiled_source_script) {
d0d307
+	    fprintf(stderr, "No input file was defined\n");
d0d307
+	    usage();
d0d307
+    }	
d0d307
+
d0d307
+    /*
d0d307
+     * If no <infile> has been defined, then read them from
d0d307
+     * the configuration file.
d0d307
+     */
d0d307
+    if (!source_script && !compiled_source_script) { 
d0d307
+	    cyrus_init(alt_config, "compile_sieve", 0);
d0d307
+
d0d307
+	    /* Initially check if we want to have the sieve script created */
d0d307
+	    if(!(source_script = (char *) config_getstring(IMAPOPT_AUTOCREATE_SIEVE_SCRIPT))) {
d0d307
+        	fprintf(stderr,"autocreate_sieve_script option not defined. Check imapd.conf\n");
d0d307
+	        return 1;
d0d307
+	    }
d0d307
+
d0d307
+	    /* Check if we have an already compiled sieve script*/
d0d307
+	    if(!(compiled_source_script = (char *) config_getstring(IMAPOPT_AUTOCREATE_SIEVE_COMPILEDSCRIPT))) {
d0d307
+	        fprintf(stderr, "autocreate_sieve_compiledscript option not defined. Check imapd.conf\n");
d0d307
+		return 1;
d0d307
+	    }
d0d307
+
d0d307
+	    if(!strrchr(source_script,'/') || !strrchr(compiled_source_script,'/')) {
d0d307
+       		/* 
d0d307
+		 * At this point the only think that is inconsistent is the directory 
d0d307
+		 * that was created. But if the user will have any sieve scripts then 
d0d307
+		 * they will eventually go there, so no big deal 
d0d307
+		 */
d0d307
+	        fprintf(stderr, 
d0d307
+			"In imapd.conf the full path of the filenames must be defined\n");
d0d307
+	       	return 1;
d0d307
+	    }
d0d307
+    }
d0d307
+
d0d307
+    printf("input file : %s, output file : %s\n", source_script, compiled_source_script);
d0d307
+
d0d307
+
d0d307
+    if(strlen(compiled_source_script) + sizeof(".NEW") + 1 > sizeof(sieve_tmpname)) {
d0d307
+	    fprintf(stderr, "Filename %s is too big\n", compiled_source_script);
d0d307
+	    return 1;
d0d307
+    }
d0d307
+    	
d0d307
+    snprintf(sieve_tmpname, sizeof(sieve_tmpname), "%s.NEW", compiled_source_script);
d0d307
+
d0d307
+    in_stream = fopen(source_script,"r");
d0d307
+
d0d307
+    if(!in_stream) {
d0d307
+        fprintf(stderr,"Unable to open %s source sieve script\n",source_script);
Tomas Janousek 686149
+        return 1; 
d0d307
+    }
d0d307
+
d0d307
+    /* 
d0d307
+     * We open the file that will be used as the bc file. If this file exists, overwrite it 
d0d307
+     * since something bad has happened. We open the file here so that this error checking is
d0d307
+     * done before we try to open the rest of the files to start copying etc. 
d0d307
+     */
d0d307
+    out_fd = open(sieve_tmpname, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
d0d307
+    if(out_fd < 0) {
d0d307
+        if(errno == EEXIST) {
d0d307
+            fprintf(stderr, "File %s already exists\n", sieve_tmpname);
d0d307
+        } else if (errno == EACCES) {
d0d307
+            fprintf(stderr,"No access to create file %s. Please check that you have the correct permissions\n",
d0d307
+			    sieve_tmpname);
d0d307
+        } else {
d0d307
+            fprintf(stderr,"Unable to create %s. Please check that you have the correct permissions\n", 
d0d307
+			    sieve_tmpname);
d0d307
+        }
d0d307
+	
d0d307
+	fclose(in_stream);
d0d307
+	return 1;
d0d307
+    }
d0d307
+
d0d307
+    if(is_script_parsable(in_stream,&err, &s) == TIMSIEVE_FAIL) {
d0d307
+        if(err && *err) {
d0d307
+           fprintf(stderr, "Error while parsing script %s\n",err);
d0d307
+           free(err);
d0d307
+        }
d0d307
+        else
d0d307
+            fprintf(stderr,"Error while parsing script\n");
d0d307
+            unlink(sieve_tmpname);
d0d307
+	    fclose(in_stream);
d0d307
+	    close(out_fd);
Tomas Janousek 686149
+        return 1;
d0d307
+   }
d0d307
+
d0d307
+
d0d307
+    /* generate the bytecode */
d0d307
+    if(sieve_generate_bytecode(&bc,s) == TIMSIEVE_FAIL) {
d0d307
+        fprintf(stderr,"Error occured while compiling sieve script\n");
d0d307
+        /* removing the copied script and cleaning up memory */
d0d307
+        unlink(sieve_tmpname);
d0d307
+        sieve_script_free(&s);
d0d307
+        fclose(in_stream);
d0d307
+        close(out_fd);
Tomas Janousek 686149
+        return 1;
d0d307
+    }
d0d307
+    if(sieve_emit_bytecode(out_fd,bc) == TIMSIEVE_FAIL) {
d0d307
+        fprintf(stderr, "Error occured while emitting sieve script\n");
d0d307
+        unlink(sieve_tmpname);
d0d307
+        sieve_free_bytecode(&bc);
d0d307
+        sieve_script_free(&s);
d0d307
+        fclose(in_stream);
d0d307
+        close(out_fd);
Tomas Janousek 686149
+        return 1;
d0d307
+    }
d0d307
+
d0d307
+    /* clean up the memory */
d0d307
+    sieve_free_bytecode(&bc);
d0d307
+    sieve_script_free(&s);
d0d307
+
d0d307
+    close(out_fd);
d0d307
+
d0d307
+    if(rename(sieve_tmpname, compiled_source_script)) {
d0d307
+        if(errno != EEXIST) {
d0d307
+            unlink(sieve_tmpname);
d0d307
+            unlink(compiled_source_script);
d0d307
+            return 1;
d0d307
+        }
d0d307
+    }
d0d307
+    return 0;
d0d307
+}
d0d307
+
d0d307
+
d0d307
+/* to make larry's stupid functions happy :) */
d0d307
+static void foo(void)
d0d307
+{
d0d307
+    fatal("stub function called", 0);
d0d307
+}
d0d307
+
d0d307
+extern sieve_vacation_t vacation2;/* = {
d0d307
+    0,                          / min response /
d0d307
+    0,                          / max response /
d0d307
+    (sieve_callback *) &foo,    / autorespond() /
d0d307
+    (sieve_callback *) &foo     / send_response() /
d0d307
+}; */
d0d307
+
d0d307
+static int sieve_notify(void *ac __attribute__((unused)),
d0d307
+                        void *interp_context __attribute__((unused)),
d0d307
+                        void *script_context __attribute__((unused)),
d0d307
+                        void *message_context __attribute__((unused)),
d0d307
+                        const char **errmsg __attribute__((unused)))
d0d307
+{
d0d307
+    fatal("stub function called", 0);
d0d307
+    return SIEVE_FAIL;
d0d307
+}
d0d307
+
d0d307
+static int mysieve_error(int lineno, const char *msg,
d0d307
+                  void *i __attribute__((unused)), void *s)
d0d307
+{
d0d307
+    char buf[1024];
d0d307
+    char **errstr = (char **) s;
d0d307
+
d0d307
+    snprintf(buf, 80, "line %d: %s\r\n", lineno, msg);
d0d307
+    *errstr = (char *) xrealloc(*errstr, strlen(*errstr) + strlen(buf) + 30);
d0d307
+    fprintf(stderr, "%s\n", buf);
d0d307
+    strcat(*errstr, buf);
d0d307
+
d0d307
+    return SIEVE_OK;
d0d307
+}
d0d307
+
d0d307
+/* end the boilerplate */
d0d307
+
d0d307
+/* returns TRUE or FALSE */
d0d307
+int is_script_parsable(FILE *stream, char **errstr, sieve_script_t **ret)
d0d307
+{
d0d307
+    sieve_interp_t *i;
d0d307
+    sieve_script_t *s;
d0d307
+    int res;
d0d307
+
d0d307
+    res = sieve_interp_alloc(&i, NULL);
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        fprintf(stderr, "sieve_interp_alloc() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    res = sieve_register_redirect(i, (sieve_callback *) &foo;;
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        fprintf(stderr, "sieve_register_redirect() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+    res = sieve_register_discard(i, (sieve_callback *) &foo;;
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        fprintf(stderr, "sieve_register_discard() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+    res = sieve_register_reject(i, (sieve_callback *) &foo;;
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        fprintf(stderr, "sieve_register_reject() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+    res = sieve_register_fileinto(i, (sieve_callback *) &foo;;
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        fprintf(stderr, "sieve_register_fileinto() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+    res = sieve_register_keep(i, (sieve_callback *) &foo;;
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        fprintf(stderr, "sieve_register_keep() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    res = sieve_register_imapflags(i, NULL);
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        fprintf(stderr, "sieve_register_imapflags() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    res = sieve_register_size(i, (sieve_get_size *) &foo;;
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        fprintf(stderr, "sieve_register_size() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    res = sieve_register_header(i, (sieve_get_header *) &foo;;
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        fprintf(stderr, "sieve_register_header() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    res = sieve_register_envelope(i, (sieve_get_envelope *) &foo;;
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        fprintf(stderr, "sieve_register_envelope() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    res = sieve_register_vacation(i, &vacation2);
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        fprintf(stderr, "sieve_register_vacation() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    res = sieve_register_notify(i, &sieve_notify);
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        fprintf(stderr, "sieve_register_notify() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    res = sieve_register_parse_error(i, &mysieve_error);
d0d307
+    if (res != SIEVE_OK) {
d0d307
+        fprintf(stderr, "sieve_register_parse_error() returns %d\n", res);
d0d307
+        return TIMSIEVE_FAIL;
d0d307
+    }
d0d307
+
d0d307
+    rewind(stream);
d0d307
+
d0d307
+    *errstr = (char *) xmalloc(20 * sizeof(char));
d0d307
+    strcpy(*errstr, "script errors:\r\n");
d0d307
+
d0d307
+    res = sieve_script_parse(i, stream, errstr, &s);
d0d307
+
d0d307
+    if (res == SIEVE_OK) {
d0d307
+        if(ret) {
d0d307
+            *ret = s;
d0d307
+        } else {
d0d307
+            sieve_script_free(&s);
d0d307
+        }
d0d307
+        free(*errstr);
d0d307
+        *errstr = NULL;
d0d307
+    }
d0d307
+
d0d307
+    /* free interpreter */
d0d307
+    sieve_interp_free(&i);
d0d307
+
d0d307
+    return (res == SIEVE_OK) ? TIMSIEVE_OK : TIMSIEVE_FAIL;
d0d307
+}
d0d307
+
d0d307
+
d0d307
+
d0d307
+
d0d307
+
d0d307
+
a6d65f
--- cyrus-imapd-2.3.13/imap/Makefile.in.autocreate	2008-09-23 18:17:09.000000000 +0200
a6d65f
+++ cyrus-imapd-2.3.13/imap/Makefile.in	2009-01-13 11:24:48.000000000 +0100
a6d65f
@@ -101,7 +101,7 @@
a6d65f
 	convert_code.o duplicate.o saslclient.o saslserver.o signals.o \
a6d65f
 	annotate.o search_engines.o squat.o squat_internal.o mbdump.o \
a6d65f
 	imapparse.o telemetry.o user.o notify.o idle.o quota_db.o \
a6d65f
-	sync_log.o $(SEEN) mboxkey.o backend.o tls.o message_guid.o \
a6d65f
+	sync_log.o autosieve.o $(SEEN) mboxkey.o backend.o tls.o message_guid.o \
a6d65f
 	statuscache_db.o
a6d65f
 
a6d65f
 IMAPDOBJS=pushstats.o imapd.o proxy.o imap_proxy.o index.o version.o
a6d65f
@@ -118,7 +118,7 @@
a6d65f
 	fud smmapd reconstruct quota mbpath ipurge cyr_dbtool cyr_synclog \
a6d65f
 	cyrdump chk_cyrus cvt_cyrusdb deliver ctl_mboxlist \
a6d65f
 	ctl_deliver ctl_cyrusdb squatter mbexamine cyr_expire arbitron \
a6d65f
-	unexpunge @IMAP_PROGS@
a6d65f
+	unexpunge compile_sieve @IMAP_PROGS@
a6d65f
 
a6d65f
 BUILTSOURCES = imap_err.c imap_err.h pushstats.c pushstats.h \
a6d65f
 	lmtpstats.c lmtpstats.h xversion.h mupdate_err.c mupdate_err.h \
a6d65f
@@ -183,9 +183,9 @@
a6d65f
 mupdate_err.h: mupdate_err.c
a6d65f
 
a6d65f
 ### Services
a6d65f
-idled: idled.o mutex_fake.o libimap.a $(DEPLIBS)
a6d65f
+idled: idled.o mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o idled \
a6d65f
-	 idled.o mutex_fake.o libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	 idled.o mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
 lmtpd: lmtpd.o proxy.o $(LMTPOBJS) $(SIEVE_OBJS) mutex_fake.o \
a6d65f
 	 libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
a6d65f
@@ -199,163 +199,166 @@
a6d65f
 	 $(SERVICE) lmtpd.o proxy.o $(LMTPOBJS) $(SIEVE_OBJS) \
a6d65f
 	 mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
a6d65f
 
a6d65f
-imapd: $(IMAPDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
a6d65f
+imapd: $(IMAPDOBJS) mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
a6d65f
 	$(CC) $(LDFLAGS) -o imapd \
a6d65f
 	 $(SERVICE) $(IMAPDOBJS) mutex_fake.o \
a6d65f
-	libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP)
a6d65f
+	libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
a6d65f
 
a6d65f
-imapd.pure: $(IMAPDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
a6d65f
+imapd.pure: $(IMAPDOBJS) mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
a6d65f
 	$(PURIFY) $(PUREOPT) $(CC) $(LDFLAGS) -o imapd.pure \
a6d65f
 	 $(SERVICE) $(IMAPDOBJS) mutex_fake.o libimap.a \
a6d65f
-	$(DEPLIBS) $(LIBS) $(LIB_WRAP)
a6d65f
+	$(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
a6d65f
 
a6d65f
-imapd.quant: $(IMAPDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
a6d65f
+imapd.quant: $(IMAPDOBJS) mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
a6d65f
 	$(QUANTIFY) $(QUANTOPT) $(CC) $(LDFLAGS) -o imapd.quant \
a6d65f
 	 $(SERVICE) $(IMAPDOBJS) mutex_fake.o libimap.a \
a6d65f
-	$(DEPLIBS) $(LIBS) $(LIB_WRAP)
a6d65f
+	$(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
a6d65f
 
a6d65f
 mupdate: mupdate.o mupdate-slave.o mupdate-client.o mutex_pthread.o tls.o \
a6d65f
-	libimap.a $(DEPLIBS)
a6d65f
+	libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o mupdate \
a6d65f
 	 $(SERVICETHREAD) mupdate.o mupdate-slave.o mupdate-client.o \
a6d65f
 	 mutex_pthread.o tls.o libimap.a \
a6d65f
-	 $(DEPLIBS) $(LIBS) $(LIB_WRAP) -lpthread
a6d65f
+	 $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP) -lpthread
a6d65f
 
a6d65f
 mupdate.pure: mupdate.o mupdate-slave.o mupdate-client.o mutex_pthread.o \
a6d65f
-	libimap.a $(DEPLIBS)
a6d65f
+	libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(PURIFY) $(PUREOPT) $(CC) $(LDFLAGS) -o mupdate.pure \
a6d65f
 	 $(SERVICETHREAD) mupdate.o mupdate-slave.o mupdate-client.o \
a6d65f
-	 mutex_pthread.o libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP) -lpthread
a6d65f
+	 mutex_pthread.o libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP) -lpthread
a6d65f
 
a6d65f
 pop3d: pop3d.o proxy.o backend.o tls.o mutex_fake.o libimap.a \
a6d65f
-	$(DEPLIBS) $(SERVICE)
a6d65f
+	$(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
a6d65f
 	$(CC) $(LDFLAGS) -o pop3d pop3d.o proxy.o backend.o tls.o $(SERVICE) \
a6d65f
-	 mutex_fake.o libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP)
a6d65f
+	 mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
a6d65f
 
a6d65f
 nntpd: nntpd.o proxy.o backend.o index.o smtpclient.o spool.o tls.o \
a6d65f
-	 mutex_fake.o nntp_err.o libimap.a $(DEPLIBS) $(SERVICE)
a6d65f
+	 mutex_fake.o nntp_err.o libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
a6d65f
 	$(CC) $(LDFLAGS) -o nntpd nntpd.o proxy.o backend.o index.o spool.o \
a6d65f
 	 smtpclient.o tls.o $(SERVICE) mutex_fake.o nntp_err.o \
a6d65f
-	 libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP)
a6d65f
+	 libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
a6d65f
 
a6d65f
-fud: fud.o libimap.a mutex_fake.o $(DEPLIBS) $(SERVICE)
a6d65f
+fud: fud.o libimap.a mutex_fake.o $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
a6d65f
 	$(CC) $(LDFLAGS) -o fud $(SERVICE) fud.o mutex_fake.o libimap.a \
a6d65f
-	$(DEPLIBS) $(LIBS) $(LIB_WRAP)
a6d65f
+	$(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
a6d65f
 
a6d65f
-smmapd: smmapd.o libimap.a mutex_fake.o $(DEPLIBS) $(SERVICE)
a6d65f
+smmapd: smmapd.o libimap.a mutex_fake.o $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
a6d65f
 	$(CC) $(LDFLAGS) -o smmapd $(SERVICE) smmapd.o mutex_fake.o libimap.a \
a6d65f
-	$(DEPLIBS) $(LIBS) $(LIB_WRAP)
a6d65f
+	$(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
a6d65f
 
a6d65f
 sync_server: sync_server.o sync_support.o sync_commit.o \
a6d65f
-	imapparse.o tls.o libimap.a mutex_fake.o $(DEPLIBS) $(SERVICE)
a6d65f
+	imapparse.o tls.o libimap.a mutex_fake.o $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
a6d65f
 	$(CC) $(LDFLAGS) -o \
a6d65f
 	sync_server sync_server.o sync_support.o sync_commit.o \
a6d65f
 	imapparse.o tls.o $(SERVICE) libimap.a mutex_fake.o \
a6d65f
-	$(DEPLIBS) $(LIBS) $(LIB_WRAP)
a6d65f
+	$(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
d0d307
 
a6d65f
 ### Command Line Utilities
a6d65f
-arbitron: arbitron.o $(CLIOBJS) libimap.a $(DEPLIBS)
a6d65f
+arbitron: arbitron.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o arbitron arbitron.o $(CLIOBJS) \
a6d65f
-	libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
d0d307
 
a6d65f
-cyr_dbtool: cyr_dbtool.o mutex_fake.o libimap.a $(DEPLIBS)
a6d65f
+cyr_dbtool: cyr_dbtool.o mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o cyr_dbtool cyr_dbtool.o $(CLIOBJS) \
a6d65f
-	libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
d0d307
 
a6d65f
-cyr_synclog: cyr_synclog.o mutex_fake.o libimap.a $(DEPLIBS)
a6d65f
+cyr_synclog: cyr_synclog.o mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o cyr_synclog cyr_synclog.o $(CLIOBJS) \
a6d65f
-	libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
d0d307
 
a6d65f
-cvt_cyrusdb: cvt_cyrusdb.o mutex_fake.o libimap.a $(DEPLIBS)
a6d65f
+cvt_cyrusdb: cvt_cyrusdb.o mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o cvt_cyrusdb cvt_cyrusdb.o $(CLIOBJS) \
a6d65f
-	libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
d0d307
 
a6d65f
-chk_cyrus: chk_cyrus.o mutex_fake.o libimap.a $(DEPLIBS)
a6d65f
+chk_cyrus: chk_cyrus.o mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o chk_cyrus chk_cyrus.o $(CLIOBJS) \
a6d65f
-	libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-deliver: deliver.o $(LMTPOBJS) proxy.o mutex_fake.o libimap.a $(DEPLIBS)
a6d65f
+deliver: deliver.o $(LMTPOBJS) proxy.o mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o deliver deliver.o $(LMTPOBJS) proxy.o \
a6d65f
-	mutex_fake.o libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-ctl_deliver: ctl_deliver.o $(CLIOBJS) libimap.a $(DEPLIBS)
a6d65f
+ctl_deliver: ctl_deliver.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o \
a6d65f
-	 $@ ctl_deliver.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	 $@ ctl_deliver.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-ctl_mboxlist: ctl_mboxlist.o mupdate-client.o $(CLIOBJS) libimap.a $(DEPLIBS)
a6d65f
+ctl_mboxlist: ctl_mboxlist.o mupdate-client.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o $@ ctl_mboxlist.o mupdate-client.o $(CLIOBJS) \
a6d65f
-	libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-ctl_cyrusdb: ctl_cyrusdb.o $(CLIOBJS) libimap.a $(DEPLIBS)
a6d65f
+ctl_cyrusdb: ctl_cyrusdb.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o \
a6d65f
-	 $@ ctl_cyrusdb.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	 $@ ctl_cyrusdb.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-cyr_expire: cyr_expire.o $(CLIOBJS) libimap.a $(DEPLIBS)
a6d65f
+cyr_expire: cyr_expire.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o $@ cyr_expire.o $(CLIOBJS) \
a6d65f
-	libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-fetchnews: fetchnews.o $(CLIOBJS) libimap.a $(DEPLIBS)
a6d65f
+fetchnews: fetchnews.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o \
a6d65f
-	 $@ fetchnews.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	 $@ fetchnews.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-squatter: squatter.o index.o squat_build.o $(CLIOBJS) libimap.a $(DEPLIBS)
a6d65f
+squatter: squatter.o index.o squat_build.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o squatter squatter.o index.o squat_build.o \
a6d65f
-	$(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	$(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-mbpath: mbpath.o $(CLIOBJS) libimap.a $(DEPLIBS)
a6d65f
+mbpath: mbpath.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o mbpath mbpath.o $(CLIOBJS) libimap.a \
a6d65f
-	$(DEPLIBS) $(LIBS)
a6d65f
+	$(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-ipurge: ipurge.o $(CLIOBJS) libimap.a $(DEPLIBS)
a6d65f
+ipurge: ipurge.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o ipurge ipurge.o $(CLIOBJS) \
a6d65f
-	libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-cyr_virusscan: cyr_virusscan.o index.o $(CLIOBJS) libimap.a $(DEPLIBS)
a6d65f
+cyr_virusscan: cyr_virusscan.o index.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o cyr_virusscan cyr_virusscan.o index.o $(CLIOBJS) \
a6d65f
-	libimap.a $(DEPLIBS) $(LIBS) -lclamav
a6d65f
+	libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) -lclamav
a6d65f
 
a6d65f
-cyrdump: cyrdump.o index.o $(CLIOBJS) libimap.a $(DEPLIBS)
a6d65f
+cyrdump: cyrdump.o index.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o cyrdump cyrdump.o index.o $(CLIOBJS) \
a6d65f
-	libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-mbexamine: mbexamine.o $(CLIOBJS) libimap.a $(DEPLIBS)
a6d65f
+mbexamine: mbexamine.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o \
a6d65f
-	 mbexamine mbexamine.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	 mbexamine mbexamine.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-reconstruct: reconstruct.o $(CLIOBJS) libimap.a $(DEPLIBS)
a6d65f
+reconstruct: reconstruct.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o \
a6d65f
-	 reconstruct reconstruct.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	 reconstruct reconstruct.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-quota: quota.o $(CLIOBJS) libimap.a $(DEPLIBS)
a6d65f
+quota: quota.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o quota quota.o $(CLIOBJS) \
a6d65f
-	libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-tls_prune: tls_prune.o tls.o $(CLIOBJS) libimap.a $(DEPLIBS)
a6d65f
+tls_prune: tls_prune.o tls.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o \
a6d65f
-	 $@ tls_prune.o tls.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	 $@ tls_prune.o tls.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-unexpunge: unexpunge.o $(CLIOBJS) libimap.a $(DEPLIBS)
a6d65f
+unexpunge: unexpunge.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o $@ unexpunge.o $(CLIOBJS) \
a6d65f
-	libimap.a $(DEPLIBS) $(LIBS)
a6d65f
+	libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-make_md5: make_md5.o libimap.a mutex_fake.o $(DEPLIBS)
a6d65f
-	$(CC) $(LDFLAGS) -o make_md5 make_md5.o libimap.a mutex_fake.o $(DEPLIBS) $(LIBS)
a6d65f
+make_md5: make_md5.o libimap.a mutex_fake.o $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
+	$(CC) $(LDFLAGS) -o make_md5 make_md5.o libimap.a mutex_fake.o $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
-make_sha1: make_sha1.o libimap.a mutex_fake.o $(DEPLIBS)
a6d65f
-	$(CC) $(LDFLAGS) -o make_sha1 make_sha1.o libimap.a mutex_fake.o $(DEPLIBS) $(LIBS)
a6d65f
+make_sha1: make_sha1.o libimap.a mutex_fake.o $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
+	$(CC) $(LDFLAGS) -o make_sha1 make_sha1.o libimap.a mutex_fake.o $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
 sync_client: sync_client.o sync_support.o \
a6d65f
-	backend.o tls.o imapparse.o libimap.a mutex_fake.o $(DEPLIBS)
a6d65f
+	backend.o tls.o imapparse.o libimap.a mutex_fake.o $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o \
a6d65f
 	sync_client sync_client.o sync_support.o \
a6d65f
-	backend.o tls.o imapparse.o libimap.a mutex_fake.o $(DEPLIBS) $(LIBS)
a6d65f
+	backend.o tls.o imapparse.o libimap.a mutex_fake.o $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
 sync_reset: sync_reset.o sync_support.o sync_commit.o \
a6d65f
-	libimap.a mutex_fake.o $(DEPLIBS)
a6d65f
+	libimap.a mutex_fake.o $(SIEVE_LIBS) $(DEPLIBS)
a6d65f
 	$(CC) $(LDFLAGS) -o \
a6d65f
 	sync_reset sync_reset.o sync_support.o sync_commit.o \
a6d65f
-	libimap.a mutex_fake.o $(DEPLIBS) $(LIBS)
a6d65f
+	libimap.a mutex_fake.o $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 
a6d65f
+compile_sieve: compile_sieve.o libimap.a $(DEPLIBS) $(SIEVE_LIBS)
a6d65f
+	$(CC) $(LDFLAGS) -o compile_sieve compile_sieve.o $(CLIOBJS) \
a6d65f
+	libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
a6d65f
 ### Other Misc Targets
d0d307
 
a6d65f
 clean:
a6d65f
--- cyrus-imapd-2.3.13/imap/lmtpd.c.autocreate	2008-04-22 15:11:18.000000000 +0200
a6d65f
+++ cyrus-imapd-2.3.13/imap/lmtpd.c	2009-01-13 11:14:09.000000000 +0100
Tomas Janousek 915c4a
@@ -117,6 +117,8 @@
d0d307
 static FILE *spoolfile(message_data_t *msgdata);
d0d307
 static void removespool(message_data_t *msgdata);
d0d307
 
cf58a5
+static int autocreate_inbox(const char *user, const char *domain);
d0d307
+
d0d307
 /* current namespace */
d0d307
 static struct namespace lmtpd_namespace;
d0d307
 
bf3e29
@@ -976,6 +978,86 @@ void shut_down(int code)
d0d307
     exit(code);
d0d307
 }
d0d307
 
cf58a5
+
d0d307
+/*
d0d307
+ * Autocreate Inbox and subfolders upon login
d0d307
+ */
cf58a5
+int autocreate_inbox(const char *user, const char *domain)
d0d307
+{
cf58a5
+    struct auth_state *auth_state;
d0d307
+    char inboxname[MAX_MAILBOX_NAME+1];
cf58a5
+    char *rcpt_userid = NULL;
d0d307
+    int autocreatequota;
cf58a5
+    int r = 0;
cf58a5
+
cf58a5
+    if (user == NULL)
cf58a5
+          return IMAP_MAILBOX_NONEXISTENT;
cf58a5
+
cf58a5
+    if (domain != NULL) {
cf58a5
+	int k;
cf58a5
+	
cf58a5
+	rcpt_userid = (char *) xmalloc((strlen(user) + strlen(domain) + 2) * sizeof(char));
cf58a5
+	k = strlcpy(rcpt_userid, user, strlen(user) + 1);
cf58a5
+  	*(rcpt_userid + k) = '@';
cf58a5
+       strlcpy(rcpt_userid + k + 1, domain, strlen(domain) + 1);
cf58a5
+    } else {
cf58a5
+	rcpt_userid = (char *) user;
cf58a5
+    }
cf58a5
+
d0d307
+
d0d307
+    /*
d0d307
+     * Exclude anonymous
d0d307
+     */
cf58a5
+    if (!strcmp(rcpt_userid, "anonymous")) {
cf58a5
+	if (rcpt_userid != user) {
cf58a5
+	    free(rcpt_userid);
cf58a5
+	}
d0d307
+
cf58a5
+        return IMAP_MAILBOX_NONEXISTENT;
cf58a5
+    }
cf58a5
+    
d0d307
+    /*
d0d307
+     * Check for autocreatequota and createonpost
d0d307
+     */
d0d307
+    if (!(autocreatequota = config_getint(IMAPOPT_AUTOCREATEQUOTA)) ||
cf58a5
+        !(config_getswitch(IMAPOPT_CREATEONPOST))) {
cf58a5
+	    
cf58a5
+	if (rcpt_userid != user) {
cf58a5
+	    free(rcpt_userid);
cf58a5
+	}
cf58a5
+	
d0d307
+        return IMAP_MAILBOX_NONEXISTENT;
cf58a5
+     }
cf58a5
+
d0d307
+
d0d307
+    /*
d0d307
+     * Exclude admin's accounts
d0d307
+     */
cf58a5
+     auth_state = auth_newstate(rcpt_userid);
cf58a5
+     
cf58a5
+     if (global_authisa(auth_state, IMAPOPT_ADMINS)) {
cf58a5
+	if (rcpt_userid != user) {
cf58a5
+	    free(rcpt_userid);
cf58a5
+	}
d0d307
+
cf58a5
+        return IMAP_MAILBOX_NONEXISTENT;
cf58a5
+     }
cf58a5
+     
d0d307
+     r = (*lmtpd_namespace.mboxname_tointernal) (&lmtpd_namespace,
d0d307
+                                "INBOX", rcpt_userid, inboxname);
cf58a5
+     
d0d307
+     if (!r)
cf58a5
+ 	r = mboxlist_autocreateinbox(&lmtpd_namespace, rcpt_userid,
cf58a5
+                         auth_state, inboxname, autocreatequota);
cf58a5
+     
cf58a5
+     if (rcpt_userid != user) {
cf58a5
+	free(rcpt_userid);
cf58a5
+     }
cf58a5
+       
d0d307
+     return r;
d0d307
+}
d0d307
+
d0d307
+
cf58a5
 static int verify_user(const char *user, const char *domain, char *mailbox,
bf3e29
 		       quota_t quotacheck, struct auth_state *authstate)
d0d307
 {
346e22
@@ -1019,6 +1101,15 @@
d0d307
 	 */
cf58a5
 	r = mlookup(namebuf, &server, &acl, NULL);
cf58a5
 
cf58a5
+	/* If user mailbox does not exist, then invoke autocreate inbox function */
cf58a5
+	if (r == IMAP_MAILBOX_NONEXISTENT) {
cf58a5
+	    r = autocreate_inbox(user, domain);
cf58a5
+
cf58a5
+	    /* Try to locate the mailbox again */
d0d307
+	    if (!r)
cf58a5
+		r = mlookup(namebuf, &server, &acl, NULL);
cf58a5
+	}
cf58a5
+
cf58a5
 	if (r == IMAP_MAILBOX_NONEXISTENT && !user &&
cf58a5
 	    config_getswitch(IMAPOPT_LMTP_FUZZY_MAILBOX_MATCH) &&
cf58a5
 	    /* see if we have a mailbox whose name is close */
346e22
@@ -1045,6 +1136,7 @@
cf58a5
 			     aclcheck, (quotacheck < 0)
cf58a5
 			     || config_getswitch(IMAPOPT_LMTP_STRICT_QUOTA) ?
cf58a5
 			     quotacheck : 0);
d0d307
+
a6d65f
 	}
a6d65f
     }
a6d65f
 
a6d65f
--- cyrus-imapd-2.3.13/imap/imapd.c.autocreate	2008-10-08 17:47:06.000000000 +0200
a6d65f
+++ cyrus-imapd-2.3.13/imap/imapd.c	2009-01-13 11:14:09.000000000 +0100
a6d65f
@@ -209,6 +209,7 @@
a6d65f
 void motd_file(int fd);
a6d65f
 void shut_down(int code);
a6d65f
 void fatal(const char *s, int code);
a6d65f
+void autocreate_inbox(void);
a6d65f
 
a6d65f
 void cmdloop(void);
a6d65f
 void cmd_login(char *tag, char *user);
a6d65f
@@ -1975,6 +1976,43 @@
a6d65f
 }
a6d65f
 
a6d65f
 /*
a6d65f
+ * Autocreate Inbox and subfolders upon login
a6d65f
+ */
a6d65f
+void autocreate_inbox()
a6d65f
+{
a6d65f
+    char inboxname[MAX_MAILBOX_NAME+1];
a6d65f
+    int autocreatequota;
a6d65f
+    int r;
a6d65f
+ 
a6d65f
+    /*
a6d65f
+     * Exlude admin's accounts
a6d65f
+     */
a6d65f
+    if (imapd_userisadmin || imapd_userisproxyadmin)
a6d65f
+        return;
a6d65f
+ 
a6d65f
+    /*
a6d65f
+     * Exclude anonymous
a6d65f
+     */
a6d65f
+    if (!strcmp(imapd_userid, "anonymous"))
a6d65f
+        return;
a6d65f
+ 
a6d65f
+    if ((autocreatequota = config_getint(IMAPOPT_AUTOCREATEQUOTA))) {
a6d65f
+        /* This is actyally not required
a6d65f
+           as long as the lenght of userid is ok */
a6d65f
+           r = (*imapd_namespace.mboxname_tointernal) (&imapd_namespace,
a6d65f
+                                      "INBOX", imapd_userid, inboxname);
a6d65f
+           if (!r)
a6d65f
+               r = mboxlist_lookup(inboxname, NULL, NULL);
a6d65f
+ 
a6d65f
+           if (r == IMAP_MAILBOX_NONEXISTENT) {
a6d65f
+                mboxlist_autocreateinbox(&imapd_namespace, imapd_userid,
a6d65f
+                         imapd_authstate, inboxname, autocreatequota);
a6d65f
+	   }
a6d65f
+     }
a6d65f
+}
a6d65f
+
a6d65f
+
a6d65f
+/*
a6d65f
  * Perform a LOGIN command
a6d65f
  */
a6d65f
 void cmd_login(char *tag, char *user)
a6d65f
@@ -2151,6 +2189,9 @@
a6d65f
 				strcspn(imapd_userid, "@") : 0);
d0d307
 
a6d65f
     freebuf(&passwdbuf);
d0d307
+
a6d65f
+    autocreate_inbox();
d0d307
+
a6d65f
     return;
a6d65f
 }
d0d307
 
a6d65f
@@ -2308,6 +2349,8 @@
a6d65f
 				config_virtdomains ?
a6d65f
 				strcspn(imapd_userid, "@") : 0);
d0d307
 
a6d65f
+    autocreate_inbox();
d0d307
+
a6d65f
     return;
a6d65f
 }
d0d307
 
a6d65f
--- cyrus-imapd-2.3.13/imap/pop3d.c.autocreate	2008-04-22 15:11:18.000000000 +0200
a6d65f
+++ cyrus-imapd-2.3.13/imap/pop3d.c	2009-01-13 11:14:09.000000000 +0100
a6d65f
@@ -172,6 +172,8 @@
a6d65f
 static char popd_apop_chal[45 + MAXHOSTNAMELEN + 1]; /* <rand.time@hostname> */
a6d65f
 static void cmd_apop(char *response);
a6d65f
 
a6d65f
+static int autocreate_inbox(char *inboxname, char *userid);
d0d307
+
a6d65f
 static void cmd_auth(char *arg);
a6d65f
 static void cmd_capa(void);
a6d65f
 static void cmd_pass(char *pass);
a6d65f
@@ -1245,6 +1247,7 @@
a6d65f
 	popd_userid = xstrdup(userbuf);
a6d65f
 	prot_printf(popd_out, "+OK Name is a valid mailbox\r\n");
a6d65f
     }
d0d307
+
a6d65f
 }
d0d307
 
a6d65f
 void cmd_pass(char *pass)
a6d65f
@@ -1548,6 +1551,43 @@
d0d307
 }
a6d65f
 
a6d65f
 /*
a6d65f
+ * Autocreate Inbox and subfolders upon login
d0d307
+ */
a6d65f
+int autocreate_inbox(char *inboxname, char *auth_userid)
a6d65f
+{
a6d65f
+    struct auth_state *auth_state;
a6d65f
+    int autocreatequota;
a6d65f
+    int r;
d0d307
+
a6d65f
+    if (inboxname == NULL || auth_userid == NULL)
a6d65f
+	    return IMAP_MAILBOX_NONEXISTENT;
a6d65f
+    
a6d65f
+    /*
a6d65f
+     * Exclude anonymous
a6d65f
+     */
a6d65f
+    if (!strcmp(popd_userid, "anonymous"))
a6d65f
+        return IMAP_MAILBOX_NONEXISTENT;
d0d307
+
a6d65f
+    /*
a6d65f
+     * Check for autocreatequota
a6d65f
+     */
a6d65f
+    if (!(autocreatequota = config_getint(IMAPOPT_AUTOCREATEQUOTA)))
a6d65f
+        return IMAP_MAILBOX_NONEXISTENT;
d0d307
+
a6d65f
+    /*
a6d65f
+     * Exclude admin's accounts
a6d65f
+     */
a6d65f
+     auth_state = auth_newstate(popd_userid);
a6d65f
+     if (global_authisa(auth_state, IMAPOPT_ADMINS))
a6d65f
+          return IMAP_MAILBOX_NONEXISTENT;
d0d307
+
a6d65f
+     r = mboxlist_autocreateinbox(&popd_namespace, auth_userid,
a6d65f
+                         auth_state, inboxname, autocreatequota);
a6d65f
+     return r;
d0d307
+}
d0d307
+
d0d307
+
d0d307
+/*
a6d65f
  * Complete the login process by opening and locking the user's inbox
a6d65f
  */
a6d65f
 int openinbox(void)
a6d65f
@@ -1576,6 +1616,12 @@
a6d65f
 
a6d65f
     if (!r) r = mboxlist_detail(inboxname, &type, NULL, NULL,
a6d65f
 				&server, &acl, NULL);
d0d307
+
a6d65f
+    /* Try once again after autocreate_inbox */
a6d65f
+    if (r == IMAP_MAILBOX_NONEXISTENT && !(r = autocreate_inbox(inboxname, userid)))
a6d65f
+	r = mboxlist_detail(inboxname, &type, NULL, NULL,
a6d65f
+				&server, &acl, NULL);
d0d307
+
a6d65f
     if (!r && (config_popuseacl = config_getswitch(IMAPOPT_POPUSEACL)) &&
a6d65f
 	(!acl ||
a6d65f
 	 !((myrights = cyrus_acl_myrights(popd_authstate, acl)) & ACL_READ))) {
a6d65f
--- cyrus-imapd-2.3.13/ptclient/Makefile.in.autocreate	2008-03-24 19:34:22.000000000 +0100
a6d65f
+++ cyrus-imapd-2.3.13/ptclient/Makefile.in	2009-01-13 11:14:09.000000000 +0100
a6d65f
@@ -57,10 +57,11 @@
a6d65f
 AFS_LDFLAGS = @AFS_LDFLAGS@ @COM_ERR_LDFLAGS@
a6d65f
 AFS_LIBS = @AFS_LIBS@
a6d65f
 IMAP_LIBS = @IMAP_LIBS@ @LIB_RT@
a6d65f
+SIEVE_LIBS = @SIEVE_LIBS@
a6d65f
 LIBS = $(IMAP_LIBS) @COM_ERR_LIBS@
a6d65f
 LIB_SASL = @LIB_SASL@
a6d65f
 LIB_WRAP = @LIB_WRAP@
a6d65f
-DEPLIBS = ../imap/libimap.a ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
a6d65f
+DEPLIBS = ../imap/libimap.a $(SIEVE_LIBS) ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@ 
a6d65f
 UTIL_LIBS = ../imap/mutex_fake.o ../imap/cli_fatal.o
a6d65f
 
a6d65f
 LDAP_LIBS=@LDAP_LIBS@
a6d65f
--- cyrus-imapd-2.3.13/README.autocreate.autocreate	2009-01-13 11:14:09.000000000 +0100
a6d65f
+++ cyrus-imapd-2.3.13/README.autocreate	2009-01-13 11:14:09.000000000 +0100
a6d65f
@@ -0,0 +1,211 @@
a6d65f
+Cyrus IMAP autocreate Inbox patch
a6d65f
+----------------------------------
d0d307
+
a6d65f
+NOTE : This patch has been created at the University of Athens. For more info, as well 
a6d65f
+as more patches on Cyrus IMAPD server, please visit http://email.uoa.gr/ 
d0d307
+
a6d65f
+The design of Cyrus IMAP server does not predict the automatic creation of users'
a6d65f
+INBOX folders. The creation of a user's INBOX is considered to be an external task,
a6d65f
+that has to be completed as part of the user email account creation procedure. 
a6d65f
+Hence, to create a new email account the site administrator has to:
d0d307
+
a6d65f
+  a) Include the new account in the user database for the authentication procedure
a6d65f
+     (e.g. sasldb, shadow, mysql, ldap).
a6d65f
+  b) Create the corresponding INBOX folder. 
d0d307
+
a6d65f
+Alternatively, the user, if succesfully authenticated, may create his own INBOX folder,
a6d65f
+as long as the configuration of the site allows it (see "autocreatequota" in imapd.conf).
a6d65f
+Unlike what not careful readers may think, enabling the "autocreatequota" option, doesn't 
a6d65f
+lead to the automatic INBOX folder creation by Cyrus IMAP server.
a6d65f
+In fact, "autocreate" means that the IMAP clients are allowed to automatically create 
a6d65f
+the user INBOX. 
d0d307
+
a6d65f
+This patch adds the functionality of automatic creation of the users' INBOX folders into
a6d65f
+the Cyrus IMAP server. It is implemented as two features, namely the  "create on login"
a6d65f
+and "create on post".
a6d65f
+ 
d0d307
+
d0d307
+
a6d65f
+Create on login
a6d65f
+===============
a6d65f
+This feauture provides automatic creation of a user's INBOX folder when all of the 
a6d65f
+following requirements are met:
d0d307
+
a6d65f
+i)  The user has succesfully passed the authentication procedure.
d0d307
+
a6d65f
+ii) The user's authorisation ID (typically the same as the user's
a6d65f
+authentication ID)  doesn't belong to the imap_admins or admins
a6d65f
+accounts (see imapd.conf).
d0d307
+
a6d65f
+iii) The "autocreatequota" option in the imap configuration file 
a6d65f
+has been set to a non zero value. 
d0d307
+
a6d65f
+iv) The corresponding to the user's authorisation ID INBOX folder
a6d65f
+does not exist.
d0d307
+
a6d65f
+The user's first login is the most typical case when all four requirements are met. 
a6d65f
+Note that if the authenticated ID is allowed to proxy to another account for which 
a6d65f
+all of the above requirements are met, the corresponding INBOX folder for that account 
a6d65f
+will be created.
d0d307
+
d0d307
+
cf58a5
+
a6d65f
+Create on post
a6d65f
+==============
a6d65f
+This feauture provides automatic creation of a user's INBOX folder when all of the 
a6d65f
+following requirements are met. 
cf58a5
+
a6d65f
+i) An email message addressed to the user has been received.  
cf58a5
+
a6d65f
+ii) The recipient is not any of the imap_admins or admins accounts. 
a6d65f
+Note that passing emails to admins or imap_admins accounts from 
a6d65f
+the MTA to LMTP should be avoided in any case.
cf58a5
+
a6d65f
+iii) The recipient's INBOX does not exist.
d0d307
+
a6d65f
+iv) The "autocreatequota" option in the imap configuration file 
a6d65f
+has been set to a non zero value. 
d0d307
+
a6d65f
+v) The "createonpost" option in the imap configuration file 
a6d65f
+has been switched on. 
d0d307
+
d0d307
+
a6d65f
+Besides the automatic creation of INBOX folder, additional functionalities are
a6d65f
+provided:
d0d307
+
a6d65f
+  (A) Automatic creation of INBOX subfolders controlled by "autocreateinboxfolders"
a6d65f
+configuration option. eg 
d0d307
+
a6d65f
+autocreateinboxfolders: sent|drafts|spam|templates
d0d307
+
a6d65f
+  (B) Automatic subscription of INBOX subfolders controlled by "autosubscribeinboxfolders"
a6d65f
+configuration option. eg
d0d307
+
a6d65f
+autosubscribeinboxfolders: sent|spam
d0d307
+
a6d65f
+Obviously, only subscription to subfolders included in the "autocreateinboxfolder"
a6d65f
+list is meaningful. 
d0d307
+
a6d65f
+  (C) Automatic subscription to shared folders (bulletin boards). The user gets
a6d65f
+automatically subscribed to the shared folders declared in the "autosubscribesharedfolders"
a6d65f
+configuration option in imapd.conf.
a6d65f
+eg autosubscribesharedfolders: public_folder | public_folder.subfolder
d0d307
+
a6d65f
+In order the above action to succeed, the shared folder has to pre-exist the INBOX creation
a6d65f
+and the user must have the appropriate permissions in order to be able to subscribe to the
a6d65f
+shared folder.
d0d307
+
a6d65f
+* A new config option has been added. 'autosubscribe_all_sharedfolders' is a yes/no
a6d65f
+option. When set to yes, the user is automatically subscribed to all shared folders one