summaryrefslogtreecommitdiff
path: root/network/cyrus-imapd
diff options
context:
space:
mode:
Diffstat (limited to 'network/cyrus-imapd')
-rw-r--r--network/cyrus-imapd/README17
-rw-r--r--network/cyrus-imapd/README.SLACKWARE4
-rw-r--r--network/cyrus-imapd/cyrus-imapd.SlackBuild42
-rw-r--r--network/cyrus-imapd/cyrus-imapd.info8
-rw-r--r--network/cyrus-imapd/patches/cyrus-imapd-2.4.4-autocreate-0.10-0-slackware.patch2165
-rw-r--r--network/cyrus-imapd/patches/cyrus-imapd-2.4.4-autosieve-0.6.0.patch182
6 files changed, 2391 insertions, 27 deletions
diff --git a/network/cyrus-imapd/README b/network/cyrus-imapd/README
index 718fbb8dd2..c276947781 100644
--- a/network/cyrus-imapd/README
+++ b/network/cyrus-imapd/README
@@ -1,5 +1,3 @@
-What is IMAP?
-
The Cyrus IMAP (Internet Message Access Protocol) server provides access to
personal mail and system-wide bulletin boards through the IMAP protocol.
The Cyrus IMAP server is a scalable enterprise mail system designed for use
@@ -25,5 +23,16 @@ Cyrus technologies scale from independent use in email departments to a system
centrally managed in a large enterprise.
For more information on how to install and run cyrus-imapd, see
-README.SLACKWARE that came with this package (which is also installed with the
-docs).
+README.SLACKWARE that came with this package (which is also installed
+with the documentation).
+
+Two additional patches have been included, autocreate and autosieve, which
+improve cyrus' capabilities. To learn more about them, check their accompanying
+README files. To disable them, use: PATCHES=no ./cyrus-imapd.SlackBuild
+
+You must have a "cyrus" user and group to run this script.
+Something like this will create them:
+ # groupadd -g 238 cyrus
+ # useradd -d /var/imap -s /bin/sh -u 238 -g 238 cyrus
+See http://slackbuilds.org/uid_gid.txt for uid/gid suggestions.
+
diff --git a/network/cyrus-imapd/README.SLACKWARE b/network/cyrus-imapd/README.SLACKWARE
index 6866435185..acdd29007e 100644
--- a/network/cyrus-imapd/README.SLACKWARE
+++ b/network/cyrus-imapd/README.SLACKWARE
@@ -8,10 +8,10 @@ a specific directory structure, you can do something like this:
Afterwards run mkimap script to setup the enviroment:
# su - cyrus
-# /usr/doc/cyrus-imapd-2.3.16/tools/mkimap
+# /usr/doc/cyrus-imapd-2.4.6/tools/mkimap
You will probably also want to put this into rc.local:
if [ -x /etc/rc.d/rc.cyrus-imapd ]; then
- . /etc/rc.d/rc.cyrus-imapd start
+ /etc/rc.d/rc.cyrus-imapd start
fi
diff --git a/network/cyrus-imapd/cyrus-imapd.SlackBuild b/network/cyrus-imapd/cyrus-imapd.SlackBuild
index 710e0f4ea4..d1ce170e1b 100644
--- a/network/cyrus-imapd/cyrus-imapd.SlackBuild
+++ b/network/cyrus-imapd/cyrus-imapd.SlackBuild
@@ -2,7 +2,7 @@
# Slackware build script for cyrus-imapd
-# Copyright 2010, mario <mario@slackverse.org>
+# Copyright 2010-2011, mario <mario@slackverse.org>
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
@@ -23,16 +23,16 @@
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
PRGNAM=cyrus-imapd
-VERSION=${VERSION:-2.3.16}
+VERSION=${VERSION:-2.4.8}
BUILD=${BUILD:-1}
TAG=${TAG:-_SBo}
-# Automatically determine the architecture we're building on:
+PATCHES=${PATCHES:-yes}
+
if [ -z "$ARCH" ]; then
case "$( uname -m )" in
i?86) ARCH=i486 ;;
arm*) ARCH=arm ;;
- # Unless $ARCH is already set, use uname -m for all other archs:
*) ARCH=$( uname -m ) ;;
esac
fi
@@ -56,14 +56,14 @@ else
LIBDIRSUFFIX=""
fi
-# Bail if user isn't valid on your system
-if ! grep -q ^cyrus: /etc/passwd ; then
- echo " You must have a cyrus user to run this script."
- echo " # groupadd -g 238 cyrus"
- echo " # useradd -d /var/imap -s /bin/sh -u 238 -g 238 cyrus"
- echo " Or something similar."
+bailout() {
+ printf "\nYou must have a \"cyrus\" user and group to run this script.\n"
+ printf "Something like this will create them:\n"
+ printf "\t# groupadd -g 238 cyrus\n\t# useradd -d /var/imap -s /bin/sh -u 238 -g 238 cyrus\n\n"
exit 1
-fi
+}
+getent group cyrus >/dev/null || bailout
+getent passwd cyrus >/dev/null || bailout
# Build with mysql database by default, sqlite/mysql/postgresql are supported
DATABASE=${DATABASE:-mysql}
@@ -89,6 +89,12 @@ find . \
\( -perm 666 -o -perm 664 -o -perm 600 -o -perm 444 -o -perm 440 -o -perm 400 \) \
-exec chmod 644 {} \;
+if [ "$PATCHES" = yes ]; then
+# Patches for autocreate/autosieve
+ patch -p1 <$CWD/patches/cyrus-imapd-2.4.4-autocreate-0.10-0-slackware.patch
+ patch -p1 <$CWD/patches/cyrus-imapd-2.4.4-autosieve-0.6.0.patch
+fi
+
CFLAGS="$SLKCFLAGS" \
CXXFLAGS="$SLKCFLAGS" \
./configure \
@@ -105,8 +111,8 @@ CXXFLAGS="$SLKCFLAGS" \
--with-bdb-incdir=/usr/include/db4 \
--with-cyrus-user=cyrus \
--with-cyrus-group=cyrus \
- $DATABASE \
- --build=$ARCH-slackware-linux
+ --build=$ARCH-slackware-linux \
+ $DATABASE
make PERL_MM_OPT='INSTALLDIRS=vendor'
make install DESTDIR=$PKG
@@ -133,14 +139,16 @@ find $PKG -name perllocal.pod \
| xargs rm -f
mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
-cp -a COPYRIGHT README README.andrew doc/ master/conf tools/ $PKG/usr/doc/$PRGNAM-$VERSION
+cp -a COPYRIGHT README* doc/* master/conf tools/ $PKG/usr/doc/$PRGNAM-$VERSION
cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
cat $CWD/README.SLACKWARE > $PKG/usr/doc/$PRGNAM-$VERSION/README.SLACKWARE
# Clean up the obsolete /usr/lib on 64bit systems.
-if [ "$ARCH" = "x86_64" ]; then
- rmdir $PKG/usr/lib
-fi
+[ "$ARCH" = "x86_64" ] && rmdir $PKG/usr/lib
+
+# Remove perllocal.pod and other special files; remove empty directories
+find $PKG -name perllocal.pod -o -name ".packlist" -o -name "*.bs" | xargs rm -f || true
+find $PKG -depth -type d -empty -delete || true
mkdir -p $PKG/install
cat $CWD/slack-desc > $PKG/install/slack-desc
diff --git a/network/cyrus-imapd/cyrus-imapd.info b/network/cyrus-imapd/cyrus-imapd.info
index 64fad2a40a..8de2f720ba 100644
--- a/network/cyrus-imapd/cyrus-imapd.info
+++ b/network/cyrus-imapd/cyrus-imapd.info
@@ -1,10 +1,10 @@
PRGNAM="cyrus-imapd"
-VERSION="2.3.16"
+VERSION="2.4.8"
HOMEPAGE="http://www.cyrusimap.org/"
-DOWNLOAD="ftp://ftp.cyrusimap.org/cyrus-imapd/cyrus-imapd-2.3.16.tar.gz"
-MD5SUM="6a37feb1985974eee8a4a4b2932dd54c"
+DOWNLOAD="ftp://ftp.cyrusimap.org/cyrus-imapd/cyrus-imapd-2.4.8.tar.gz"
+MD5SUM="b55930293787a42d571a47f69aaacf28"
DOWNLOAD_x86_64=""
MD5SUM_x86_64=""
MAINTAINER="mario"
EMAIL="mario@slackverse.org"
-APPROVED="michiel"
+APPROVED="rworkman"
diff --git a/network/cyrus-imapd/patches/cyrus-imapd-2.4.4-autocreate-0.10-0-slackware.patch b/network/cyrus-imapd/patches/cyrus-imapd-2.4.4-autocreate-0.10-0-slackware.patch
new file mode 100644
index 0000000000..263af064c7
--- /dev/null
+++ b/network/cyrus-imapd/patches/cyrus-imapd-2.4.4-autocreate-0.10-0-slackware.patch
@@ -0,0 +1,2165 @@
+# Changed #include <com_err.h> to #include <et/com_err.h>
+# Updated by mario@slackverse.org, 2011
+diff -Naur cyrus-imapd-2.4.4.orig/README.autocreate cyrus-imapd-2.4.4/README.autocreate
+--- cyrus-imapd-2.4.4.orig/README.autocreate 1970-01-01 01:00:00.000000000 +0100
++++ cyrus-imapd-2.4.4/README.autocreate 2010-11-16 08:48:37.704981331 +0100
+@@ -0,0 +1,213 @@
++Cyrus IMAP autocreate Inbox patch
++----------------------------------
++
++NOTE : This patch has been created at the University of Athens. For more info, as well
++as more patches on Cyrus IMAPD server, please visit http://email.uoa.gr/
++
++NOTE : Patch updated for Cyrus IMAP 2.4.x by Martin Matuska <mm@FreeBSD.org>
++
++The design of Cyrus IMAP server does not predict the automatic creation of users'
++INBOX folders. The creation of a user's INBOX is considered to be an external task,
++that has to be completed as part of the user email account creation procedure.
++Hence, to create a new email account the site administrator has to:
++
++ a) Include the new account in the user database for the authentication procedure
++ (e.g. sasldb, shadow, mysql, ldap).
++ b) Create the corresponding INBOX folder.
++
++Alternatively, the user, if succesfully authenticated, may create his own INBOX folder,
++as long as the configuration of the site allows it (see "autocreatequota" in imapd.conf).
++Unlike what not careful readers may think, enabling the "autocreatequota" option, doesn't
++lead to the automatic INBOX folder creation by Cyrus IMAP server.
++In fact, "autocreate" means that the IMAP clients are allowed to automatically create
++the user INBOX.
++
++This patch adds the functionality of automatic creation of the users' INBOX folders into
++the Cyrus IMAP server. It is implemented as two features, namely the "create on login"
++and "create on post".
++
++
++
++Create on login
++===============
++This feauture provides automatic creation of a user's INBOX folder when all of the
++following requirements are met:
++
++i) The user has succesfully passed the authentication procedure.
++
++ii) The user's authorisation ID (typically the same as the user's
++authentication ID) doesn't belong to the imap_admins or admins
++accounts (see imapd.conf).
++
++iii) The "autocreatequota" option in the imap configuration file
++has been set to a non zero value.
++
++iv) The corresponding to the user's authorisation ID INBOX folder
++does not exist.
++
++The user's first login is the most typical case when all four requirements are met.
++Note that if the authenticated ID is allowed to proxy to another account for which
++all of the above requirements are met, the corresponding INBOX folder for that account
++will be created.
++
++
++
++Create on post
++==============
++This feauture provides automatic creation of a user's INBOX folder when all of the
++following requirements are met.
++
++i) An email message addressed to the user has been received.
++
++ii) The recipient is not any of the imap_admins or admins accounts.
++Note that passing emails to admins or imap_admins accounts from
++the MTA to LMTP should be avoided in any case.
++
++iii) The recipient's INBOX does not exist.
++
++iv) The "autocreatequota" option in the imap configuration file
++has been set to a non zero value.
++
++v) The "createonpost" option in the imap configuration file
++has been switched on.
++
++
++Besides the automatic creation of INBOX folder, additional functionalities are
++provided:
++
++ (A) Automatic creation of INBOX subfolders controlled by "autocreateinboxfolders"
++configuration option. eg
++
++autocreateinboxfolders: sent|drafts|spam|templates
++
++ (B) Automatic subscription of INBOX subfolders controlled by "autosubscribeinboxfolders"
++configuration option. eg
++
++autosubscribeinboxfolders: sent|spam
++
++Obviously, only subscription to subfolders included in the "autocreateinboxfolder"
++list is meaningful.
++
++ (C) Automatic subscription to shared folders (bulletin boards). The user gets
++automatically subscribed to the shared folders declared in the "autosubscribesharedfolders"
++configuration option in imapd.conf.
++eg autosubscribesharedfolders: public_folder | public_folder.subfolder
++
++In order the above action to succeed, the shared folder has to pre-exist the INBOX creation
++and the user must have the appropriate permissions in order to be able to subscribe to the
++shared folder.
++
++* A new config option has been added. 'autosubscribe_all_sharedfolders' is a yes/no
++option. When set to yes, the user is automatically subscribed to all shared folders one
++has permission to subscribe to. Please, note that when this option is set to yes, then
++'autosubscribesharedfolders' option is overriden.
++
++ (D) Automatic creation of a predefined default sieve script.
++
++This is very useful when a default sieve script is used for every user. Usually, a
++default anti-spam script may me be written in a file and copied to each user
++sieve scripts upon the INBOX creation. The imapd.conf options that have been added
++are 'autocreate_sieve_script', 'autocreate_sieve_compiledscript' and
++'generate_compiled_sieve_script'.
++
++autocreate_sieve_script configuration option refers to the full path of the file
++that contains the sieve script. The default value is null and if no file is defined,
++then no default script is created upon INBOX creation. (The feature is disabled)
++eg autocreate_sieve_script: /etc/default_sieve_script
++
++autocreate_sieve_compiledscript configuration option refers to the full path of the
++file that contains the bytecode compiled sieve script. If this filename is defined
++in imapd.conf and the file exists, then it is automatically copied in the user's sieve
++directory. If it is not defined, then a bytecode sieve script gets on the fly compiled
++by the daemon.
++eg autocreate_sieve_compiledscript: /etc/default_sieve_script.bc
++
++generate_compiled_sieve_script is a boolean option that triggers the compilation of the
++source sieve script to bytecode sieve script. The file that the bytecode script will
++be saved is pointed by autocreate_sieve_compiledscript.
++
++Ways of compiling a sieve script :
++1. Compile a sieve script using the standard sievec utility, distributed by CMU
++2. Compile a sieve script using the compile_sieve utility, released by UoA. This
++ tool is almost identical to the sievec utility, with the difference that it
++ reads the input and output file from autocreate_sieve_script and
++ autocreate_sieve_compiledscript options in imapd.conf
++3. Let cyrus create a compiled sieve script using a source script. Cyrus can be
++ instructed to save the compiled script any time a compiled script does not exist.
++
++NOTES :
++1. In order this functionality to work, the following requirements must have been met:
++ - 'sieveusehomedir' option must be 'no' in the configuration (default).
++ - 'sievedir' option must have a valid value.
++2. Currently, this patch checks the validity of the source script while generating a
++ bytecode compiled script, but not the validity of the bytecode sieve script file.
++ The administrator should make sure that the provided files contain a valid sieve
++ script as well as the compiled script is updated every time the source script changes.
++
++
++ (E) The administrator may control for which users and/or groups may the INBOXes
++automatically be created. The autocreate_users option restricts the groups
++for which the patch will create the mailboxes.
++
++The default value of autocreate_users is anyone. So, if not set at all, the patch will
++work for all users. However, one may set:
++
++autocreate_users: user1 user2 group:group1 group:group2
++
++In that case, the INBOX will be created only for user1, user2 and the users that belong
++to group1 and group2.
++
++More refined control per service is provided by the options imap_autocreate_users,
++pop3_autocreate_users and lmtp_autocreate_users. These options override the
++autocreate_users option and offer per service control.
++
++Example:
++One may want to restrict the create on post functionality only for a specific group
++of users. To achieve this, the following lines must be added in the imapd.conf file:
++
++createonpost: yes
++lmtp_autocreate_users: group:groupname
++
++
++
++Issues to be considered
++=======================
++
++I) In order to use the create on post feauture one should be absolutely sure that:
++a) The MTA checks the validity of the email recipient before sending the email to
++LMTP. This is an RFC821 requirement. This usually expands to "the mta should be
++able to use the account database as user mailbox database".
++b) Only authorised accounts/services can talk to LMTP.
++
++II) Especially in the case of imap logins, the current patch implementation checks
++for the INBOX folder existence upon login, causing an extra mailbox lookup in most
++of the cases.
++A better approach would be to chase the "IMAP_MAILBOX_NONEXISTENT" error code and
++check if the error is associated with an INBOX folder. However, this would mess up
++Cyrus code. The way it was implemented may not have been the most performance
++optimised, but it produces a much cleaner and simple patch.
++
++
++
++Virtual Domains Support
++=======================
++
++Virtual domains are supported by all versions of the patch for cyrus-imapd-2.2.1-BETA and
++later. However, it is not possible to declare different INBOX subfolders to be created or
++shared folders to be subscribed to for every domain.
++
++
++
++Things to be done
++=================
++
++1. Support MUPDATE
++
++It is within the developers' intentions to support the mupdate protocol, but serious
++design issues on future cyrus releases have to resolved first.
++
++2. Select different attributes (quota, partition, sieve filter, etc) depending on the group
++a user belongs to.
++
++For more information and updates please visit http://email.uoa.gr/projects/cyrus/autocreate
++
+diff -Naur cyrus-imapd-2.4.4.orig/imap/Makefile.in cyrus-imapd-2.4.4/imap/Makefile.in
+--- cyrus-imapd-2.4.4.orig/imap/Makefile.in 2010-11-16 08:48:20.817612092 +0100
++++ cyrus-imapd-2.4.4/imap/Makefile.in 2010-11-16 08:49:21.892354019 +0100
+@@ -66,7 +66,7 @@
+ IMAP_COM_ERR_LIBS = @IMAP_COM_ERR_LIBS@
+ LIB_WRAP = @LIB_WRAP@
+ LIBS = $(IMAP_LIBS) $(IMAP_COM_ERR_LIBS)
+-DEPLIBS = ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
++DEPLIBS = $(SIEVE_LIBS) ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
+
+ CFLAGS = @CFLAGS@
+ LDFLAGS = @LDFLAGS@ @COM_ERR_LDFLAGS@
+@@ -102,7 +102,7 @@
+ imapparse.o telemetry.o user.o notify.o idle.o quota_db.o \
+ sync_log.o $(SEEN) mboxkey.o backend.o tls.o message_guid.o \
+ statuscache_db.o userdeny_db.o sequence.o upgrade_index.o \
+- dlist.o version.o
++ dlist.o version.o autosieve.o
+
+ IMAPDOBJS=pushstats.o imapd.o proxy.o imap_proxy.o index.o
+
+@@ -118,7 +118,7 @@
+ fud smmapd reconstruct quota mbpath ipurge cyr_dbtool cyr_synclog \
+ cyrdump chk_cyrus cvt_cyrusdb deliver ctl_mboxlist \
+ ctl_deliver ctl_cyrusdb squatter mbexamine cyr_expire arbitron \
+- unexpunge cyr_df cyr_sequence cyr_userseen @IMAP_PROGS@
++ unexpunge compile_sieve cyr_df cyr_sequence cyr_userseen @IMAP_PROGS@
+
+ BUILTSOURCES = imap_err.c imap_err.h pushstats.c pushstats.h \
+ lmtpstats.c lmtpstats.h mupdate_err.c mupdate_err.h \
+@@ -180,9 +180,9 @@
+ mupdate_err.h: mupdate_err.c
+
+ ### Services
+-idled: idled.o mutex_fake.o libimap.a $(DEPLIBS)
++idled: idled.o mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS)
+ $(CC) $(LDFLAGS) -o idled \
+- idled.o mutex_fake.o libimap.a $(DEPLIBS) $(LIBS)
++ idled.o mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
+
+ lmtpd: lmtpd.o proxy.o $(LMTPOBJS) $(SIEVE_OBJS) mutex_fake.o \
+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
+@@ -365,6 +365,10 @@
+ sync_reset sync_reset.o sync_support.o \
+ libimap.a mutex_fake.o $(DEPLIBS) $(LIBS)
+
++compile_sieve: compile_sieve.o libimap.a $(DEPLIBS) $(SIEVE_LIBS)
++ $(CC) $(LDFLAGS) -o compile_sieve compile_sieve.o $(CLIOBJS) \
++ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
++
+ ### Other Misc Targets
+
+ clean:
+diff -Naur cyrus-imapd-2.4.4.orig/imap/autosieve.c cyrus-imapd-2.4.4/imap/autosieve.c
+--- cyrus-imapd-2.4.4.orig/imap/autosieve.c 1970-01-01 01:00:00.000000000 +0100
++++ cyrus-imapd-2.4.4/imap/autosieve.c 2010-11-16 08:48:37.722056581 +0100
+@@ -0,0 +1,590 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++#ifdef HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <sys/uio.h>
++#include <fcntl.h>
++#include <ctype.h>
++#include <time.h>
++#include <syslog.h>
++#include <et/com_err.h>
++#include <config.h>
++
++#include "global.h"
++#include "util.h"
++#include "xmalloc.h"
++#include "xstrlcpy.h"
++#include "xstrlcat.h"
++#include "mailbox.h"
++#include "imap_err.h"
++#include "sieve_interface.h"
++#include "script.h"
++
++#define TIMSIEVE_FAIL -1
++#define TIMSIEVE_OK 0
++#define MAX_FILENAME 1024
++
++static int get_script_name(char *sievename, size_t buflen, const char *filename);
++static int get_script_dir(char *sieve_script_dir, size_t buflen, char *userid, const char *sieve_dir);
++int autoadd_sieve(char *userid, const char *source_script);
++
++//static void fatal(const char *s, int code);
++static void foo(void);
++static int sieve_notify(void *ac __attribute__((unused)),
++ void *interp_context __attribute__((unused)),
++ void *script_context __attribute__((unused)),
++ void *message_context __attribute__((unused)),
++ const char **errmsg __attribute__((unused)));
++static int mysieve_error(int lineno, const char *msg,
++ void *i __attribute__((unused)), void *s);
++static int is_script_parsable(FILE *stream, char **errstr, sieve_script_t **ret);
++
++
++sieve_vacation_t vacation2 = {
++ 0, /* min response */
++ 0, /* max response */
++ (sieve_callback *) &foo, /* autorespond() */
++ (sieve_callback *) &foo /* send_response() */
++};
++
++
++/*
++ * Find the name of the sieve script
++ * given the source script and compiled script names
++ */
++static int get_script_name(char *sievename, size_t buflen, const char *filename)
++{
++ char *p;
++ int r;
++
++ p = strrchr(filename, '/');
++ if (p == NULL)
++ p = (char *) filename;
++ else
++ p++;
++
++ r = strlcpy(sievename, p, buflen) - buflen;
++ return (r >= 0 || r == -buflen ? 1 : 0);
++}
++
++
++/*
++ * Find the directory where the sieve scripts of the user
++ * reside
++ */
++static int get_script_dir(char *sieve_script_dir, size_t buflen, char *userid, const char *sieve_dir)
++{
++ char *user = NULL, *domain = NULL;
++
++ /* Setup the user and the domain */
++ if(config_virtdomains && (domain = strchr(userid, '@'))) {
++ user = (char *) xmalloc((domain - userid +1) * sizeof(char));
++ strlcpy(user, userid, domain - userid + 1);
++ domain++;
++ } else
++ user = userid;
++
++ /* Find the dir path where the sieve scripts of the user will reside */
++ if (config_virtdomains && domain) {
++ if(snprintf(sieve_script_dir, buflen, "%s%s%c/%s/%c/%s/",
++ sieve_dir, FNAME_DOMAINDIR, dir_hash_c(domain, config_fulldirhash), domain, dir_hash_c(user,config_fulldirhash), user) >= buflen) {
++ free(user);
++ return 1;
++ }
++ } else {
++ if(snprintf(sieve_script_dir, buflen, "%s/%c/%s/",
++ sieve_dir, dir_hash_c(user,config_fulldirhash), user) >= buflen)
++ return 1;
++ }
++
++ /* Free the xmalloced user memory, reserved above */
++ if(user != userid)
++ free(user);
++
++ return 0;
++}
++
++int autoadd_sieve(char *userid, const char *source_script)
++{
++ sieve_script_t *s = NULL;
++ bytecode_info_t *bc = NULL;
++ char *err = NULL;
++ FILE *in_stream, *out_fp;
++ int out_fd, in_fd, r, k;
++ int do_compile = 0;
++ const char *sieve_dir = NULL;
++ const char *compiled_source_script = NULL;
++ char sievename[MAX_FILENAME];
++ char sieve_script_name[MAX_FILENAME];
++ char sieve_script_dir[MAX_FILENAME];
++ char sieve_bcscript_name[MAX_FILENAME];
++ char sieve_default[MAX_FILENAME];
++ char sieve_tmpname[MAX_FILENAME];
++ char sieve_bctmpname[MAX_FILENAME];
++ char sieve_bclink_name[MAX_FILENAME];
++ char buf[4096];
++ mode_t oldmask;
++ struct stat statbuf;
++
++ /* We don't support using the homedirectory, like timsieved */
++ if (config_getswitch(IMAPOPT_SIEVEUSEHOMEDIR)) {
++ syslog(LOG_WARNING,"autocreate_sieve: autocreate_sieve does not work with sieveusehomedir option in imapd.conf");
++ return 1;
++ }
++
++ /* Check if sievedir is defined in imapd.conf */
++ if(!(sieve_dir = config_getstring(IMAPOPT_SIEVEDIR))) {
++ syslog(LOG_WARNING, "autocreate_sieve: sievedir option is not defined. Check imapd.conf");
++ return 1;
++ }
++
++ /* Check if autocreate_sieve_compiledscript is defined in imapd.conf */
++ if(!(compiled_source_script = config_getstring(IMAPOPT_AUTOCREATE_SIEVE_COMPILEDSCRIPT))) {
++ syslog(LOG_WARNING, "autocreate_sieve: autocreate_sieve_compiledscript option is not defined. Compiling it");
++ do_compile = 1;
++ }
++
++ if(get_script_dir(sieve_script_dir, sizeof(sieve_script_dir), userid, sieve_dir)) {
++ syslog(LOG_WARNING, "autocreate_sieve: Cannot find sieve scripts directory");
++ return 1;
++ }
++
++ if (get_script_name(sievename, sizeof(sievename), source_script)) {
++ syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve script %s", source_script);
++ return 1;
++ }
++
++ if(snprintf(sieve_tmpname, sizeof(sieve_tmpname), "%s%s.script.NEW",sieve_script_dir, sievename) >= sizeof(sieve_tmpname)) {
++ syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
++ return 1;
++ }
++ if(snprintf(sieve_bctmpname, sizeof(sieve_bctmpname), "%s%s.bc.NEW",sieve_script_dir, sievename) >= sizeof(sieve_bctmpname)) {
++ syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
++ return 1;
++ }
++ if(snprintf(sieve_script_name, sizeof(sieve_script_name), "%s%s.script",sieve_script_dir, sievename) >= sizeof(sieve_script_name)) {
++ syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
++ return 1;
++ }
++ if(snprintf(sieve_bcscript_name, sizeof(sieve_bcscript_name), "%s%s.bc",sieve_script_dir, sievename) >= sizeof(sieve_bcscript_name)) {
++ syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
++ return 1;
++ }
++ if(snprintf(sieve_default, sizeof(sieve_default), "%s%s",sieve_script_dir,"defaultbc") >= sizeof(sieve_default)) {
++ syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
++ return 1;
++ }
++ if(snprintf(sieve_bclink_name, sizeof(sieve_bclink_name), "%s.bc", sievename) >= sizeof(sieve_bclink_name)) {
++ syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
++ return 1;
++ }
++
++ /* Check if a default sieve filter alrady exists */
++ if(!stat(sieve_default,&statbuf)) {
++ syslog(LOG_WARNING,"autocreate_sieve: Default sieve script already exists");
++ fclose(in_stream);
++ return 1;
++ }
++
++ /* Open the source script. if there is a problem with that exit */
++ in_stream = fopen(source_script, "r");
++ if(!in_stream) {
++ syslog(LOG_WARNING,"autocreate_sieve: Unable to open sieve script %s. Check permissions",source_script);
++ return 1;
++ }
++
++
++ /*
++ * At this point we start the modifications of the filesystem
++ */
++
++ /* Create the directory where the sieve scripts will reside */
++ r = cyrus_mkdir(sieve_script_dir, 0755);
++ if(r == -1) {
++ /* If this fails we just leave */
++ syslog(LOG_WARNING,"autocreate_sieve: Unable to create directory %s. Check permissions",sieve_script_name);
++ return 1;
++ }
++
++ /*
++ * We open the file that will be used as the bc file. If this file exists, overwrite it
++ * since something bad has happened. We open the file here so that this error checking is
++ * done before we try to open the rest of the files to start copying etc.
++ */
++ out_fd = open(sieve_bctmpname, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
++ if(out_fd < 0) {
++ if(errno == EEXIST) {
++ syslog(LOG_WARNING,"autocreate_sieve: File %s already exists. Probaly left over. Ignoring",sieve_bctmpname);
++ } else if (errno == EACCES) {
++ syslog(LOG_WARNING,"autocreate_sieve: No access to create file %s. Check permissions",sieve_bctmpname);
++ fclose(in_stream);
++ return 1;
++ } else {
++ syslog(LOG_WARNING,"autocreate_sieve: Unable to create %s. Unknown error",sieve_bctmpname);
++ fclose(in_stream);
++ return 1;
++ }
++ }
++
++ if(!do_compile && compiled_source_script && (in_fd = open(compiled_source_script, O_RDONLY)) != -1) {
++ while((r = read(in_fd, buf, sizeof(buf))) > 0) {
++ if((k=write(out_fd, buf,r)) < 0) {
++ syslog(LOG_WARNING, "autocreate_sieve: Error writing to file: %s, error: %d", sieve_bctmpname, errno);
++ close(out_fd);
++ close(in_fd);
++ fclose(in_stream);
++ unlink(sieve_bctmpname);
++ return 1;
++ }
++ }
++
++ if(r == 0) { /* EOF */
++ close(out_fd);
++ close(in_fd);
++ } else if (r < 0) {
++ syslog(LOG_WARNING, "autocreate_sieve: Error reading compiled script file: %s. Will try to compile it",
++ compiled_source_script);
++ close(in_fd);
++ do_compile = 1;
++ if(lseek(out_fd, 0, SEEK_SET)) {
++ syslog(LOG_WARNING, "autocreate_sieve: Major IO problem. Aborting");
++ return 1;
++ }
++ }
++ close(in_fd);
++ } else {
++ if(compiled_source_script)
++ syslog(LOG_WARNING,"autocreate_sieve: Problem opening compiled script file: %s. Compiling it", compiled_source_script);
++ do_compile = 1;
++ }
++
++
++ /* Because we failed to open a precompiled bc sieve script, we compile one */
++ if(do_compile) {
++ if(is_script_parsable(in_stream,&err, &s) == TIMSIEVE_FAIL) {
++ if(err && *err) {
++ syslog(LOG_WARNING,"autocreate_sieve: Error while parsing script %s.",err);
++ free(err);
++ } else
++ syslog(LOG_WARNING,"autocreate_sieve: Error while parsing script");
++
++ unlink(sieve_bctmpname);
++ fclose(in_stream);
++ close(out_fd);
++ return 1;
++ }
++
++ /* generate the bytecode */
++ if(sieve_generate_bytecode(&bc, s) == TIMSIEVE_FAIL) {
++ syslog(LOG_WARNING,"autocreate_sieve: problem compiling sieve script");
++ /* removing the copied script and cleaning up memory */
++ unlink(sieve_bctmpname);
++ sieve_script_free(&s);
++ fclose(in_stream);
++ close(out_fd);
++ return 1;
++ }
++
++ if(sieve_emit_bytecode(out_fd, bc) == TIMSIEVE_FAIL) {
++ syslog(LOG_WARNING,"autocreate_sieve: problem emiting sieve script");
++ /* removing the copied script and cleaning up memory */
++ unlink(sieve_bctmpname);
++ sieve_free_bytecode(&bc);
++ sieve_script_free(&s);
++ fclose(in_stream);
++ close(out_fd);
++ return 1;
++ }
++
++ /* clean up the memory */
++ sieve_free_bytecode(&bc);
++ sieve_script_free(&s);
++ }
++
++ close(out_fd);
++ rewind(in_stream);
++
++ /* Copy the initial script */
++ oldmask = umask(077);
++ if((out_fp = fopen(sieve_tmpname, "w")) == NULL) {
++ syslog(LOG_WARNING,"autocreate_sieve: Unable to open %s destination sieve script", sieve_tmpname);
++ unlink(sieve_bctmpname);
++ umask(oldmask);
++ fclose(in_stream);
++ return 1;
++ }
++ umask(oldmask);
++
++ while((r = fread(buf,sizeof(char), sizeof(buf), in_stream))) {
++ if( fwrite(buf,sizeof(char), r, out_fp) != r) {
++ syslog(LOG_WARNING,"autocreate_sieve: Problem writing to sieve script file: %s",sieve_tmpname);
++ fclose(out_fp);
++ unlink(sieve_tmpname);
++ unlink(sieve_bctmpname);
++ fclose(in_stream);
++ return 1;
++ }
++ }
++
++ if(feof(in_stream)) {
++ fclose(out_fp);
++ } else { /* ferror */
++ fclose(out_fp);
++ unlink(sieve_tmpname);
++ unlink(sieve_bctmpname);
++ fclose(in_stream);
++ return 1;
++ }
++
++ /* Renaming the necessary stuff */
++ if(rename(sieve_tmpname, sieve_script_name)) {
++ unlink(sieve_tmpname);
++ unlink(sieve_bctmpname);
++ return 1;
++ }
++
++ if(rename(sieve_bctmpname, sieve_bcscript_name)) {
++ unlink(sieve_bctmpname);
++ unlink(sieve_bcscript_name);
++ return 1;
++ }
++
++ /* end now with the symlink */
++ if(symlink(sieve_bclink_name, sieve_default)) {
++ if(errno != EEXIST) {
++ syslog(LOG_WARNING, "autocreate_sieve: problem making the default link.");
++ /* Lets delete the files */
++ unlink(sieve_script_name);
++ unlink(sieve_bcscript_name);
++ }
++ }
++
++ /*
++ * If everything has succeeded AND we have compiled the script AND we have requested
++ * to generate the global script so that it is not compiled each time then we create it.
++ */
++ if(do_compile &&
++ config_getswitch(IMAPOPT_GENERATE_COMPILED_SIEVE_SCRIPT)) {
++
++ if(!compiled_source_script) {
++ syslog(LOG_WARNING, "autocreate_sieve: To save a compiled sieve script, autocreate_sieve_compiledscript must have been defined in imapd.conf");
++ return 0;
++ }
++
++ if(snprintf(sieve_tmpname, sizeof(sieve_tmpname), "%s.NEW", compiled_source_script) >= sizeof(sieve_tmpname))
++ return 0;
++
++ /*
++ * Copy everything from the newly created bc sieve sieve script.
++ */
++ if((in_fd = open(sieve_bcscript_name, O_RDONLY))<0) {
++ return 0;
++ }
++
++ if((out_fd = open(sieve_tmpname, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
++ if(errno == EEXIST) {
++ /* Someone is already doing this so just bail out. */
++ syslog(LOG_WARNING, "autocreate_sieve: %s already exists. Some other instance processing it, or it is left over", sieve_tmpname);
++ close(in_fd);
++ return 0;
++ } else if (errno == EACCES) {
++ syslog(LOG_WARNING,"autocreate_sieve: No access to create file %s. Check permissions",sieve_tmpname);
++ close(in_fd);
++ return 0;
++ } else {
++ syslog(LOG_WARNING,"autocreate_sieve: Unable to create %s",sieve_tmpname);
++ close(in_fd);
++ return 0;
++ }
++ }
++
++ while((r = read(in_fd, buf, sizeof(buf))) > 0) {
++ if((k = write(out_fd,buf,r)) < 0) {
++ syslog(LOG_WARNING, "autocreate_sieve: Error writing to file: %s, error: %d", sieve_tmpname, errno);
++ close(out_fd);
++ close(in_fd);
++ unlink(sieve_tmpname);
++ return 0;
++ }
++ }
++
++ if(r == 0 ) { /*EOF */
++ close(out_fd);
++ close(in_fd);
++ } else if (r < 0) {
++ syslog(LOG_WARNING, "autocreate_sieve: Error writing to file: %s, error: %d", sieve_tmpname, errno);
++ close(out_fd);
++ close(in_fd);
++ unlink(sieve_tmpname);
++ return 0;
++ }
++
++ /* Rename the temporary created sieve script to its final name. */
++ if(rename(sieve_tmpname, compiled_source_script)) {
++ if(errno != EEXIST) {
++ unlink(sieve_tmpname);
++ unlink(compiled_source_script);
++ }
++ return 0;
++ }
++
++ syslog(LOG_NOTICE, "autocreate_sieve: Compiled sieve script was successfully saved in %s", compiled_source_script);
++ }
++
++ return 0;
++}
++
++/*static void fatal(const char *s, int code)
++{
++ printf("Fatal error: %s (%d)\r\n", s, code);
++ exit(1);
++}*/
++
++/* to make larry's stupid functions happy :) */
++static void foo(void)
++{
++ fatal("stub function called", 0);
++}
++
++static int sieve_notify(void *ac __attribute__((unused)),
++ void *interp_context __attribute__((unused)),
++ void *script_context __attribute__((unused)),
++ void *message_context __attribute__((unused)),
++ const char **errmsg __attribute__((unused)))
++{
++ fatal("stub function called", 0);
++ return SIEVE_FAIL;
++}
++
++static int mysieve_error(int lineno, const char *msg,
++ void *i __attribute__((unused)), void *s)
++{
++ char buf[1024];
++ char **errstr = (char **) s;
++
++ snprintf(buf, 80, "line %d: %s\r\n", lineno, msg);
++ *errstr = (char *) xrealloc(*errstr, strlen(*errstr) + strlen(buf) + 30);
++ syslog(LOG_DEBUG, "%s", buf);
++ strcat(*errstr, buf);
++
++ return SIEVE_OK;
++}
++
++/* end the boilerplate */
++
++/* returns TRUE or FALSE */
++int is_script_parsable(FILE *stream, char **errstr, sieve_script_t **ret)
++{
++ sieve_interp_t *i;
++ sieve_script_t *s;
++ int res;
++
++ res = sieve_interp_alloc(&i, NULL);
++ if (res != SIEVE_OK) {
++ syslog(LOG_WARNING, "sieve_interp_alloc() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ res = sieve_register_redirect(i, (sieve_callback *) &foo);
++ if (res != SIEVE_OK) {
++ syslog(LOG_WARNING, "sieve_register_redirect() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++ res = sieve_register_discard(i, (sieve_callback *) &foo);
++ if (res != SIEVE_OK) {
++ syslog(LOG_WARNING, "sieve_register_discard() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++ res = sieve_register_reject(i, (sieve_callback *) &foo);
++ if (res != SIEVE_OK) {
++ syslog(LOG_WARNING, "sieve_register_reject() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++ res = sieve_register_fileinto(i, (sieve_callback *) &foo);
++ if (res != SIEVE_OK) {
++ syslog(LOG_WARNING, "sieve_register_fileinto() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++ res = sieve_register_keep(i, (sieve_callback *) &foo);
++ if (res != SIEVE_OK) {
++ syslog(LOG_WARNING, "sieve_register_keep() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ res = sieve_register_imapflags(i, NULL);
++ if (res != SIEVE_OK) {
++ syslog(LOG_WARNING, "sieve_register_imapflags() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ res = sieve_register_size(i, (sieve_get_size *) &foo);
++ if (res != SIEVE_OK) {
++ syslog(LOG_WARNING, "sieve_register_size() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ res = sieve_register_header(i, (sieve_get_header *) &foo);
++ if (res != SIEVE_OK) {
++ syslog(LOG_WARNING, "sieve_register_header() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ res = sieve_register_envelope(i, (sieve_get_envelope *) &foo);
++ if (res != SIEVE_OK) {
++ syslog(LOG_WARNING, "sieve_register_envelope() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ res = sieve_register_vacation(i, &vacation2);
++ if (res != SIEVE_OK) {
++ syslog(LOG_WARNING, "sieve_register_vacation() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ res = sieve_register_notify(i, &sieve_notify);
++ if (res != SIEVE_OK) {
++ syslog(LOG_WARNING, "sieve_register_notify() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ res = sieve_register_parse_error(i, &mysieve_error);
++ if (res != SIEVE_OK) {
++ syslog(LOG_WARNING, "sieve_register_parse_error() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ rewind(stream);
++
++ *errstr = (char *) xmalloc(20 * sizeof(char));
++ strcpy(*errstr, "script errors:\r\n");
++
++ res = sieve_script_parse(i, stream, errstr, &s);
++
++ if (res == SIEVE_OK) {
++ if(ret) {
++ *ret = s;
++ } else {
++ sieve_script_free(&s);
++ }
++ free(*errstr);
++ *errstr = NULL;
++ }
++
++ /* free interpreter */
++ sieve_interp_free(&i);
++
++ return (res == SIEVE_OK) ? TIMSIEVE_OK : TIMSIEVE_FAIL;
++}
++
++/*
++ * Btw the initial date of this patch is Sep, 02 2004 which is the birthday of
++ * Pavlos. Author of cyrusmaster. So consider this patch as his birthday present
++ */
++
+diff -Naur cyrus-imapd-2.4.4.orig/imap/compile_sieve.c cyrus-imapd-2.4.4/imap/compile_sieve.c
+--- cyrus-imapd-2.4.4.orig/imap/compile_sieve.c 1970-01-01 01:00:00.000000000 +0100
++++ cyrus-imapd-2.4.4/imap/compile_sieve.c 2010-11-16 08:48:37.724064645 +0100
+@@ -0,0 +1,365 @@
++/* This tool compiles the sieve script from a command
++line so that it can be used wby the autoadd patch */
++#include <stdio.h>
++#include <stdlib.h>
++
++#include <config.h>
++#include <string.h>
++#ifdef HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <sys/uio.h>
++#include <fcntl.h>
++#include <ctype.h>
++#include <time.h>
++#include <et/com_err.h>
++
++#include "global.h"
++
++#include "util.h"
++#include "xmalloc.h"
++#include "xstrlcpy.h"
++#include "xstrlcat.h"
++#include "mailbox.h"
++#include "imap_err.h"
++#include "sieve_interface.h"
++#include "script.h"
++
++#include <pwd.h>
++
++#define TIMSIEVE_FAIL -1
++#define TIMSIEVE_OK 0
++#define MAX_FILENAME_SIZE 100
++
++/* Needed by libconfig */
++const int config_need_data = 0;
++
++static int is_script_parsable(FILE *stream, char **errstr, sieve_script_t **ret);
++
++/*static void fatal(const char *s, int code)
++{
++ printf("Fatal error: %s (%d)\r\n", s, code);
++
++ exit(1);
++}*/
++
++void usage(void)
++{
++ fprintf(stderr,
++ "Usage:\n\tcompile_sieve [-C <altconfig>] [-i <infile> -o <outfile>]\n");
++ exit(-1);
++}
++
++
++int main (int argc, char **argv)
++{
++
++ sieve_script_t *s = NULL;
++ bytecode_info_t *bc = NULL;
++ char *err = NULL;
++ FILE *in_stream;
++ int out_fd, opt;
++ char *source_script = NULL;
++ char *compiled_source_script = NULL;
++ char *alt_config = NULL;
++ extern char *optarg;
++ char sieve_tmpname[MAX_MAILBOX_NAME+1];
++
++ if (geteuid() == 0) fatal("must run as the Cyrus user", EC_USAGE);
++
++ while((opt = getopt(argc, argv, "C:i:o:")) != EOF) {
++ switch (opt) {
++ case 'C': /* alt config file */
++ alt_config = optarg;
++ break;
++ case 'i': /* input script file */
++ source_script = optarg;
++ break;
++ case 'o': /* output script file */
++ compiled_source_script = optarg;
++ break;
++ default:
++ usage();
++ break;
++ }
++ }
++
++ if(source_script && !compiled_source_script) {
++ fprintf(stderr, "No output file was defined\n");
++ usage();
++ } else if (!source_script && compiled_source_script) {
++ fprintf(stderr, "No input file was defined\n");
++ usage();
++ }
++
++ /*
++ * If no <infile> has been defined, then read them from
++ * the configuration file.
++ */
++ if (!source_script && !compiled_source_script) {
++ cyrus_init(alt_config, "compile_sieve", 0);
++
++ /* Initially check if we want to have the sieve script created */
++ if(!(source_script = (char *) config_getstring(IMAPOPT_AUTOCREATE_SIEVE_SCRIPT))) {
++ fprintf(stderr,"autocreate_sieve_script option not defined. Check imapd.conf\n");
++ return 1;
++ }
++
++ /* Check if we have an already compiled sieve script*/
++ if(!(compiled_source_script = (char *) config_getstring(IMAPOPT_AUTOCREATE_SIEVE_COMPILEDSCRIPT))) {
++ fprintf(stderr, "autocreate_sieve_compiledscript option not defined. Check imapd.conf\n");
++ return 1;
++ }
++
++ if(!strrchr(source_script,'/') || !strrchr(compiled_source_script,'/')) {
++ /*
++ * At this point the only think that is inconsistent is the directory
++ * that was created. But if the user will have any sieve scripts then
++ * they will eventually go there, so no big deal
++ */
++ fprintf(stderr,
++ "In imapd.conf the full path of the filenames must be defined\n");
++ return 1;
++ }
++ }
++
++ printf("input file : %s, output file : %s\n", source_script, compiled_source_script);
++
++
++ if(strlen(compiled_source_script) + sizeof(".NEW") + 1 > sizeof(sieve_tmpname)) {
++ fprintf(stderr, "Filename %s is too big\n", compiled_source_script);
++ return 1;
++ }
++
++ snprintf(sieve_tmpname, sizeof(sieve_tmpname), "%s.NEW", compiled_source_script);
++
++ in_stream = fopen(source_script,"r");
++
++ if(!in_stream) {
++ fprintf(stderr,"Unable to open %s source sieve script\n",source_script);
++ return 1;
++ }
++
++ /*
++ * We open the file that will be used as the bc file. If this file exists, overwrite it
++ * since something bad has happened. We open the file here so that this error checking is
++ * done before we try to open the rest of the files to start copying etc.
++ */
++ out_fd = open(sieve_tmpname, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
++ if(out_fd < 0) {
++ if(errno == EEXIST) {
++ fprintf(stderr, "File %s already exists\n", sieve_tmpname);
++ } else if (errno == EACCES) {
++ fprintf(stderr,"No access to create file %s. Please check that you have the correct permissions\n",
++ sieve_tmpname);
++ } else {
++ fprintf(stderr,"Unable to create %s. Please check that you have the correct permissions\n",
++ sieve_tmpname);
++ }
++
++ fclose(in_stream);
++ return 1;
++ }
++
++ if(is_script_parsable(in_stream,&err, &s) == TIMSIEVE_FAIL) {
++ if(err && *err) {
++ fprintf(stderr, "Error while parsing script %s\n",err);
++ free(err);
++ }
++ else
++ fprintf(stderr,"Error while parsing script\n");
++ unlink(sieve_tmpname);
++ fclose(in_stream);
++ close(out_fd);
++ return 1;
++ }
++
++
++ /* generate the bytecode */
++ if(sieve_generate_bytecode(&bc,s) == TIMSIEVE_FAIL) {
++ fprintf(stderr,"Error occured while compiling sieve script\n");
++ /* removing the copied script and cleaning up memory */
++ unlink(sieve_tmpname);
++ sieve_script_free(&s);
++ fclose(in_stream);
++ close(out_fd);
++ return 1;
++ }
++ if(sieve_emit_bytecode(out_fd,bc) == TIMSIEVE_FAIL) {
++ fprintf(stderr, "Error occured while emitting sieve script\n");
++ unlink(sieve_tmpname);
++ sieve_free_bytecode(&bc);
++ sieve_script_free(&s);
++ fclose(in_stream);
++ close(out_fd);
++ return 1;
++ }
++
++ /* clean up the memory */
++ sieve_free_bytecode(&bc);
++ sieve_script_free(&s);
++
++ close(out_fd);
++
++ if(rename(sieve_tmpname, compiled_source_script)) {
++ if(errno != EEXIST) {
++ unlink(sieve_tmpname);
++ unlink(compiled_source_script);
++ return 1;
++ }
++ }
++ return 0;
++}
++
++
++/* to make larry's stupid functions happy :) */
++static void foo(void)
++{
++ fatal("stub function called", 0);
++}
++
++extern sieve_vacation_t vacation2;/* = {
++ 0, / min response /
++ 0, / max response /
++ (sieve_callback *) &foo, / autorespond() /
++ (sieve_callback *) &foo / send_response() /
++}; */
++
++static int sieve_notify(void *ac __attribute__((unused)),
++ void *interp_context __attribute__((unused)),
++ void *script_context __attribute__((unused)),
++ void *message_context __attribute__((unused)),
++ const char **errmsg __attribute__((unused)))
++{
++ fatal("stub function called", 0);
++ return SIEVE_FAIL;
++}
++
++static int mysieve_error(int lineno, const char *msg,
++ void *i __attribute__((unused)), void *s)
++{
++ char buf[1024];
++ char **errstr = (char **) s;
++
++ snprintf(buf, 80, "line %d: %s\r\n", lineno, msg);
++ *errstr = (char *) xrealloc(*errstr, strlen(*errstr) + strlen(buf) + 30);
++ fprintf(stderr, "%s\n", buf);
++ strcat(*errstr, buf);
++
++ return SIEVE_OK;
++}
++
++/* end the boilerplate */
++
++/* returns TRUE or FALSE */
++int is_script_parsable(FILE *stream, char **errstr, sieve_script_t **ret)
++{
++ sieve_interp_t *i;
++ sieve_script_t *s;
++ int res;
++
++ res = sieve_interp_alloc(&i, NULL);
++ if (res != SIEVE_OK) {
++ fprintf(stderr, "sieve_interp_alloc() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ res = sieve_register_redirect(i, (sieve_callback *) &foo);
++ if (res != SIEVE_OK) {
++ fprintf(stderr, "sieve_register_redirect() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++ res = sieve_register_discard(i, (sieve_callback *) &foo);
++ if (res != SIEVE_OK) {
++ fprintf(stderr, "sieve_register_discard() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++ res = sieve_register_reject(i, (sieve_callback *) &foo);
++ if (res != SIEVE_OK) {
++ fprintf(stderr, "sieve_register_reject() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++ res = sieve_register_fileinto(i, (sieve_callback *) &foo);
++ if (res != SIEVE_OK) {
++ fprintf(stderr, "sieve_register_fileinto() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++ res = sieve_register_keep(i, (sieve_callback *) &foo);
++ if (res != SIEVE_OK) {
++ fprintf(stderr, "sieve_register_keep() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ res = sieve_register_imapflags(i, NULL);
++ if (res != SIEVE_OK) {
++ fprintf(stderr, "sieve_register_imapflags() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ res = sieve_register_size(i, (sieve_get_size *) &foo);
++ if (res != SIEVE_OK) {
++ fprintf(stderr, "sieve_register_size() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ res = sieve_register_header(i, (sieve_get_header *) &foo);
++ if (res != SIEVE_OK) {
++ fprintf(stderr, "sieve_register_header() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ res = sieve_register_envelope(i, (sieve_get_envelope *) &foo);
++ if (res != SIEVE_OK) {
++ fprintf(stderr, "sieve_register_envelope() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ res = sieve_register_vacation(i, &vacation2);
++ if (res != SIEVE_OK) {
++ fprintf(stderr, "sieve_register_vacation() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ res = sieve_register_notify(i, &sieve_notify);
++ if (res != SIEVE_OK) {
++ fprintf(stderr, "sieve_register_notify() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ res = sieve_register_parse_error(i, &mysieve_error);
++ if (res != SIEVE_OK) {
++ fprintf(stderr, "sieve_register_parse_error() returns %d\n", res);
++ return TIMSIEVE_FAIL;
++ }
++
++ rewind(stream);
++
++ *errstr = (char *) xmalloc(20 * sizeof(char));
++ strcpy(*errstr, "script errors:\r\n");
++
++ res = sieve_script_parse(i, stream, errstr, &s);
++
++ if (res == SIEVE_OK) {
++ if(ret) {
++ *ret = s;
++ } else {
++ sieve_script_free(&s);
++ }
++ free(*errstr);
++ *errstr = NULL;
++ }
++
++ /* free interpreter */
++ sieve_interp_free(&i);
++
++ return (res == SIEVE_OK) ? TIMSIEVE_OK : TIMSIEVE_FAIL;
++}
++
++
++
++
++
++
+diff -Naur cyrus-imapd-2.4.4.orig/imap/imapd.c cyrus-imapd-2.4.4/imap/imapd.c
+--- cyrus-imapd-2.4.4.orig/imap/imapd.c 2010-11-16 08:48:20.829659918 +0100
++++ cyrus-imapd-2.4.4/imap/imapd.c 2010-11-16 08:48:37.728081052 +0100
+@@ -269,6 +269,7 @@
+ void motd_file(int fd);
+ void shut_down(int code);
+ void fatal(const char *s, int code);
++void autocreate_inbox(void);
+
+ void cmdloop(void);
+ void cmd_login(char *tag, char *user);
+@@ -2102,8 +2103,47 @@
+ mboxname_hiersep_tointernal(&imapd_namespace, imapd_userid,
+ config_virtdomains ?
+ strcspn(imapd_userid, "@") : 0);
++
++ autocreate_inbox();
++}
++
++/*
++ * Autocreate Inbox and subfolders upon login
++ */
++void autocreate_inbox()
++{
++ char inboxname[MAX_MAILBOX_NAME+1];
++ int autocreatequota;
++ int r;
++
++ /*
++ * Exlude admin's accounts
++ */
++ if (imapd_userisadmin || imapd_userisproxyadmin)
++ return;
++
++ /*
++ * Exclude anonymous
++ */
++ if (!strcmp(imapd_userid, "anonymous"))
++ return;
++
++ if ((autocreatequota = config_getint(IMAPOPT_AUTOCREATEQUOTA))) {
++ /* This is actyally not required
++ as long as the lenght of userid is ok */
++ r = (*imapd_namespace.mboxname_tointernal) (&imapd_namespace,
++ "INBOX", imapd_userid, inboxname);
++ if (!r)
++ r = mboxlist_lookup(inboxname, NULL, NULL);
++
++ if (r == IMAP_MAILBOX_NONEXISTENT) {
++ mboxlist_autocreateinbox(&imapd_namespace, imapd_userid,
++ imapd_authstate, inboxname, autocreatequota);
++ }
++ }
+ }
+
++
+ /*
+ * Perform a LOGIN command
+ */
+@@ -5880,6 +5920,8 @@
+ goto freeargs;
+ }
+
++ autocreate_inbox();
++
+ return;
+
+ freeargs:
+diff -Naur cyrus-imapd-2.4.4.orig/imap/lmtpd.c cyrus-imapd-2.4.4/imap/lmtpd.c
+--- cyrus-imapd-2.4.4.orig/imap/lmtpd.c 2010-11-16 08:48:20.824640875 +0100
++++ cyrus-imapd-2.4.4/imap/lmtpd.c 2010-11-16 08:48:37.729084805 +0100
+@@ -119,6 +119,8 @@
+ static FILE *spoolfile(message_data_t *msgdata);
+ static void removespool(message_data_t *msgdata);
+
++static int autocreate_inbox(const char *user, const char *domain);
++
+ /* current namespace */
+ static struct namespace lmtpd_namespace;
+
+@@ -976,6 +978,86 @@
+ exit(code);
+ }
+
++
++/*
++ * Autocreate Inbox and subfolders upon login
++ */
++int autocreate_inbox(const char *user, const char *domain)
++{
++ struct auth_state *auth_state;
++ char inboxname[MAX_MAILBOX_NAME+1];
++ char *rcpt_userid = NULL;
++ int autocreatequota;
++ int r = 0;
++
++ if (user == NULL)
++ return IMAP_MAILBOX_NONEXISTENT;
++
++ if (domain != NULL) {
++ int k;
++
++ rcpt_userid = (char *) xmalloc((strlen(user) + strlen(domain) + 2) * sizeof(char));
++ k = strlcpy(rcpt_userid, user, strlen(user) + 1);
++ *(rcpt_userid + k) = '@';
++ strlcpy(rcpt_userid + k + 1, domain, strlen(domain) + 1);
++ } else {
++ rcpt_userid = (char *) user;
++ }
++
++
++ /*
++ * Exclude anonymous
++ */
++ if (!strcmp(rcpt_userid, "anonymous")) {
++ if (rcpt_userid != user) {
++ free(rcpt_userid);
++ }
++
++ return IMAP_MAILBOX_NONEXISTENT;
++ }
++
++ /*
++ * Check for autocreatequota and createonpost
++ */
++ if (!(autocreatequota = config_getint(IMAPOPT_AUTOCREATEQUOTA)) ||
++ !(config_getswitch(IMAPOPT_CREATEONPOST))) {
++
++ if (rcpt_userid != user) {
++ free(rcpt_userid);
++ }
++
++ return IMAP_MAILBOX_NONEXISTENT;
++ }
++
++
++ /*
++ * Exclude admin's accounts
++ */
++ auth_state = auth_newstate(rcpt_userid);
++
++ if (global_authisa(auth_state, IMAPOPT_ADMINS)) {
++ if (rcpt_userid != user) {
++ free(rcpt_userid);
++ }
++
++ return IMAP_MAILBOX_NONEXISTENT;
++ }
++
++ r = (*lmtpd_namespace.mboxname_tointernal) (&lmtpd_namespace,
++ "INBOX", rcpt_userid, inboxname);
++
++ if (!r)
++ r = mboxlist_autocreateinbox(&lmtpd_namespace, rcpt_userid,
++ auth_state, inboxname, autocreatequota);
++
++ if (rcpt_userid != user) {
++ free(rcpt_userid);
++ }
++
++ return r;
++}
++
++
+ static int verify_user(const char *user, const char *domain, char *mailbox,
+ quota_t quotacheck, struct auth_state *authstate)
+ {
+@@ -1019,6 +1101,15 @@
+ */
+ r = mlookup(namebuf, &server, &acl, NULL);
+
++ /* If user mailbox does not exist, then invoke autocreate inbox function */
++ if (r == IMAP_MAILBOX_NONEXISTENT) {
++ r = autocreate_inbox(user, domain);
++
++ /* Try to locate the mailbox again */
++ if (!r)
++ r = mlookup(namebuf, &server, &acl, NULL);
++ }
++
+ if (r == IMAP_MAILBOX_NONEXISTENT && !user &&
+ config_getswitch(IMAPOPT_LMTP_FUZZY_MAILBOX_MATCH) &&
+ /* see if we have a mailbox whose name is close */
+@@ -1045,6 +1136,7 @@
+ aclcheck, (quotacheck < 0)
+ || config_getswitch(IMAPOPT_LMTP_STRICT_QUOTA) ?
+ quotacheck : 0);
++
+ }
+ }
+
+diff -Naur cyrus-imapd-2.4.4.orig/imap/mboxlist.c cyrus-imapd-2.4.4/imap/mboxlist.c
+--- cyrus-imapd-2.4.4.orig/imap/mboxlist.c 2010-11-16 08:48:20.818616124 +0100
++++ cyrus-imapd-2.4.4/imap/mboxlist.c 2010-11-16 08:48:37.732096343 +0100
+@@ -84,6 +84,12 @@
+ #include "quota.h"
+ #include "sync_log.h"
+
++#ifdef USE_SIEVE
++extern int autoadd_sieve(char *userid,
++ const char *source_script);
++#endif
++
++
+ #define DB config_mboxlist_db
+ #define SUBDB config_subscription_db
+
+@@ -100,6 +106,19 @@
+ void *rock);
+ static int mboxlist_changequota(const char *name, int matchlen, int maycreate,
+ void *rock);
++static int mboxlist_autosubscribe_sharedfolders(struct namespace *namespace,
++ char *userid, char *auth_userid,
++ struct auth_state *auth_state);
++
++/*
++ * Struct needed to be passed as void *rock to
++ * mboxlist_autochangesub();
++ */
++struct changesub_rock_st {
++ char *userid;
++ char *auth_userid;
++ struct auth_state *auth_state;
++};
+
+ char *mboxlist_makeentry(int mbtype, const char *part, const char *acl)
+ {
+@@ -2996,3 +3015,349 @@
+
+ return(count);
+ }
++
++/*
++ * Automatically subscribe user to *ALL* shared folders,
++ * one has permissions to be subscribed to.
++ * INBOX subfolders are excluded.
++ */
++static int mboxlist_autochangesub(char *name, int matchlen, int maycreate,
++ void *rock) {
++
++ struct changesub_rock_st *changesub_rock = (struct changesub_rock_st *) rock;
++ char *userid = changesub_rock->userid;
++ char *auth_userid = changesub_rock->auth_userid;
++ struct auth_state *auth_state = changesub_rock->auth_state;
++ int r;
++
++
++ if((strlen(name) == 5 && !strncmp(name, "INBOX", 5)) || /* Exclude INBOX */
++ (strlen(name) > 5 && !strncmp(name, "INBOX.",6)) || /* Exclude INBOX subfolders */
++ (strlen(name) > 4 && !strncmp(name, "user.", 5))) /* Exclude other users' folders */
++ return 0;
++
++
++ r = mboxlist_changesub(name, userid, auth_state, 1, 0);
++
++ if (r) {
++ syslog(LOG_WARNING,
++ "autosubscribe: User %s to folder %s, subscription failed: %s",
++ auth_userid, name, error_message(r));
++ } else {
++ syslog(LOG_NOTICE,
++ "autosubscribe: User %s to folder %s, subscription succeeded",
++ auth_userid, name);
++ }
++
++ return 0;
++}
++
++#define SEP '|'
++
++/*
++ * Automatically subscribe user to a shared folder.
++ * Subscription is done successfully, if the shared
++ * folder exists and the user has the necessary
++ * permissions.
++ */
++static int mboxlist_autosubscribe_sharedfolders(struct namespace *namespace,
++ char *userid, char *auth_userid,
++ struct auth_state *auth_state) {
++
++ const char *sub ;
++ char *p, *q, *next_sub;
++ char folder[MAX_MAILBOX_NAME+1], name[MAX_MAILBOX_NAME+1], mailboxname[MAX_MAILBOX_NAME+1];
++ int len;
++ int r = 0;
++ int subscribe_all_sharedfolders = 0;
++
++ subscribe_all_sharedfolders = config_getswitch(IMAPOPT_AUTOSUBSCRIBE_ALL_SHAREDFOLDERS);
++
++ /*
++ * If subscribeallsharedfolders is set to yes in imapd.conf, then
++ * subscribe user to every shared folder one has the apropriate
++ * permissions.
++ */
++ if(subscribe_all_sharedfolders) {
++ char pattern[MAX_MAILBOX_PATH+1];
++ struct changesub_rock_st changesub_rock;
++
++ strcpy(pattern, "*");
++ changesub_rock.userid = userid;
++ changesub_rock.auth_userid = auth_userid;
++ changesub_rock.auth_state = auth_state;
++
++ r = mboxlist_findall(namespace, pattern, 0, userid,
++ auth_state, mboxlist_autochangesub, &changesub_rock);
++
++ return r;
++ }
++
++ if ((sub=config_getstring(IMAPOPT_AUTOSUBSCRIBESHAREDFOLDERS)) == NULL)
++ return r;
++
++ next_sub = (char *) sub;
++ while (*next_sub) {
++ for (p = next_sub ; isspace((int) *p) || *p == SEP ; p++);
++ for (next_sub = p ; *next_sub && *next_sub != SEP ; next_sub++);
++ for (q = next_sub ; q > p && (isspace((int) *q) || *q == SEP || !*q) ; q--);
++ if (!*p ) continue;
++
++ len = q - p + 1;
++ /* Check for folder length */
++ if (len > sizeof(folder)-1)
++ continue;
++
++ if (!r) {
++ strncpy(folder, p, len);
++ folder[len] = '\0';
++
++ strlcpy(name, namespace->prefix[NAMESPACE_SHARED], sizeof(name));
++ len = strlcat(name, folder, sizeof(name));
++
++ r = (namespace->mboxname_tointernal) (namespace, name, userid,
++ mailboxname);
++ }
++
++ if (!r)
++ r = mboxlist_changesub(mailboxname, userid, auth_state, 1, 0);
++
++ if (!r) {
++ syslog(LOG_NOTICE, "autosubscribe: User %s to %s succeeded",
++ userid, folder);
++ } else {
++ syslog(LOG_WARNING, "autosubscribe: User %s to %s failed: %s",
++ userid, folder, error_message(r));
++ r = 0;
++ }
++ }
++
++ return r;
++}
++
++
++
++int mboxlist_autocreateinbox(struct namespace *namespace,
++ char *userid,
++ struct auth_state *auth_state,
++ char *mailboxname, int autocreatequota) {
++ char name [MAX_MAILBOX_NAME+1];
++ char folder [MAX_MAILBOX_NAME+1];
++ char *auth_userid = NULL;
++ char *partition = NULL;
++ const char *crt;
++ const char *sub;
++ char *p, *q, *next_crt, *next_sub;
++ int len;
++ int r = 0;
++ int numcrt = 0;
++ int numsub = 0;
++#ifdef USE_SIEVE
++ const char *source_script;
++#endif
++
++
++
++ auth_userid = auth_canonuser(auth_state);
++ if (auth_userid == NULL) {
++ /*
++ * Couldn't get cannon userid
++ */
++ syslog(LOG_ERR,
++ "autocreateinbox: Could not get canonified userid for user %s", userid);
++ return IMAP_PARTITION_UNKNOWN;
++ }
++
++ /* Added this for debug information. */
++ syslog(LOG_DEBUG, "autocreateinbox: autocreate inbox for user %s was called", auth_userid);
++
++ /*
++ * While this is not needed for admins
++ * and imap_admins accounts, it would be
++ * better to separate *all* admins and
++ * proxyservers from normal accounts
++ * (accounts that have mailboxes).
++ * UOA Specific note(1): Even if we do not
++ * exclude these servers-classes here,
++ * UOA specific code, will neither return
++ * role, nor create INBOX, because none of these
++ * administrative accounts belong to the
++ * mailRecipient objectclass, or have imapPartition.
++ * UOA Specific note(2): Another good reason for doing
++ * this, is to prevent the code, from getting into
++ * cyrus_ldap.c because of the continues MSA logins to LMTPd.
++ */
++
++ /*
++ * admins and the coresponding imap
++ * service, had already been excluded.
++ */
++
++ /*
++ * Do we really need group membership
++ * for admins or service_admins?
++ */
++ if (global_authisa(auth_state, IMAPOPT_ADMINS)) return 0;
++
++ /*
++ * Do we really need group membership
++ * for proxyservers?
++ */
++ if (global_authisa(auth_state, IMAPOPT_PROXYSERVERS)) return 0;
++
++ /*
++ * Check if user belongs to the autocreate_users group. This option
++ * controls for whom the mailbox may be automatically created. Default
++ * value for this option is 'anyone'. So, if not declared, all mailboxes
++ * will be created.
++ */
++ if (!global_authisa(auth_state, IMAPOPT_AUTOCREATE_USERS)) {
++ syslog(LOG_DEBUG, "autocreateinbox: User %s does not belong to the autocreate_users. No mailbox is created",
++ auth_userid);
++ return IMAP_MAILBOX_NONEXISTENT;
++ }
++
++#if 0
++ /*
++ * Get Partition info or return.
++ * (Here you should propably use
++ * you own "get_partition(char *userid)"
++ * function. Otherwise all new INBOXes will be
++ * created into whatever partition has been declared
++ * as default in your imapd.conf)
++ */
++
++ partition = get_partition(userid);
++ if (partition == NULL) {
++ /*
++ * Couldn't get partition info
++ */
++ syslog(LOG_ERR,
++ "Could not get imapPartition info for user %s", userid);
++ return IMAP_PARTITION_UNKNOWN;
++ }
++#endif
++
++ r = mboxlist_createmailbox(mailboxname, 0, NULL,
++ 1, userid, auth_state, 0, 0, 0);
++
++ if (!r && autocreatequota > 0)
++ r = mboxlist_setquota(mailboxname, autocreatequota, 0);
++
++ if (!r)
++ r = mboxlist_changesub(mailboxname, userid,
++ auth_state, 1, 1);
++
++ if (!r) {
++ syslog(LOG_NOTICE, "autocreateinbox: User %s, INBOX was successfully created in partition %s",
++ auth_userid, partition == NULL ? "default" : partition);
++ } else {
++ syslog(LOG_ERR, "autocreateinbox: User %s, INBOX failed. %s",
++ auth_userid, error_message(r));
++ }
++
++#if 0
++ /* Allocated from get_partition, and not needed any more */
++ free_partition(partition);
++#endif
++
++ if (r) return r;
++
++ /* INBOX's subfolders */
++ if ((crt=config_getstring(IMAPOPT_AUTOCREATEINBOXFOLDERS)))
++ sub=config_getstring(IMAPOPT_AUTOSUBSCRIBEINBOXFOLDERS);
++
++ /* Roll through crt */
++ next_crt = (char *) crt;
++ while (next_crt!=NULL && *next_crt) {
++ for (p = next_crt ; isspace((int) *p) || *p == SEP ; p++);
++ for (next_crt = p ; *next_crt && *next_crt != SEP ; next_crt++);
++ for (q = next_crt ; q > p && (isspace((int) *q) || *q == SEP || !*q); q--);
++
++ if (!*p) continue;
++
++ len = q - p + 1;
++
++ /* First time we check for length */
++ if (len > sizeof(folder) - 5)
++ r = IMAP_MAILBOX_BADNAME;
++
++ if (!r) {
++ strncpy(folder, p, len);
++ folder[len] = '\0';
++
++ strlcpy(name, namespace->prefix[NAMESPACE_INBOX], sizeof(name));
++ len = strlcat(name, folder, sizeof(name));
++ }
++
++ if (!r)
++ r = (namespace->mboxname_tointernal) (namespace, name, userid,
++ mailboxname);
++ if (!r)
++ r = mboxlist_createmailbox(mailboxname, 0, NULL,
++ 1, userid, auth_state, 0, 0, 0);
++
++ if (!r) {
++ numcrt++;
++ syslog(LOG_NOTICE, "autocreateinbox: User %s, subfolder %s creation succeeded.",
++ auth_userid, name);
++ } else {
++ syslog(LOG_WARNING, "autocreateinbox: User %s, subfolder %s creation failed. %s",
++ auth_userid, name, error_message(r));
++ r=0;
++ continue;
++ }
++
++ /* Roll through sub */
++ next_sub = (char *) sub;
++ while (next_sub!=NULL && *next_sub) {
++ for (p = next_sub ; isspace((int) *p) || *p == SEP ; p++);
++ for (next_sub = p ; *next_sub && *next_sub != SEP ; next_sub++);
++ for (q = next_sub ; q > p && (isspace((int) *q) || *q == SEP || !*q) ; q--);
++ if (!*p ) continue;
++
++ len = q - p + 1;
++
++ if (len != strlen(folder) || strncmp(folder, p, len))
++ continue;
++
++ r = mboxlist_changesub(mailboxname, userid, auth_state, 1, 1);
++
++ if (!r) {
++ numsub++;
++ syslog(LOG_NOTICE,"autocreateinbox: User %s, subscription to %s succeeded",
++ auth_userid, name);
++ } else
++ syslog(LOG_WARNING, "autocreateinbox: User %s, subscription to %s failed. %s",
++ auth_userid, name, error_message(r));
++
++ break;
++ }
++ }
++
++ if (crt!=NULL && *crt)
++ syslog(LOG_INFO, "User %s, Inbox subfolders, created %d, subscribed %d",
++ auth_userid, numcrt, numsub);
++
++ /*
++ * Check if shared folders are available for subscription.
++ */
++ mboxlist_autosubscribe_sharedfolders(namespace, userid, auth_userid, auth_state);
++
++#ifdef USE_SIEVE
++ /*
++ * Here the autocreate sieve script feature is iniated from.
++ */
++ source_script = config_getstring(IMAPOPT_AUTOCREATE_SIEVE_SCRIPT);
++
++ if (source_script) {
++ if (!autoadd_sieve(userid, source_script))
++ syslog(LOG_NOTICE, "autocreate_sieve: User %s, default sieve script creation succeeded", auth_userid);
++ else
++ syslog(LOG_WARNING, "autocreate_sieve: User %s, default sieve script creation failed", auth_userid);
++ }
++#endif
++
++ return r;
++}
++
+diff -Naur cyrus-imapd-2.4.4.orig/imap/mboxlist.h cyrus-imapd-2.4.4/imap/mboxlist.h
+--- cyrus-imapd-2.4.4.orig/imap/mboxlist.h 2010-11-16 08:48:20.828655886 +0100
++++ cyrus-imapd-2.4.4/imap/mboxlist.h 2010-11-16 08:48:37.732096343 +0100
+@@ -221,4 +221,9 @@
+ const char *userid,
+ struct auth_state *authstate);
+
++int mboxlist_autocreateinbox(struct namespace *namespace,char *userid,
++ struct auth_state *auth_state, char *mailboxname,
++ int autocreatequota);
++
++
+ #endif
+diff -Naur cyrus-imapd-2.4.4.orig/imap/pop3d.c cyrus-imapd-2.4.4/imap/pop3d.c
+--- cyrus-imapd-2.4.4.orig/imap/pop3d.c 2010-11-16 08:48:20.820623909 +0100
++++ cyrus-imapd-2.4.4/imap/pop3d.c 2010-11-16 08:48:37.734104407 +0100
+@@ -181,6 +181,8 @@
+ static char popd_apop_chal[45 + MAXHOSTNAMELEN + 1]; /* <rand.time@hostname> */
+ static void cmd_apop(char *response);
+
++static int autocreate_inbox(char *inboxname, char *userid);
++
+ static void cmd_auth(char *arg);
+ static void cmd_capa(void);
+ static void cmd_pass(char *pass);
+@@ -1389,6 +1391,7 @@
+ popd_userid = xstrdup(userbuf);
+ prot_printf(popd_out, "+OK Name is a valid mailbox\r\n");
+ }
++
+ }
+
+ void cmd_pass(char *pass)
+@@ -1692,6 +1695,43 @@
+ }
+
+ /*
++ * Autocreate Inbox and subfolders upon login
++ */
++int autocreate_inbox(char *inboxname, char *auth_userid)
++{
++ struct auth_state *auth_state;
++ int autocreatequota;
++ int r;
++
++ if (inboxname == NULL || auth_userid == NULL)
++ return IMAP_MAILBOX_NONEXISTENT;
++
++ /*
++ * Exclude anonymous
++ */
++ if (!strcmp(popd_userid, "anonymous"))
++ return IMAP_MAILBOX_NONEXISTENT;
++
++ /*
++ * Check for autocreatequota
++ */
++ if (!(autocreatequota = config_getint(IMAPOPT_AUTOCREATEQUOTA)))
++ return IMAP_MAILBOX_NONEXISTENT;
++
++ /*
++ * Exclude admin's accounts
++ */
++ auth_state = auth_newstate(popd_userid);
++ if (global_authisa(auth_state, IMAPOPT_ADMINS))
++ return IMAP_MAILBOX_NONEXISTENT;
++
++ r = mboxlist_autocreateinbox(&popd_namespace, auth_userid,
++ auth_state, inboxname, autocreatequota);
++ return r;
++}
++
++
++/*
+ * Complete the login process by opening and locking the user's inbox
+ */
+ int openinbox(void)
+@@ -1720,6 +1760,12 @@
+ userid, inboxname);
+
+ if (!r) r = mboxlist_lookup(inboxname, &mbentry, NULL);
++
++ /* Try once again after autocreate_inbox */
++ if (r == IMAP_MAILBOX_NONEXISTENT &&
++ !(r = autocreate_inbox(inboxname, userid)))
++ r = mboxlist_lookup(inboxname, &mbentry, NULL);
++
+ if (!r && (config_popuseacl = config_getswitch(IMAPOPT_POPUSEACL)) &&
+ (!mbentry.acl ||
+ !((myrights = cyrus_acl_myrights(popd_authstate, mbentry.acl)) & ACL_READ))) {
+diff -Naur cyrus-imapd-2.4.4.orig/lib/auth.c cyrus-imapd-2.4.4/lib/auth.c
+--- cyrus-imapd-2.4.4.orig/lib/auth.c 2010-11-16 08:48:20.875850421 +0100
++++ cyrus-imapd-2.4.4/lib/auth.c 2010-11-16 08:48:37.755228749 +0100
+@@ -118,3 +118,11 @@
+
+ auth->freestate(auth_state);
+ }
++
++char *auth_canonuser(struct auth_state *auth_state)
++{
++ struct auth_mech *auth = auth_fromname();
++
++ return auth->auth_canonuser(auth_state);
++}
++
+diff -Naur cyrus-imapd-2.4.4.orig/lib/auth.h cyrus-imapd-2.4.4/lib/auth.h
+--- cyrus-imapd-2.4.4.orig/lib/auth.h 2010-11-16 08:48:20.881874054 +0100
++++ cyrus-imapd-2.4.4/lib/auth.h 2010-11-16 08:48:37.755228749 +0100
+@@ -55,6 +55,7 @@
+ const char *identifier);
+ struct auth_state *(*newstate)(const char *identifier);
+ void (*freestate)(struct auth_state *auth_state);
++ char *(*auth_canonuser)(struct auth_state *auth_state);
+ };
+
+ extern struct auth_mech *auth_mechs[];
+@@ -77,5 +78,6 @@
+ const char *identifier);
+ struct auth_state *auth_newstate(const char *identifier);
+ void auth_freestate(struct auth_state *auth_state);
++char *auth_canonuser(struct auth_state *auth_state);
+
+ #endif /* INCLUDED_AUTH_H */
+diff -Naur cyrus-imapd-2.4.4.orig/lib/auth_krb.c cyrus-imapd-2.4.4/lib/auth_krb.c
+--- cyrus-imapd-2.4.4.orig/lib/auth_krb.c 2010-11-16 08:48:20.885889903 +0100
++++ cyrus-imapd-2.4.4/lib/auth_krb.c 2010-11-16 08:48:37.756232781 +0100
+@@ -341,6 +341,15 @@
+ free((char *)auth_state);
+ }
+
++static char *mycanonuser(struct auth_state *auth_state)
++{
++ if (auth_state)
++ return auth_state->userid;
++
++ return NULL;
++}
++
++
+ #else /* HAVE_KRB */
+
+ static int mymemberof(
+@@ -372,6 +381,13 @@
+ fatal("Authentication mechanism (krb) not compiled in", EC_CONFIG);
+ }
+
++static char *mycanonuser(
++ struct auth_state *auth_state __attribute__((unused)))
++{
++ fatal("Authentication mechanism (krb) not compiled in", EC_CONFIG);
++}
++
++
+ #endif
+
+ struct auth_mech auth_krb =
+@@ -382,4 +398,5 @@
+ &mymemberof,
+ &mynewstate,
+ &myfreestate,
++ &mycanonuser,
+ };
+diff -Naur cyrus-imapd-2.4.4.orig/lib/auth_krb5.c cyrus-imapd-2.4.4/lib/auth_krb5.c
+--- cyrus-imapd-2.4.4.orig/lib/auth_krb5.c 2010-11-16 08:48:20.877858205 +0100
++++ cyrus-imapd-2.4.4/lib/auth_krb5.c 2010-11-16 08:48:37.756232781 +0100
+@@ -199,6 +199,14 @@
+ free(auth_state);
+ }
+
++static char *mycanonuser(struct auth_state *auth_state)
++{
++ if (auth_state)
++ return auth_state->userid;
++
++ return NULL;
++}
++
+ #else /* HAVE_GSSAPI_H */
+
+ static int mymemberof(
+@@ -230,6 +238,13 @@
+ fatal("Authentication mechanism (krb5) not compiled in", EC_CONFIG);
+ }
+
++static char *mycanonuser(
++ struct auth_state *auth_state __attribute__((unused)))
++{
++ fatal("Authentication mechanism (krb5) not compiled in", EC_CONFIG);
++ return NULL;
++}
++
+ #endif
+
+ struct auth_mech auth_krb5 =
+@@ -240,4 +255,5 @@
+ &mymemberof,
+ &mynewstate,
+ &myfreestate,
++ &mycanonuser,
+ };
+diff -Naur cyrus-imapd-2.4.4.orig/lib/auth_pts.c cyrus-imapd-2.4.4/lib/auth_pts.c
+--- cyrus-imapd-2.4.4.orig/lib/auth_pts.c 2010-11-16 08:48:20.877858205 +0100
++++ cyrus-imapd-2.4.4/lib/auth_pts.c 2010-11-16 08:48:37.757236534 +0100
+@@ -512,6 +512,14 @@
+ free(auth_state);
+ }
+
++static char *mycanonuser(struct auth_state *auth_state)
++{
++ if (auth_state)
++ return auth_state->userid.id;
++
++ return NULL;
++}
++
+ struct auth_mech auth_pts =
+ {
+ "pts", /* name */
+@@ -520,4 +528,5 @@
+ &mymemberof,
+ &mynewstate,
+ &myfreestate,
++ &mycanonuser,
+ };
+diff -Naur cyrus-imapd-2.4.4.orig/lib/auth_unix.c cyrus-imapd-2.4.4/lib/auth_unix.c
+--- cyrus-imapd-2.4.4.orig/lib/auth_unix.c 2010-11-16 08:48:20.880870301 +0100
++++ cyrus-imapd-2.4.4/lib/auth_unix.c 2010-11-16 08:48:37.757236534 +0100
+@@ -315,6 +315,16 @@
+ free((char *)auth_state);
+ }
+
++static char *mycanonuser(auth_state)
++ struct auth_state *auth_state;
++{
++ if (auth_state)
++ return auth_state->userid;
++
++ return NULL;
++}
++
++
+
+ struct auth_mech auth_unix =
+ {
+@@ -324,4 +334,5 @@
+ &mymemberof,
+ &mynewstate,
+ &myfreestate,
++ &mycanonuser,
+ };
+diff -Naur cyrus-imapd-2.4.4.orig/lib/imapoptions cyrus-imapd-2.4.4/lib/imapoptions
+--- cyrus-imapd-2.4.4.orig/lib/imapoptions 2010-11-16 08:48:20.878862238 +0100
++++ cyrus-imapd-2.4.4/lib/imapoptions 2010-11-16 08:48:37.759244877 +0100
+@@ -245,6 +245,55 @@
+ /* Time in seconds. Any imap command that takes longer than this
+ time is logged. */
+
++{ "createonpost", 0, SWITCH }
++/* If yes, when lmtpd receives an incoming mail for an INBOX that does not exist,
++ then the INBOX is automatically created by lmtpd. */
++
++{ "autocreateinboxfolders", NULL, STRING }
++/* If a user does not have an INBOX created then the INBOX as well as some INBOX
++ subfolders are created under two conditions.
++ 1. The user logins via the IMAP or the POP3 protocol. (autocreatequota option must have a nonzero value)
++ 2. A message arrives for the user through the LMTPD protocol.(createonpost option must be yes)
++ autocreateinboxfolders is a list of INBOX's subfolders separated by a "|", that
++ are automatically created by the server under the previous two situations. */
++
++{ "autosubscribeinboxfolders", NULL, STRING }
++/* A list of folder names, separated by "|", that the users get automatically subscribed to,
++ when their INBOX is created. These folder names must have been included in the
++ autocreateinboxfolders option of the imapd.conf. */
++
++{ "autosubscribesharedfolders", NULL, STRING }
++/* A list of shared folders (bulletin boards), separated by "|", that the users get
++ automatically subscribed to, after their INBOX is created. The shared folder must
++ have been created and the user must have the required permissions to get subscribed
++ to it. Otherwise, subscribing to the shared folder fails. */
++
++{ "autosubscribe_all_sharedfolders", 0, SWITCH }
++/* If set to yes, the user is automatically subscribed to all shared folders, one has permission
++ to subscribe to. */
++
++{ "autocreate_sieve_script", NULL, STRING }
++/* The full path of a file that contains a sieve script. This script automatically becomes a
++ user's initial default sieve filter script. When this option is not defined, no default
++ sieve filter is created. The file must be readable by the cyrus daemon. */
++
++{ "autocreate_sieve_compiledscript", NULL, STRING }
++/* The full path of a file that contains a compiled in bytecode sieve script. This script
++ automatically becomes a user's initial default sieve filter script. If this option is
++ not specified, or the filename doesn't exist then the script defined by
++ autocreate_sieve_script is compiled on the fly and installed as the user's default
++ sieve script */
++
++{ "generate_compiled_sieve_script", 0, SWITCH }
++/* If set to yes and no compiled sieve script file exists, the sieve script which is
++ compiled on the fly will be saved in the file name that autocreate_sieve_compiledscript
++ option points to. In order a compiled script to be generated, autocreate_sieve_script and
++ autocreate_sieve_compiledscript must have valid values */
++
++{ "autocreate_users", "anyone", STRING }
++/* A space separated list of users and/or groups that are allowed their INBOX to be
++ automatically created. */
++
+ { "configdirectory", NULL, STRING }
+ /* The pathname of the IMAP configuration directory. This field is
+ required. */
+diff -Naur cyrus-imapd-2.4.4.orig/notifyd/Makefile.in cyrus-imapd-2.4.4/notifyd/Makefile.in
+--- cyrus-imapd-2.4.4.orig/notifyd/Makefile.in 2010-11-16 08:48:20.897937729 +0100
++++ cyrus-imapd-2.4.4/notifyd/Makefile.in 2010-11-16 08:48:37.769295255 +0100
+@@ -71,10 +71,11 @@
+ SERVICE=../master/service.o
+
+ IMAP_LIBS = @IMAP_LIBS@ @LIB_RT@
++SIEVE_LIBS = @SIEVE_LIBS@
+ IMAP_COM_ERR_LIBS = @IMAP_COM_ERR_LIBS@
+ LIB_WRAP = @LIB_WRAP@
+ LIBS = @ZEPHYR_LIBS@ @LIBS@ $(IMAP_COM_ERR_LIBS)
+-DEPLIBS=../imap/mutex_fake.o ../imap/libimap.a ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
++DEPLIBS=../imap/mutex_fake.o ../imap/libimap.a $(SIEVE_LIBS) ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
+
+ PURIFY=/usr/local/bin/purify
+ PUREOPT=-best-effort
+diff -Naur cyrus-imapd-2.4.4.orig/notifyd/notifyd.c cyrus-imapd-2.4.4/notifyd/notifyd.c
+--- cyrus-imapd-2.4.4.orig/notifyd/notifyd.c 2010-11-16 08:48:20.897937729 +0100
++++ cyrus-imapd-2.4.4/notifyd/notifyd.c 2010-11-16 08:48:37.770300684 +0100
+@@ -98,7 +98,7 @@
+
+ #define NOTIFY_MAXSIZE 8192
+
+-int do_notify()
++static int do_notify()
+ {
+ struct sockaddr_un sun_data;
+ socklen_t sunlen = sizeof(sun_data);
+diff -Naur cyrus-imapd-2.4.4.orig/ptclient/Makefile.in cyrus-imapd-2.4.4/ptclient/Makefile.in
+--- cyrus-imapd-2.4.4.orig/ptclient/Makefile.in 2010-11-16 08:48:20.800544944 +0100
++++ cyrus-imapd-2.4.4/ptclient/Makefile.in 2010-11-16 08:48:37.770300684 +0100
+@@ -57,10 +57,11 @@
+ AFS_LDFLAGS = @AFS_LDFLAGS@ @COM_ERR_LDFLAGS@
+ AFS_LIBS = @AFS_LIBS@
+ IMAP_LIBS = @IMAP_LIBS@ @LIB_RT@
++SIEVE_LIBS = @SIEVE_LIBS@
+ LIBS = $(IMAP_LIBS) @COM_ERR_LIBS@
+ LIB_SASL = @LIB_SASL@
+ LIB_WRAP = @LIB_WRAP@
+-DEPLIBS = ../imap/libimap.a ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
++DEPLIBS = ../imap/libimap.a $(SIEVE_LIBS) ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
+ UTIL_LIBS = ../imap/mutex_fake.o ../imap/cli_fatal.o
+
+ LDAP_LIBS=@LDAP_LIBS@
diff --git a/network/cyrus-imapd/patches/cyrus-imapd-2.4.4-autosieve-0.6.0.patch b/network/cyrus-imapd/patches/cyrus-imapd-2.4.4-autosieve-0.6.0.patch
new file mode 100644
index 0000000000..dee2af3f42
--- /dev/null
+++ b/network/cyrus-imapd/patches/cyrus-imapd-2.4.4-autosieve-0.6.0.patch
@@ -0,0 +1,182 @@
+diff -Naur cyrus-imapd-2.4.4.orig/README.autosievefolder cyrus-imapd-2.4.4/README.autosievefolder
+--- cyrus-imapd-2.4.4.orig/README.autosievefolder 1970-01-01 01:00:00.000000000 +0100
++++ cyrus-imapd-2.4.4/README.autosievefolder 2010-11-15 10:40:56.299163485 +0100
+@@ -0,0 +1,43 @@
++Cyrus IMAP autosievefolder patch
++----------------------------------
++
++NOTE : This patch has been created at the University of Athens. For more info, as well
++as more patches on Cyrus IMAPD server, please visit http://email.uoa.gr
++
++NOTE : Patch updated to Cyrus IMAPD 2.4.x by Martin Matuska <mm@FreeBSD.org>
++
++ When the lmtpd daemon receives an email message prior to delivering it to the
++INBOX folder of the user, checks if the user has specified sieve filters. If the
++user has specified sieve filters the filters are evaluated. If the message matches
++any of the filters the action that is specified in the filter is executed. If the action
++is FileInto it is stored in the subfolder specified in the filter. If the
++subfolder doesn't exist then the message is sent to the INBOX folder of the user.
++
++ With this patch if the folder doesn't exist AND the name of the subfolder is
++specified in the autosievefolders option, OR the anysievefolder is set to
++yes in the cyrus-imap configuration file then the subfolder is created and the mail
++is stored there.
++
++
++Check the following options of the imapd.conf file
++==================================================
++
++* anysievefolder : It must be "yes" in order to permit the autocreation of any
++INBOX subfolder requested by a sieve filter, through the "fileinto" action. (default = no)
++* autosievefolders : It is a "|" separated list of subfolders of INBOX that will be
++automatically created, if requested by a sieve filter, through the "fileinto"
++action. (default = null)
++ i.e. autosievefolders: Junk | Spam
++
++WARNING: anysievefolder, takes precedence over autosievefolders . Which means that if
++anysievefolder is set to "yes", cyrus will create any INBOX subfolder requested, no-matter what the value of autosievefolders is.
++
++
++Things to be done
++=================
++
++1. Support cyrus wildcards in the autosievefolders option.
++
++
++For more information and updates please visit http://email.uoa.gr/projects/cyrus/autosievefolder
++
+diff -Naur cyrus-imapd-2.4.4.orig/imap/lmtp_sieve.c cyrus-imapd-2.4.4/imap/lmtp_sieve.c
+--- cyrus-imapd-2.4.4.orig/imap/lmtp_sieve.c 2010-11-11 23:15:33.000000000 +0100
++++ cyrus-imapd-2.4.4/imap/lmtp_sieve.c 2010-11-15 10:40:13.127210740 +0100
+@@ -88,6 +88,9 @@
+ struct auth_state *authstate;
+ } script_data_t;
+
++static int autosieve_subfolder(char *userid, struct auth_state *auth_state,
++ char *subfolder, struct namespace *namespace);
++
+ static char *make_sieve_db(const char *user)
+ {
+ static char buf[MAX_MAILBOX_PATH+1];
+@@ -496,7 +499,20 @@
+ sd->username, mdata->notifyheader,
+ namebuf, quotaoverride, 0);
+ }
+-
++
++ if (ret == IMAP_MAILBOX_NONEXISTENT) {
++ /* if "plus" folder under INBOX, then try to create it */
++ ret = autosieve_subfolder((char *) sd->username, sd->authstate, namebuf, mdata->namespace);
++
++ /* Try to deliver the mail again. */
++ if (!ret)
++ ret = deliver_mailbox(md->f, mdata->content, mdata->stage, md->size,
++ fc->imapflags->flag, fc->imapflags->nflags,
++ (char *) sd->username, sd->authstate, md->id,
++ sd->username, mdata->notifyheader,
++ namebuf, quotaoverride, 0);
++ }
++
+ if (!ret) {
+ snmp_increment(SIEVE_FILEINTO, 1);
+ return SIEVE_OK;
+@@ -947,3 +963,80 @@
+ we'll do normal delivery */
+ return r;
+ }
++
++
++#define SEP '|'
++
++static int autosieve_subfolder(char *userid, struct auth_state *auth_state,
++ char *subfolder, struct namespace *namespace)
++{
++ char option_name_external[MAX_MAILBOX_NAME + 1];
++ char option_name_internal[MAX_MAILBOX_NAME + 1];
++ const char *subf ;
++ char *p, *q, *next_subf;
++ int len, r = 0;
++ int createsievefolder = 0;
++
++ /* Check if subfolder or userid are NULL */
++ if(userid == NULL || subfolder == NULL)
++ return IMAP_MAILBOX_NONEXISTENT;
++
++ syslog(LOG_DEBUG, "autosievefolder: autosieve_subfolder() was called for user %s, folder %s",
++ userid, subfolder);
++
++ if (config_getswitch(IMAPOPT_ANYSIEVEFOLDER)) {
++ createsievefolder = 1;
++ } else if ((subf = config_getstring(IMAPOPT_AUTOSIEVEFOLDERS)) != NULL) {
++ /* Roll through subf */
++ next_subf = (char *) subf;
++ while (*next_subf) {
++ for (p = next_subf ; isspace((int) *p) || *p == SEP ; p++);
++ for (next_subf = p ; *next_subf && *next_subf != SEP ; next_subf++);
++ for (q = next_subf ; q > p && (isspace((int) *q) || *q == SEP || !*q); q--);
++
++ if (!*p) continue;
++
++ len = q - p + 1;
++ /*
++ * This is a preliminary length check based on the assumption
++ * that the *final* internal format will be something
++ * like user.userid.subfolder(s).
++ */
++ if (len > sizeof(option_name_external) - strlen(userid) - 5)
++ return IMAP_MAILBOX_BADNAME;
++
++ strlcpy(option_name_external, namespace->prefix[NAMESPACE_INBOX], sizeof(option_name_external));
++ strncat(option_name_external, p, len);
++
++ /*
++ * Transform the option folder name to internal namespace and compare it
++ * with what must be created.
++ */
++ r = namespace->mboxname_tointernal(namespace, option_name_external, userid, option_name_internal);
++ if (r) continue;
++
++ if (!strcmp(option_name_internal, subfolder)) {
++ createsievefolder = 1;
++ break;
++ }
++ }
++ }
++
++ if (createsievefolder) {
++ /* Folder is already in internal namespace format */
++ r = mboxlist_createmailbox(subfolder, 0, NULL,
++ 1, userid, auth_state, 0, 0, 0);
++ if (!r) {
++ mboxlist_changesub(subfolder, userid, auth_state, 1, 1);
++ syslog(LOG_DEBUG, "autosievefolder: User %s, folder %s creation succeeded",
++ userid, subfolder);
++ return 0;
++ } else {
++ syslog(LOG_ERR, "autosievefolder: User %s, folder %s creation failed. %s",
++ userid, subfolder,error_message(r));
++ return r;
++ }
++ } else
++ return IMAP_MAILBOX_NONEXISTENT;
++}
++
+diff -Naur cyrus-imapd-2.4.4.orig/lib/imapoptions cyrus-imapd-2.4.4/lib/imapoptions
+--- cyrus-imapd-2.4.4.orig/lib/imapoptions 2010-11-11 23:15:33.000000000 +0100
++++ cyrus-imapd-2.4.4/lib/imapoptions 2010-11-15 10:40:13.129220481 +0100
+@@ -1096,6 +1096,15 @@
+ /* If enabled, lmtpd will look for Sieve scripts in user's home
+ directories: ~user/.sieve. */
+
++{ "anysievefolder", 0, SWITCH }
++/* It must be "yes" in order to permit the autocreation of any INBOX subfolder
++ requested by a sieve filter, through the "fileinto" action. (default = no) */
++
++{ "autosievefolders", NULL, STRING }
++/* It is a "|" separated list of subfolders of INBOX that will be automatically created,
++ if requested by a sieve filter, through the "fileinto" action. (default = null)
++ i.e. autosievefolders: Junk | Spam */
++
+ { "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