diff options
author | CHTEKK <CHTEKK@localhost> | 2007-04-13 19:03:53 +0000 |
---|---|---|
committer | CHTEKK <CHTEKK@localhost> | 2007-04-13 19:03:53 +0000 |
commit | 1f85a790113804088f9cf0c0b03287d8b14c9fd2 (patch) | |
tree | 86b45138ebe48176031d575d9ec5fc9acecf95ab | |
parent | Charset UTF-8 is what we want. (diff) | |
download | chtekk-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.patch | 1010 |
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 |