summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCHTEKK <CHTEKK@localhost>2007-04-13 19:03:53 +0000
committerCHTEKK <CHTEKK@localhost>2007-04-13 19:03:53 +0000
commit1f85a790113804088f9cf0c0b03287d8b14c9fd2 (patch)
tree86b45138ebe48176031d575d9ec5fc9acecf95ab
parentCharset UTF-8 is what we want. (diff)
downloadchtekk-1f85a790113804088f9cf0c0b03287d8b14c9fd2.tar.gz
chtekk-1f85a790113804088f9cf0c0b03287d8b14c9fd2.tar.bz2
chtekk-1f85a790113804088f9cf0c0b03287d8b14c9fd2.zip
First version.
svn path=/; revision=27
-rw-r--r--vda/postfix-2.4.0-vda-e-chtekk.patch1010
1 files changed, 1010 insertions, 0 deletions
diff --git a/vda/postfix-2.4.0-vda-e-chtekk.patch b/vda/postfix-2.4.0-vda-e-chtekk.patch
new file mode 100644
index 0000000..0575f22
--- /dev/null
+++ b/vda/postfix-2.4.0-vda-e-chtekk.patch
@@ -0,0 +1,1010 @@
+diff -Nru postfix-2.4.0/README_FILES/VDA_README postfix-2.4.0-vda/README_FILES/VDA_README
+--- postfix-2.4.0/README_FILES/VDA_README 1970-01-01 01:00:00.000000000 +0100
++++ postfix-2.4.0-vda/README_FILES/VDA_README 2007-04-13 19:05:33.000000000 +0200
+@@ -0,0 +1,9 @@
++Installation:
++
++1 - Get the Postfix source code (http://www.postfix.org/)
++2 - Get this software (http://vda.sourceforge.net/) for your Postfix version
++3 - Unpack the source code: tar -xvzf postfix-VERSION.tar.gz
++4 - Unpack the patch: gunzip postfix-VERSION-vda.patch.gz
++5 - Apply the patch: cd postfix-VERSION; patch -p1 < ../postfix-VERSION-vda.patch
++6 - Apply your configuration in the Makefile
++7 - Make
+diff -Nru postfix-2.4.0/src/global/mail_params.h postfix-2.4.0-vda/src/global/mail_params.h
+--- postfix-2.4.0/src/global/mail_params.h 2007-02-25 03:15:42.000000000 +0100
++++ postfix-2.4.0-vda/src/global/mail_params.h 2007-04-13 19:05:33.000000000 +0200
+@@ -2099,6 +2099,54 @@
+ #define DEF_VIRT_GID_MAPS ""
+ extern char *var_virt_gid_maps;
+
++#define VAR_VIRT_MAILBOX_LIMIT_MAPS "virtual_mailbox_limit_maps"
++#define DEF_VIRT_MAILBOX_LIMIT_MAPS ""
++extern char *var_virt_mailbox_limit_maps;
++
++#define VAR_VIRT_MAILBOX_LIMIT_INBOX "virtual_mailbox_limit_inbox"
++#define DEF_VIRT_MAILBOX_LIMIT_INBOX 0
++extern bool var_virt_mailbox_limit_inbox;
++
++#define VAR_VIRT_MAILBOX_LIMIT_OVERRIDE "virtual_mailbox_limit_override"
++#define DEF_VIRT_MAILBOX_LIMIT_OVERRIDE 0
++extern bool var_virt_mailbox_limit_override;
++
++#define VAR_VIRT_MAILDIR_EXTENDED "virtual_maildir_extended"
++#define DEF_VIRT_MAILDIR_EXTENDED 0
++extern bool var_virt_maildir_extended;
++
++#define VAR_VIRT_CREATE_MAILDIRSIZE "virtual_create_maildirsize"
++#define DEF_VIRT_CREATE_MAILDIRSIZE 0
++extern bool var_virt_create_maildirsize;
++
++#define VAR_VIRT_OVERQUOTA_BOUNCE "virtual_overquota_bounce"
++#define DEF_VIRT_OVERQUOTA_BOUNCE 0
++extern bool var_virt_overquota_bounce;
++
++#define VAR_VIRT_MAILDIR_LIMIT_MESSAGE "virtual_maildir_limit_message"
++#define DEF_VIRT_MAILDIR_LIMIT_MESSAGE "Sorry, the user's maildir has overdrawn his diskspace quota, please try again later."
++extern char *var_virt_maildir_limit_message;
++
++#define VAR_VIRT_MAILDIR_SUFFIX "virtual_maildir_suffix"
++#define DEF_VIRT_MAILDIR_SUFFIX ""
++extern char *var_virt_maildir_suffix;
++
++#define VAR_VIRT_TRASH_COUNT "virtual_trash_count"
++#define DEF_VIRT_TRASH_COUNT 0
++extern bool var_virt_trash_count;
++
++#define VAR_VIRT_TRASH_NAME "virtual_trash_name"
++#define DEF_VIRT_TRASH_NAME ".Trash"
++extern char *var_virt_trash_name;
++
++#define VAR_VIRT_MAILDIR_FILTER "virtual_maildir_filter"
++#define DEF_VIRT_MAILDIR_FILTER 0
++extern bool var_virt_maildir_filter;
++
++#define VAR_VIRT_MAILDIR_FILTER_MAPS "virtual_maildir_filter_maps"
++#define DEF_VIRT_MAILDIR_FILTER_MAPS ""
++extern char *var_virt_maildir_filter_maps;
++
+ #define VAR_VIRT_MINUID "virtual_minimum_uid"
+ #define DEF_VIRT_MINUID 100
+ extern int var_virt_minimum_uid;
+diff -Nru postfix-2.4.0/src/util/file_limit.c postfix-2.4.0-vda/src/util/file_limit.c
+--- postfix-2.4.0/src/util/file_limit.c 2003-10-22 20:48:36.000000000 +0200
++++ postfix-2.4.0-vda/src/util/file_limit.c 2007-04-13 19:05:33.000000000 +0200
+@@ -85,7 +85,11 @@
+ #else
+ struct rlimit rlim;
+
+- rlim.rlim_cur = rlim.rlim_max = limit;
++ /* rlim_max can be changed only by root */
++ if (getrlimit(RLIMIT_FSIZE, &rlim) < 0)
++ msg_fatal("getrlimit: %m");
++ rlim.rlim_cur = limit;
++
+ if (setrlimit(RLIMIT_FSIZE, &rlim) < 0)
+ msg_fatal("setrlimit: %m");
+ #ifdef SIGXFSZ
+diff -Nru postfix-2.4.0/src/virtual/mailbox.c postfix-2.4.0-vda/src/virtual/mailbox.c
+--- postfix-2.4.0/src/virtual/mailbox.c 2006-06-26 14:59:19.000000000 +0200
++++ postfix-2.4.0-vda/src/virtual/mailbox.c 2007-04-13 19:16:29.000000000 +0200
+@@ -70,6 +70,58 @@
+ #define YES 1
+ #define NO 0
+
++/* change_mailbox_limit - change limit for mailbox file */
++static int change_mailbox_limit(LOCAL_STATE state, USER_ATTR usr_attr)
++{
++ char *myname = "change_mailbox_limit";
++ const char *limit_res;
++ long n;
++ int status = NO;
++
++ /*
++ * Look up the virtual mailbox limit size for this user. Fall back to virtual_mailbox_limit in
++ * case lookup failed. If virtual mailbox limit size is 0 or less, fall back to virtual_mailbox_limit.
++ * If it's more than 0 (positive int), check if the value is smaller than the maximum message size,
++ * if it is and the virtual mailbox limit can't be overridden, fall back to virtual_mailbox_limit and
++ * warn the user, else use the value directly as the mailbox limit.
++ */
++ if ((limit_res = mail_addr_find(virtual_mailbox_limit_maps, state.msg_attr.user, (char **) NULL))) {
++ n = atol(limit_res);
++ if (n > 0) {
++ if ((n < var_message_limit) && (!var_virt_mailbox_limit_override)) {
++ set_file_limit(var_virt_mailbox_limit);
++ status = NO;
++
++ msg_warn("%s: recipient %s - virtual mailbox limit is "
++ "smaller than %s in %s - falling back to %s",
++ myname,
++ state.msg_attr.user,
++ VAR_MESSAGE_LIMIT,
++ virtual_mailbox_limit_maps->title,
++ VAR_VIRT_MAILBOX_LIMIT);
++ }
++ else {
++ set_file_limit((off_t)n);
++ status = YES;
++
++ if (msg_verbose)
++ msg_info("%s: set virtual mailbox limit size for %s to %ld",
++ myname, usr_attr.mailbox, n);
++ }
++ }
++ else {
++ set_file_limit(var_virt_mailbox_limit);
++ status = NO;
++ }
++ }
++ else {
++ set_file_limit(var_virt_mailbox_limit);
++ status = NO;
++ }
++
++ return(status);
++}
++
+ /* deliver_mailbox_file - deliver to recipient mailbox */
+
+ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
+@@ -207,52 +259,54 @@
+ * Look up the mailbox owner rights. Defer in case of trouble.
+ */
+ uid_res = mail_addr_find(virtual_uid_maps, state.msg_attr.user,
+- IGNORE_EXTENSION);
+- if (uid_res == 0) {
+- msg_warn("recipient %s: not found in %s",
+- state.msg_attr.user, virtual_uid_maps->title);
+- dsb_simple(why, "4.3.5", "mail system configuration error");
+- *statusp = defer_append(BOUNCE_FLAGS(state.request),
+- BOUNCE_ATTR(state.msg_attr));
+- RETURN(YES);
++ IGNORE_EXTENSION);
++
++ if ((uid_res = mail_addr_find(virtual_uid_maps, state.msg_attr.user, (char **) 0)) == 0) {
++ if ((uid_res = maps_find(virtual_uid_maps, strchr(state.msg_attr.user, '@'), DICT_FLAG_FIXED)) == 0) {
++ msg_warn("recipient %s: not found in %s", state.msg_attr.user, virtual_uid_maps->title);
++ dsb_simple(why, "4.3.5", "mail system configuration error");
++ *statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr));
++ RETURN(YES);
++ }
+ }
++
+ if ((n = atol(uid_res)) < var_virt_minimum_uid) {
+- msg_warn("recipient %s: bad uid %s in %s",
+- state.msg_attr.user, uid_res, virtual_uid_maps->title);
+- dsb_simple(why, "4.3.5", "mail system configuration error");
+- *statusp = defer_append(BOUNCE_FLAGS(state.request),
+- BOUNCE_ATTR(state.msg_attr));
+- RETURN(YES);
++ msg_warn("recipient %s: bad uid %s in %s", state.msg_attr.user, uid_res, virtual_uid_maps->title);
++ dsb_simple(why, "4.3.5", "mail system configuration error");
++ *statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr));
++ RETURN(YES);
+ }
++
+ usr_attr.uid = (uid_t) n;
+
+ /*
+ * Look up the mailbox group rights. Defer in case of trouble.
+ */
+ gid_res = mail_addr_find(virtual_gid_maps, state.msg_attr.user,
+- IGNORE_EXTENSION);
+- if (gid_res == 0) {
+- msg_warn("recipient %s: not found in %s",
+- state.msg_attr.user, virtual_gid_maps->title);
+- dsb_simple(why, "4.3.5", "mail system configuration error");
+- *statusp = defer_append(BOUNCE_FLAGS(state.request),
+- BOUNCE_ATTR(state.msg_attr));
+- RETURN(YES);
++ IGNORE_EXTENSION);
++
++ if ((gid_res = mail_addr_find(virtual_gid_maps, state.msg_attr.user, (char **) 0)) == 0) {
++ if ((gid_res = maps_find(virtual_gid_maps, strchr(state.msg_attr.user, '@'), DICT_FLAG_FIXED)) == 0) {
++ msg_warn("recipient %s: not found in %s", state.msg_attr.user, virtual_gid_maps->title);
++ dsb_simple(why, "4.3.5", "mail system configuration error");
++ *statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr));
++ RETURN(YES);
++ }
+ }
++
+ if ((n = atol(gid_res)) <= 0) {
+- msg_warn("recipient %s: bad gid %s in %s",
+- state.msg_attr.user, gid_res, virtual_gid_maps->title);
+- dsb_simple(why, "4.3.5", "mail system configuration error");
+- *statusp = defer_append(BOUNCE_FLAGS(state.request),
+- BOUNCE_ATTR(state.msg_attr));
+- RETURN(YES);
++ msg_warn("recipient %s: bad gid %s in %s", state.msg_attr.user, gid_res, virtual_gid_maps->title);
++ dsb_simple(why, "4.3.5", "mail system configuration error");
++ *statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr));
++ RETURN(YES);
+ }
++
+ usr_attr.gid = (gid_t) n;
+
+ if (msg_verbose)
+- msg_info("%s[%d]: set user_attr: %s, uid = %u, gid = %u",
+- myname, state.level, usr_attr.mailbox,
+- (unsigned) usr_attr.uid, (unsigned) usr_attr.gid);
++ msg_info("%s[%d]: set user_attr: %s, uid = %u, gid = %u",
++ myname, state.level, usr_attr.mailbox,
++ (unsigned) usr_attr.uid, (unsigned) usr_attr.gid);
+
+ /*
+ * Deliver to mailbox or to maildir.
+@@ -261,8 +315,15 @@
+
+ if (LAST_CHAR(usr_attr.mailbox) == '/')
+ *statusp = deliver_maildir(state, usr_attr);
+- else
+- *statusp = deliver_mailbox_file(state, usr_attr);
++ else {
++ int changed_limit;
++
++ changed_limit = change_mailbox_limit(state, usr_attr);
++ *statusp = deliver_mailbox_file(state, usr_attr);
++
++ if (changed_limit)
++ set_file_limit(var_virt_mailbox_limit);
++ }
+
+ /*
+ * Cleanup.
+diff -Nru postfix-2.4.0/src/virtual/maildir.c postfix-2.4.0-vda/src/virtual/maildir.c
+--- postfix-2.4.0/src/virtual/maildir.c 2006-06-26 14:59:19.000000000 +0200
++++ postfix-2.4.0-vda/src/virtual/maildir.c 2007-04-13 19:05:33.000000000 +0200
+@@ -63,10 +63,242 @@
+ #include <mbox_open.h>
+ #include <dsn_util.h>
+
++/* Patch library. */
++#include <sys/types.h> /* opendir(3), stat(2) */
++#include <sys/stat.h> /* stat(2) */
++#include <dirent.h> /* opendir(3) */
++#include <unistd.h> /* stat(2) */
++#include <stdlib.h> /* atol(3) */
++#include <string.h> /* strrchr(3) */
++#include <vstring_vstream.h>
++#include <dict.h>
++#include <dict_regexp.h>
++#include <ctype.h>
++#include <stdio.h>
++#include <sys_defs.h>
++#include <mail_addr_find.h>
++
+ /* Application-specific. */
+
+ #include "virtual.h"
+
++/*
++ * Gives the size of the file according to the Maildir++ extension
++ * present in the filename (code taken from courier-imap).
++ *
++ * Arguments:
++ * n: filename
++ *
++ * Returns the size given in ",S=size" in the filename,
++ * zero if it cannot find ",S=size" in the filename.
++ */
++static long maildir_parsequota(const char *n)
++{
++ const char *o;
++ int yes = 0;
++
++ if ((o = strrchr(n, '/')) == 0)
++ o = n;
++
++ for (; *o; o++) {
++ if (*o == ':')
++ break;
++ }
++
++ for (; o >= n; --o) {
++ if (*o == '/')
++ break;
++
++ if (*o == ',' && o[1] == 'S' && o[2] == '=') {
++ yes = 1;
++ o += 3;
++ break;
++ }
++ }
++
++ if (yes) {
++ long s = 0;
++
++ while (*o >= '0' && *o <= '9')
++ s = s*10 + (*o++ - '0');
++
++ return s;
++ }
++
++ return 0;
++}
++
++/*
++ * Computes quota usage for a directory (taken from exim).
++ *
++ * This function is called if quota is set for a virtual maildir box.
++ * It scans the directory and stats all the files in order to get a total
++ * size and count. This is an expensive thing to do. But by doing it this
++ * way no write access is needed to a single file that can be erased or
++ * meddled with because of lock problems.
++ *
++ * Arguments:
++ * dirname: the name of the directory
++ * countptr: where to add the file count (because this function recurses)
++ * mailplus: if the check will make use of the Maildir++ extension
++ *
++ * Returns the sum of the sizes of all stattable files,
++ * zero if the directory could not be opened.
++ */
++static long check_dir_size(char *dirname, long *countptr, bool mailplus)
++{
++ char *myname = "check_dir_size";
++ DIR *dir;
++ long sum = 0;
++ struct dirent *ent;
++ struct stat statbuf;
++
++ dir = opendir(dirname);
++ if (dir == NULL) {
++ if (make_dirs(dirname, 0700) == 0) { /* Try to create the dirs. */
++ dir = opendir(dirname); /* Reopen the dir. */
++ if (dir == NULL) {
++ msg_warn("%s: cannot open directory: %s, second try", myname, dirname);
++ return 0;
++ }
++ }
++ else {
++ msg_warn("%s: cannot open directory: %s", myname, dirname);
++ return 0;
++ }
++ }
++
++ while ((ent = readdir(dir)) != NULL) {
++ char *name = ent->d_name;
++ VSTRING *buffer;
++
++ if (var_virt_trash_count) {
++ if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0 || strcmp(name, var_virt_trash_name) == 0)
++ continue;
++ }
++ else {
++ if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
++ continue;
++ }
++
++ if (var_virt_maildir_extended && mailplus) {
++ /* Using Maildir++ size information. */
++ sum += maildir_parsequota(name);
++ (*countptr)++;
++ }
++ else {
++ buffer = vstring_alloc(1024);
++ vstring_sprintf(buffer, "%s/%s", dirname, name);
++ if (stat(vstring_str(buffer), &statbuf) < 0) {
++ vstring_free(buffer);
++ continue;
++ }
++ if ((statbuf.st_mode & S_IFREG) != 0) {
++ if (strcmp(dirname + strlen(dirname) - 3 , "new") == 0 || strcmp(dirname + strlen(dirname) - 3 , "cur") == 0 || strcmp(dirname + strlen(dirname) - 3 , "tmp") == 0) {
++ sum += statbuf.st_size;
++ (*countptr)++;
++ }
++ } else if ((statbuf.st_mode & S_IFDIR) != 0) {
++ sum += check_dir_size(vstring_str(buffer), countptr, mailplus);
++ }
++ vstring_free(buffer);
++ }
++ }
++ closedir(dir);
++
++ if (msg_verbose)
++ msg_info("%s: dir=%s sum=%ld count=%ld", myname, dirname, sum, *countptr);
++
++ return sum;
++}
++
++/* Cut all occurrences of pattern from string. */
++static char *strcut(char *str, const char *pat)
++{
++ char *ptr, *loc, *ret;
++ ret = str;
++ loc = str;
++
++ /* No match, return original string. */
++ if (!strstr(loc, pat))
++ return(str);
++
++ while (*loc && (ptr = strstr(loc, pat))) {
++ while (loc < ptr)
++ *str++ = *loc++;
++ loc += strlen(pat);
++ }
++
++ while (*loc)
++ *str++ = *loc++;
++
++ *str = 0;
++
++ return(ret);
++}
++
++static long sql2file(char *filename, char *user)
++{
++ char *myname = "sql2file";
++ char *filter_sqlres;
++ char filter_fileres[128];
++ long sqlmtime = 0, filemtime = 0, retval = 0;
++ int filterfile, size_sqlres, i;
++ struct stat statbuf;
++
++ if (*var_virt_maildir_filter_maps != 0) {
++ filter_sqlres = (char *) mymalloc(16000);
++ filter_sqlres = (char *) mail_addr_find(virtual_maildir_filter_maps, user, (char **) 0);
++
++ if (filter_sqlres) {
++ strcut(filter_sqlres, "\r");
++ if (filter_sqlres[0] == '#' && filter_sqlres[1] == ' ' && filter_sqlres[2] == 'M') {
++ size_sqlres = strlen(filter_sqlres);
++
++ for (i = 4; i <= size_sqlres; i++) {
++ if(filter_sqlres[i] == '/' && filter_sqlres[i+1] == '^') {
++ filter_sqlres[i-1] = '\n';
++ }
++ }
++
++ filter_sqlres[(size_sqlres+1)] = '\0';
++
++ sqlmtime = atol(filter_sqlres+3);
++ retval = sqlmtime;
++
++ filterfile = open(filename, O_RDONLY, 0);
++ if (filterfile) {
++ read(filterfile, (void *) filter_fileres, 127);
++ close(filterfile);
++
++ filemtime = atol(filter_fileres+3);
++ }
++
++ if (msg_verbose)
++ msg_info("%s: filter data: sql_size=%u sql_mtime=%ld file_mtime=%ld", myname, strlen(filter_sqlres), sqlmtime, filemtime);
++ }
++ if (sqlmtime != filemtime && sqlmtime != 0) {
++ if ((filterfile = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0660))) {
++ if (msg_verbose)
++ msg_info("%s: updating filter file: %s", myname, filename);
++ write(filterfile, filter_sqlres, strlen(filter_sqlres));
++ close(filterfile);
++ } else {
++ msg_warn("%s: can't create filter file: %s", myname, filename);
++ retval = 0;
++ }
++ }
++ }
++ } else {
++ if (stat(filename, &statbuf) == 0)
++ retval = (long) statbuf.st_mtime;
++ if (msg_verbose)
++ msg_info("%s: processing filter file: file_mtime=%ld", myname, retval);
++ }
++
++ return(retval);
++}
++
+ /* deliver_maildir - delivery to maildir-style mailbox */
+
+ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr)
+@@ -86,6 +318,27 @@
+ struct stat st;
+ struct timeval starttime;
+
++ /* Maildir Quota. */
++ const char *limit_res; /* Limit from map. */
++ char *sizefilename = (char *) 0;
++ VSTRING *filequota; /* Quota from 'maildirsize' file. */
++ VSTREAM *sizefile;
++ long n = 0; /* Limit in long integer format. */
++ long saved_count = 0; /* The total number of files. */
++ long saved_size = 0; /* The quota of the whole Maildir. */
++ struct stat statbuf; /* To check the size of the mail written. */
++ struct stat sizefile_stat; /* To check the size of the maildirsize file (cannot be larger than 5k). */
++ time_t tm;
++
++ /* Maildir Filters. */
++ const char *value, *cmd_text;
++ char *filtername, *header, *bkpnewfile;
++ VSTRING *fltstr;
++ VSTREAM *tmpfilter;
++ DICT *FILTERS;
++ long sqlmtime;
++ int cmd_len;
++
+ GETTIMEOFDAY(&starttime);
+
+ /*
+@@ -122,6 +375,80 @@
+ curdir = concatenate(usr_attr.mailbox, "cur/", (char *) 0);
+
+ /*
++ * Concatenate the maildir suffix (if set).
++ */
++ if (*var_virt_maildir_suffix == 0) {
++ newdir = concatenate(usr_attr.mailbox, "new/", (char *) 0);
++ tmpdir = concatenate(usr_attr.mailbox, "tmp/", (char *) 0);
++ curdir = concatenate(usr_attr.mailbox, "cur/", (char *) 0);
++ }
++ else {
++ newdir = concatenate(usr_attr.mailbox, var_virt_maildir_suffix, (char *) 0);
++ tmpdir = concatenate(usr_attr.mailbox, var_virt_maildir_suffix, (char *) 0);
++ curdir = concatenate(usr_attr.mailbox, var_virt_maildir_suffix, (char *) 0);
++ newdir = concatenate(newdir, "new/", (char *) 0);
++ tmpdir = concatenate(tmpdir, "tmp/", (char *) 0);
++ curdir = concatenate(curdir, "cur/", (char *) 0);
++ }
++
++ /*
++ * Find the Maildir limit in the maps. Fall back to virtual_mailbox_limit in
++ * case limit is smaller than message_size_limit.
++ */
++ if ((limit_res = mail_addr_find(virtual_mailbox_limit_maps, state.msg_attr.user, (char **) NULL))) {
++ n = atol(limit_res);
++ if (n > 0) {
++ if ((n < var_message_limit) && (!var_virt_mailbox_limit_override)) {
++ n = var_virt_mailbox_limit;
++
++ msg_warn("%s: recipient %s - virtual maildir limit is "
++ "smaller than %s in %s - falling back to %s",
++ myname,
++ state.msg_attr.user,
++ VAR_MESSAGE_LIMIT,
++ virtual_mailbox_limit_maps->title,
++ VAR_VIRT_MAILBOX_LIMIT);
++ }
++ else {
++ if (msg_verbose)
++ msg_info("%s: set virtual maildir limit size for %s to %ld",
++ myname, usr_attr.mailbox, n);
++ }
++ }
++ else {
++ /* Invalid limit size (negative), or zero. Set n to 0. */
++ n = 0;
++ }
++ } else {
++ /* There is no limit in the maps. Set n to 0. */
++ n = 0;
++ }
++
++ /*
++ * Check quota before delivering the mail.
++ */
++ if (n != 0) {
++ set_eugid(usr_attr.uid, usr_attr.gid);
++ if (var_virt_mailbox_limit_inbox) {
++ /* Check Inbox only (new and cur dirs) with Maildir++. */
++ saved_size = check_dir_size(newdir, &saved_count, 1);
++ saved_size += check_dir_size(curdir, &saved_count, 1);
++ /* Check tmp dir without Maildir++. */
++ saved_size += check_dir_size(tmpdir, &saved_count, 0);
++ }
++ else {
++ /*
++ * Check all boxes.
++ * This will use "old" stat() calls instead of the faster
++ * Maildir++ support because we cannot afford the
++ * time to test all filename types.
++ */
++ saved_size = check_dir_size(usr_attr.mailbox, &saved_count, 0);
++ }
++ set_eugid(var_owner_uid, var_owner_gid);
++ }
++
++ /*
+ * Create and write the file as the recipient, so that file quota work.
+ * Create any missing directories on the fly. The file name is chosen
+ * according to ftp://koobera.math.uic.edu/www/proto/maildir.html:
+@@ -178,6 +505,7 @@
+ (unsigned long) starttime.tv_sec, var_pid, get_hostname());
+ tmpfile = concatenate(tmpdir, STR(buf), (char *) 0);
+ newfile = 0;
++ bkpnewfile = 0;
+ if ((dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0
+ && (errno != ENOENT
+ || make_dirs(tmpdir, 0700) < 0
+@@ -200,17 +528,254 @@
+ (unsigned long) starttime.tv_usec,
+ get_hostname());
+ newfile = concatenate(newdir, STR(buf), (char *) 0);
++ bkpnewfile = concatenate(STR(buf), (char *) 0); /* Will need it later, if we MOVE to other folders. */
+ if ((mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr),
+ dst, copy_flags, "\n",
+ why)) == 0) {
++
++ /*
++ * Add a ",S=<sizeoffile>" to the newly written file according to the
++ * Maildir++ specifications: http://www.inter7.com/courierimap/README.maildirquota.html
++ * This needs a stat(2) of the tempfile and modification of the
++ * name of the file.
++ */
++ if (stat(tmpfile, &statbuf) == 0) {
++ if (n != 0) {
++ saved_size += (long) statbuf.st_size;
++ saved_count++;
++ }
++ if (var_virt_maildir_extended) {
++ /* Append the size of the file to newfile. */
++ vstring_sprintf(buf, ",S=%ld", (long) statbuf.st_size);
++ newfile = concatenate(newfile, STR(buf), (char *) 0);
++ }
++ }
++
++ /*
++ * Now we have the maildir size in saved_size, compare it to the max
++ * quota value and eventually issue a message that we've overdrawn it.
++ */
++ if (saved_size > n) {
++ mail_copy_status = MAIL_COPY_STAT_WRITE;
++ vstring_sprintf(why->reason, "%s", var_virt_maildir_limit_message);
++ if ((statbuf.st_size > n) || (var_virt_overquota_bounce))
++ errno = EFBIG;
++ else
++ errno = EDQUOT;
++ }
++ else {
++ /* Maildirfilter code by rk@demiurg.net. */
++ if (var_virt_maildir_filter) {
++ if (msg_verbose)
++ msg_info("%s: loading DICT filters", myname);
++
++#define STREQUAL(x,y,l) (strncasecmp((x), (y), (l)) == 0 && (y)[l] == 0)
++#define MAIL_COPY_STAT_REJECT (1<<3)
++#define MAIL_COPY_STAT_DISCARD (1<<4)
++
++ /* Read filters. */
++ filtername = concatenate("regexp:", usr_attr.mailbox, "maildirfilter", (char *) 0);
++ sqlmtime = sql2file(strchr(filtername, '/'), state.msg_attr.user);
++
++ /* Check if this filter is already registered as dictionary. */
++ if (msg_verbose)
++ msg_info("%s: checking DICT filters for %s", myname, filtername);
++
++ if ((FILTERS = dict_handle(filtername))) {
++ if (msg_verbose)
++ msg_info("%s: DICT filter found", myname);
++
++ /*
++ * If we have mtime in our DICT structure, check it against sqlmtime
++ * and reload the filters if they differ.
++ */
++ if (FILTERS->mtime > 0 && sqlmtime > 0 && sqlmtime != FILTERS->mtime) {
++ if (msg_verbose)
++ msg_info("%s: reloading DICT filters (dict_mtime=%ld != sql_mtime=%ld)",
++ myname, FILTERS->mtime, sqlmtime);
++
++ dict_unregister(filtername);
++ FILTERS = dict_open(filtername, O_RDONLY, DICT_FLAG_LOCK);
++ dict_register(filtername, FILTERS);
++ FILTERS->mtime = sqlmtime;
++ }
++ }
++ else {
++ if (sqlmtime > 0) {
++ /* Registering filter as new dictionary. */
++ if (msg_verbose)
++ msg_info("%s: loading DICT filters from %s (mtime=%ld)",
++ myname, filtername, sqlmtime);
++
++ FILTERS = dict_open(filtername, O_RDONLY, DICT_FLAG_LOCK);
++ dict_register(filtername, FILTERS);
++ FILTERS->mtime = sqlmtime;
++ }
++ }
++
++ if (FILTERS && (tmpfilter = vstream_fopen(tmpfile, O_RDONLY, 0))) {
++ fltstr = vstring_alloc(1024);
++ header = (char *) malloc(8192); /* !!!INSECURE!!! See 7168-hack below. */
++ header[0] = 0;
++ vstring_get_nonl_bound(fltstr, tmpfilter, 1023);
++ header = concatenate(header, STR(fltstr), (char *) 0);
++
++ while(!vstream_feof(tmpfilter) && fltstr->vbuf.data[0] && strlen(header) < 7168 ) {
++ vstring_get_nonl_bound(fltstr, tmpfilter, 1023);
++ /* Glue multiline headers, replacing leading TAB with space. */
++ if (msg_verbose)
++ msg_info("%s: fltstr value: %s", myname, STR(fltstr));
++
++ if (fltstr->vbuf.data[0] == ' ' || fltstr->vbuf.data[0] == '\t' ) {
++ if (fltstr->vbuf.data[0] == '\t')
++ fltstr->vbuf.data[0] = ' ';
++ header = concatenate(header, STR(fltstr), (char *) 0);
++ }
++ else {
++ header = concatenate(header, "\n", STR(fltstr), (char *) 0);
++ }
++ }
++
++ if (msg_verbose)
++ msg_info("%s: checking filter CMD for %s", myname, filtername);
++
++ /* Check whole header part with regexp maps. */
++ if ((value = dict_get(FILTERS, lowercase(header))) != 0) {
++ if (msg_verbose)
++ msg_info("%s: preparing filter CMD", myname);
++
++ cmd_text = value + strcspn(value, " \t");
++ cmd_len = cmd_text - value;
++ while (*cmd_text && ISSPACE(*cmd_text))
++ cmd_text++;
++
++ if (msg_verbose)
++ msg_info("%s: executing filter CMD", myname);
++
++ if (STREQUAL(value, "REJECT", cmd_len)) {
++ if (msg_verbose)
++ msg_info("%s: executing filter CMD REJECT", myname);
++
++ mail_copy_status = MAIL_COPY_STAT_REJECT;
++ vstring_sprintf(why->reason, "%s", cmd_text);
++ dsb_simple(why, "5.0.0", "User filter - REJECT");
++ }
++
++ if (STREQUAL(value, "DISCARD", cmd_len)) {
++ if (msg_verbose)
++ msg_info("%s: executing filter CMD DISCARD", myname);
++
++ mail_copy_status = MAIL_COPY_STAT_DISCARD;
++ vstring_sprintf(why->reason, "%s", cmd_text);
++ dsb_simple(why, "5.0.0", "User filter - DISCARD");
++ }
++
++ if (STREQUAL(value, "MOVE", cmd_len)) {
++ if (msg_verbose)
++ msg_info("%s: executing filter CMD MOVE", myname);
++
++ strcut((char *) cmd_text, " ");
++ strcut((char *) cmd_text, "\t");
++ strcut((char *) cmd_text, "/");
++ strcut((char *) cmd_text, "..");
++
++ if (*var_virt_maildir_suffix == 0) {
++ newfile = concatenate(usr_attr.mailbox, (char *) 0);
++ }
++ else {
++ newfile = concatenate(usr_attr.mailbox, var_virt_maildir_suffix, (char *) 0);
++ }
++
++ if (cmd_text[0] != '.') {
++ newfile = concatenate(newfile, ".", (char *) 0);
++ }
++ newdir = concatenate(newfile, cmd_text, "/", "new/", (char *) 0);
++ tmpdir = concatenate(newfile, cmd_text, "/", "tmp/", (char *) 0);
++ curdir = concatenate(newfile, cmd_text, "/", "cur/", (char *) 0);
++ newfile = concatenate(newfile, cmd_text, "/", "new/", bkpnewfile, (char *) 0);
++ }
++
++ if (STREQUAL(value, "LOG", cmd_len) || STREQUAL(value, "WARN", cmd_len)) {
++ msg_warn("%s: header check warning: %s", myname, cmd_text);
++ }
++
++ if (STREQUAL(value, "INFO", cmd_len)) {
++ msg_info("%s: header check info: %s", myname, cmd_text);
++ }
++
++ if (msg_verbose)
++ msg_info("%s: exiting filter CMD", myname);
++ } /* End-Of-Check */
++
++ myfree(header);
++ vstring_free(fltstr);
++ vstream_fclose(tmpfilter);
++ }
++ myfree(filtername);
++ } /* End-Of-Maildirfilter */
++
++ /* Deliver to curdir. */
++ if (mail_copy_status == 0) {
++
+ if (sane_link(tmpfile, newfile) < 0
+ && (errno != ENOENT
+- || (make_dirs(curdir, 0700), make_dirs(newdir, 0700)) < 0
++ || (make_dirs(curdir, 0700), make_dirs(newdir, 0700), make_dirs(tmpdir,0700)) < 0
+ || sane_link(tmpfile, newfile) < 0)) {
+ dsb_simple(why, mbox_dsn(errno, "4.2.0"),
+ "create maildir file %s: %m", newfile);
+ mail_copy_status = MAIL_COPY_STAT_WRITE;
+ }
++
++ if (var_virt_create_maildirsize) {
++ time(&tm);
++
++ if (*var_virt_maildir_suffix == 0) {
++ sizefilename = concatenate(usr_attr.mailbox, "maildirsize", (char *) 0);
++ }
++ else {
++ sizefilename = concatenate(usr_attr.mailbox, var_virt_maildir_suffix, (char *) 0);
++ sizefilename = concatenate(sizefilename, "maildirsize", (char *) 0);
++ }
++
++ /* Make sure the quota in the file is the same as in the maildirsize file. */
++ sizefile = vstream_fopen(sizefilename, O_RDONLY, 0);
++ if (sizefile) {
++ filequota = vstring_alloc(128);
++ vstring_get_null_bound(filequota, sizefile, 127);
++ vstream_fclose(sizefile);
++ if (atol(vstring_export(filequota)) != n)
++ unlink(sizefilename);
++ }
++
++ /* Open maildirsize file to append this transaction. */
++ sizefile = vstream_fopen(sizefilename, O_WRONLY | O_APPEND, 0644);
++
++ /* If the open fails (maildirsize doesn't exist), or it's too large, overwrite it. */
++ if(!sizefile || (stat(sizefilename, &sizefile_stat) != 0) || (int) sizefile_stat.st_size > 5120 || (int) sizefile_stat.st_mtime + 15*60 < tm) {
++ /* If the file exists, sizefile has been opened above, so close it. */
++ if (sizefile) {
++ vstream_fclose(sizefile);
++ sizefile = vstream_fopen(sizefilename, O_WRONLY | O_TRUNC, 0644);
++ }
++ else {
++ sizefile = vstream_fopen(sizefilename, O_WRONLY | O_CREAT, 0644);
++ }
++
++ /* If the creation worked, write to the file, otherwise just give up. */
++ if (sizefile) {
++ vstream_fprintf(sizefile, "%ldS\n%ld %ld\n", n, saved_size, saved_count);
++ vstream_fclose(sizefile);
++ }
++ }
++ else {
++ /* We opened maildirsize, so let's append our transaction and close it. */
++ vstream_fprintf(sizefile, "%ld 1\n", (long) statbuf.st_size);
++ vstream_fclose(sizefile);
++ }
++ }
++ }
++}
++
+ }
+ if (unlink(tmpfile) < 0)
+ msg_warn("remove %s: %m", tmpfile);
+@@ -231,6 +796,9 @@
+ STR(why->reason));
+ msg_warn("perhaps you need to create the maildirs in advance");
+ }
++ if (errno == EFBIG) {
++ dsb_simple(why, "5.0.0", "The user has overdrawn his diskspace quota");
++ }
+ vstring_sprintf_prepend(why->reason, "maildir delivery failed: ");
+ deliver_status =
+ (STR(why->status)[0] == '4' ?
+@@ -246,6 +814,8 @@
+ myfree(newdir);
+ myfree(tmpdir);
+ myfree(curdir);
++ if (sizefilename)
++ myfree(sizefilename);
+ myfree(tmpfile);
+ if (newfile)
+ myfree(newfile);
+diff -Nru postfix-2.4.0/src/virtual/virtual.c postfix-2.4.0-vda/src/virtual/virtual.c
+--- postfix-2.4.0/src/virtual/virtual.c 2007-03-27 02:07:43.000000000 +0200
++++ postfix-2.4.0-vda/src/virtual/virtual.c 2007-04-13 19:05:33.000000000 +0200
+@@ -330,12 +330,27 @@
+ int var_virt_mailbox_limit;
+ char *var_mail_spool_dir; /* XXX dependency fix */
+
++char *var_virt_mailbox_limit_maps;
++bool var_virt_mailbox_limit_inbox;
++bool var_virt_mailbox_limit_override;
++bool var_virt_maildir_extended;
++bool var_virt_create_maildirsize;
++bool var_virt_overquota_bounce;
++char *var_virt_maildir_limit_message;
++char *var_virt_maildir_suffix;
++bool var_virt_trash_count;
++char *var_virt_trash_name;
++bool var_virt_maildir_filter;
++char *var_virt_maildir_filter_maps;
++
+ /*
+ * Mappings.
+ */
+ MAPS *virtual_mailbox_maps;
+ MAPS *virtual_uid_maps;
+ MAPS *virtual_gid_maps;
++MAPS *virtual_mailbox_limit_maps;
++MAPS *virtual_maildir_filter_maps;
+
+ /*
+ * Bit masks.
+@@ -445,15 +460,20 @@
+ */
+ virtual_mailbox_maps =
+ maps_create(VAR_VIRT_MAILBOX_MAPS, var_virt_mailbox_maps,
+- DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
+-
++ DICT_FLAG_LOCK);
+ virtual_uid_maps =
+ maps_create(VAR_VIRT_UID_MAPS, var_virt_uid_maps,
+- DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
+-
++ DICT_FLAG_LOCK);
+ virtual_gid_maps =
+ maps_create(VAR_VIRT_GID_MAPS, var_virt_gid_maps,
+- DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
++ DICT_FLAG_LOCK);
++ virtual_mailbox_limit_maps =
++ maps_create(VAR_VIRT_MAILBOX_LIMIT_MAPS, var_virt_mailbox_limit_maps,
++ DICT_FLAG_LOCK);
++
++ virtual_maildir_filter_maps =
++ maps_create(VAR_VIRT_MAILDIR_FILTER_MAPS, var_virt_maildir_filter_maps,
++ DICT_FLAG_LOCK);
+
+ virtual_mbox_lock_mask = mbox_lock_mask(var_virt_mailbox_lock);
+ }
+@@ -495,16 +515,33 @@
+ VAR_VIRT_MAILBOX_LIMIT, DEF_VIRT_MAILBOX_LIMIT, &var_virt_mailbox_limit, 0, 0,
+ 0,
+ };
+- static CONFIG_STR_TABLE str_table[] = {
+- VAR_MAIL_SPOOL_DIR, DEF_MAIL_SPOOL_DIR, &var_mail_spool_dir, 0, 0,
+- VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0,
+- VAR_VIRT_UID_MAPS, DEF_VIRT_UID_MAPS, &var_virt_uid_maps, 0, 0,
+- VAR_VIRT_GID_MAPS, DEF_VIRT_GID_MAPS, &var_virt_gid_maps, 0, 0,
+- VAR_VIRT_MAILBOX_BASE, DEF_VIRT_MAILBOX_BASE, &var_virt_mailbox_base, 1, 0,
+- VAR_VIRT_MAILBOX_LOCK, DEF_VIRT_MAILBOX_LOCK, &var_virt_mailbox_lock, 1, 0,
+- 0,
++
++ static CONFIG_BOOL_TABLE bool_table[] = {
++ VAR_VIRT_MAILBOX_LIMIT_INBOX, DEF_VIRT_MAILBOX_LIMIT_INBOX, &var_virt_mailbox_limit_inbox,
++ VAR_VIRT_MAILBOX_LIMIT_OVERRIDE, DEF_VIRT_MAILBOX_LIMIT_OVERRIDE, &var_virt_mailbox_limit_override,
++ VAR_VIRT_MAILDIR_EXTENDED, DEF_VIRT_MAILDIR_EXTENDED, &var_virt_maildir_extended,
++ VAR_VIRT_CREATE_MAILDIRSIZE, DEF_VIRT_CREATE_MAILDIRSIZE, &var_virt_create_maildirsize,
++ VAR_VIRT_OVERQUOTA_BOUNCE, DEF_VIRT_OVERQUOTA_BOUNCE, &var_virt_overquota_bounce,
++ VAR_VIRT_TRASH_COUNT, DEF_VIRT_TRASH_COUNT, &var_virt_trash_count,
++ VAR_VIRT_MAILDIR_FILTER, DEF_VIRT_MAILDIR_FILTER, &var_virt_maildir_filter,
++ 0,
+ };
+
++ static CONFIG_STR_TABLE str_table[] = {
++ VAR_MAIL_SPOOL_DIR, DEF_MAIL_SPOOL_DIR, &var_mail_spool_dir, 0, 0,
++ VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0,
++ VAR_VIRT_UID_MAPS, DEF_VIRT_UID_MAPS, &var_virt_uid_maps, 0, 0,
++ VAR_VIRT_GID_MAPS, DEF_VIRT_GID_MAPS, &var_virt_gid_maps, 0, 0,
++ VAR_VIRT_MAILBOX_LIMIT_MAPS, DEF_VIRT_MAILBOX_LIMIT_MAPS, &var_virt_mailbox_limit_maps, 0, 0,
++ VAR_VIRT_MAILBOX_BASE, DEF_VIRT_MAILBOX_BASE, &var_virt_mailbox_base, 1, 0,
++ VAR_VIRT_MAILBOX_LOCK, DEF_VIRT_MAILBOX_LOCK, &var_virt_mailbox_lock, 1, 0,
++ VAR_VIRT_MAILDIR_LIMIT_MESSAGE, DEF_VIRT_MAILDIR_LIMIT_MESSAGE, &var_virt_maildir_limit_message, 1, 0,
++ VAR_VIRT_MAILDIR_SUFFIX, DEF_VIRT_MAILDIR_SUFFIX, &var_virt_maildir_suffix, 0, 0,
++ VAR_VIRT_TRASH_NAME, DEF_VIRT_TRASH_NAME, &var_virt_trash_name, 0, 0,
++ VAR_VIRT_MAILDIR_FILTER_MAPS, DEF_VIRT_MAILDIR_FILTER_MAPS, &var_virt_maildir_filter_maps, 0, 0,
++ 0,
++ };
++
+ /*
+ * Fingerprint executables and core dumps.
+ */
+@@ -516,6 +553,7 @@
+ MAIL_SERVER_PRE_INIT, pre_init,
+ MAIL_SERVER_POST_INIT, post_init,
+ MAIL_SERVER_PRE_ACCEPT, pre_accept,
++ MAIL_SERVER_BOOL_TABLE, bool_table,
+ MAIL_SERVER_PRIVILEGED,
+ 0);
+ }
+diff -Nru postfix-2.4.0/src/virtual/virtual.h postfix-2.4.0-vda/src/virtual/virtual.h
+--- postfix-2.4.0/src/virtual/virtual.h 2006-01-08 00:59:47.000000000 +0100
++++ postfix-2.4.0-vda/src/virtual/virtual.h 2007-04-13 19:05:33.000000000 +0200
+@@ -34,6 +34,8 @@
+ extern MAPS *virtual_mailbox_maps;
+ extern MAPS *virtual_uid_maps;
+ extern MAPS *virtual_gid_maps;
++extern MAPS *virtual_mailbox_limit_maps;
++extern MAPS *virtual_maildir_filter_maps;
+
+ /*
+ * User attributes: these control the privileges for delivery to external