svn commit: r447911 - in head/mail/postfix211: . files

Olli Hauer ohauer at FreeBSD.org
Sun Aug 13 19:19:18 UTC 2017


Author: ohauer
Date: Sun Aug 13 19:19:16 2017
New Revision: 447911
URL: https://svnweb.freebsd.org/changeset/ports/447911

Log:
  - update to 2.10.10
  - add modified VDA patch to FILESDIR [1]
  
  Note:
  The 2.11 port will be deprecated at the time postfix-2.11.x is no longer
  supported by the postfix author (Wietse Venema), this will happen with
  the release of postfix-3.3.x.
  
  [1] It seems the VDA project os dead, there are no working patches
  against actual postfix releases provided by the project.
  This is and will be the last postfix port with VDA support, users
  using the VDA patch should adopt dovecot-lda which has also quota
  support.  As alternative VDA users can jump on the wagon and try to
  become an active maintainer of the SF.net VDA project (or a fork)

Added:
  head/mail/postfix211/files/extra-patch-postfix-vda-v13-2.11.x   (contents, props changed)
Modified:
  head/mail/postfix211/Makefile
  head/mail/postfix211/distinfo

Modified: head/mail/postfix211/Makefile
==============================================================================
--- head/mail/postfix211/Makefile	Sun Aug 13 19:11:15 2017	(r447910)
+++ head/mail/postfix211/Makefile	Sun Aug 13 19:19:16 2017	(r447911)
@@ -2,7 +2,7 @@
 # $FreeBSD$
 
 PORTNAME=	postfix
-PORTVERSION=	2.11.8
+PORTVERSION=	2.11.10
 PORTEPOCH=	1
 CATEGORIES=	mail ipv6
 MASTER_SITES=	ftp://ftp.porcupine.org/mirrors/postfix-release/ \
@@ -25,7 +25,6 @@ LICENSE_PERMS=	dist-mirror dist-sell pkg-mirror pkg-se
 
 PORTSCOUT=	limit:^2\.11\.
 
-VDAVERSION=	2.10.0
 CONFLICTS_INSTALL?=	courier-0.* opensmtpd-[0-9]* \
 		sendmail-8.* sendmail+*-8.* smail-3.* zmailer-2.* \
 		postfix2?-* postfix-3.* postfix-current-*
@@ -239,8 +238,7 @@ _REQUIRE+=		ypserv
 .endif
 
 .if ${PORT_OPTIONS:MVDA}
-PATCH_SITES+=		http://vda.sourceforge.net/VDA/:vda
-PATCHFILES+=		postfix-vda-v13-${VDAVERSION}.patch:-p1:vda
+EXTRA_PATCHES+=		${FILESDIR}/extra-patch-postfix-vda-v13-2.11.x
 .endif
 
 .if ${PORT_OPTIONS:MTEST}
@@ -318,6 +316,9 @@ do-configure:
 	${MAKEFILEFLAGS} CCARGS="${POSTFIX_CCARGS}" \
 	AUXLIBS="${POSTFIX_AUXLIBS}" && \
 	${ECHO} "all: default" >> Makefile)
+
+post-stage-VDA-on:
+	${HEAD} -n 17 ${FILESDIR}/extra-patch-postfix-vda-v13-2.11.x >> ${WRKDIR}/pkg-message
 
 pre-install-INST_BASE-on:
 	${MKDIR} ${STAGEDIR}/etc/rc.d

Modified: head/mail/postfix211/distinfo
==============================================================================
--- head/mail/postfix211/distinfo	Sun Aug 13 19:11:15 2017	(r447910)
+++ head/mail/postfix211/distinfo	Sun Aug 13 19:19:16 2017	(r447911)
@@ -1,6 +1,6 @@
-TIMESTAMP = 1463402666
-SHA256 (postfix/postfix-2.11.8.tar.gz) = 3c4ece0846b519e2e800608f3009e929a3c2a1c7841bf07397ec9edc7463c923
-SIZE (postfix/postfix-2.11.8.tar.gz) = 4032263
+TIMESTAMP = 1383475619
+SHA256 (postfix/postfix-2.11.10.tar.gz) = 4d9dca8a6f08adcb70fc02a00bde0f8057f062bc16dfa32acd6bbec2b0ffb9dd
+SIZE (postfix/postfix-2.11.10.tar.gz) = 4033890
 SHA256 (postfix/postfix-2.8.0-libspf2-1.2.x-0.patch.gz) = e5c38e5bc226cab109c02a4e530ab1aefd3bb06f2169f3e052bdf83d2727aacc
 SIZE (postfix/postfix-2.8.0-libspf2-1.2.x-0.patch.gz) = 8191
 SHA256 (postfix/postfix-vda-v13-2.10.0.patch) = 6208021eb0b37ac6482e334e538ed5700cc22c4d4dd66ed9e975ae5f20bf935f

Added: head/mail/postfix211/files/extra-patch-postfix-vda-v13-2.11.x
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/mail/postfix211/files/extra-patch-postfix-vda-v13-2.11.x	Sun Aug 13 19:19:16 2017	(r447911)
@@ -0,0 +1,1385 @@
+
+VDA patch against postfix-2.11.10+
+
+It seems the upstream VDA project is no longer maintained, the last
+changes against postfix-2.x could also be archived by using the -p1
+parameter.  This is an updated patch against 2.11.10 and it will be
+the last VDA patch for the postfix ports.
+
+Users using the VDA patch should adopt dovecot-lda which has also quota
+support.  As alternative users can jump on the wagon and try to become
+an active maintainer of the SF.net VDA project (or a fork)
+
+The 2.11 port will be deprecated at the time postfix-2.11.x is no longer
+supported by the postfix author (Wietse Venema), this will happen with
+the release of postfix-3.3.x.
+
+===========================================================================
+--- README_FILES/VDA_README.orig	1970-01-01 01:00:00.000000000 +0100
++++ README_FILES/VDA_README
+@@ -0,0 +1,10 @@
++Postfix VDA patch for maildir++ quota support by 
++    Anderson Nadal <andernadal at gmail.com>
++    Tomas Macek <maca02 at atlas.cz>
++    Lucca Longinotti
++
++See VDA patch official website http://vda.sf.net for instructions
++howto patch the Postfix's sourcetree and configure the options 
++provided by this patch.
++
++
+--- src/global/mail_params.h.orig	2017-08-13 09:19:28 UTC
++++ src/global/mail_params.h
+@@ -2413,6 +2413,54 @@ extern char *var_virt_uid_maps;
+ #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_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_LIMIT_MESSAGE_MAPS "virtual_maildir_limit_message_maps"
++#define DEF_VIRT_MAILDIR_LIMIT_MESSAGE_MAPS ""
++extern char *var_virt_maildir_limit_message_maps;
++
++#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;
+--- src/util/file_limit.c.orig	2003-10-22 18:48:36 UTC
++++ src/util/file_limit.c
+@@ -85,7 +85,11 @@ void    set_file_limit(off_t limit)
+ #else
+     struct rlimit rlim;
+ 
+-    rlim.rlim_cur = rlim.rlim_max = limit;
++    /* rlim_max can only be changed 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
+--- src/virtual/mailbox.c.orig	2016-08-22 21:24:31 UTC
++++ src/virtual/mailbox.c
+@@ -52,6 +52,7 @@
+ #include <mymalloc.h>
+ #include <stringops.h>
+ #include <set_eugid.h>
++#include <iostuff.h>
+ 
+ /* Global library. */
+ 
+@@ -70,6 +71,70 @@
+ #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 = 0;
++    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 negative, fall back to virtual_mailbox_limit.
++     * If it's 0, set the mailbox limit to 0, which means unlimited.
++     * 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 (*var_virt_mailbox_limit_maps != 0 && (limit_res = mail_addr_find(virtual_mailbox_limit_maps, state.msg_attr.user, (char **) NULL)) != 0) {
++        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 if (n == 0) {
++                set_file_limit(OFF_T_MAX);
++                status = YES;
++
++                if (msg_verbose)
++                    msg_info("%s: set virtual mailbox limit size for %s to %ld",
++                            myname, usr_attr.mailbox, OFF_T_MAX);
++        }
++        else {
++            /* Invalid limit size (negative). Use default virtual_mailbox_limit. */
++            set_file_limit(var_virt_mailbox_limit);
++            status = NO;
++        }
++    }
++    else {
++        /* There is no limit in the maps. Use default virtual_mailbox_limit. */
++        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)
+@@ -214,62 +279,72 @@ int     deliver_mailbox(LOCAL_STATE stat
+      * 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.
+      */
+ #define LAST_CHAR(s) (s[strlen(s) - 1])
+ 
+-    if (LAST_CHAR(usr_attr.mailbox) == '/')
+-	*statusp = deliver_maildir(state, usr_attr);
+-    else
+-	*statusp = deliver_mailbox_file(state, usr_attr);
++    if (LAST_CHAR(usr_attr.mailbox) == '/') {
++        *statusp = deliver_maildir(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.
+--- src/virtual/maildir.c.orig	2012-01-25 00:41:08 UTC
++++ src/virtual/maildir.c
+@@ -64,28 +64,420 @@
+ #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"
+ 
+-/* deliver_maildir - delivery to maildir-style mailbox */
++/* Maildirsize maximal size. */
+ 
+-int     deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr)
++#define SIZEFILE_MAX 5120
++
++/*
++ * Chris Stratford <chriss at pipex.net>
++ * Read the maildirsize file to get quota info.
++ *
++ * Arguments:
++ *  dirname: the maildir
++ *  countptr: number of messages
++ *
++ * Returns the size of all mails as read from maildirsize,
++ * zero if it couldn't read the file.
++ */
++static long read_maildirsize(char *filename, long *sumptr, long *countptr)
++{
++    char *myname = "read_maildirsize";
++    struct stat statbuf;
++    VSTREAM *sizefile;
++    char *p;
++    int len, first;
++    long sum = 0, count = 0, ret_value = -1;
++
++    if (msg_verbose) 
++	msg_info("%s: we will use sizefile = '%s'", myname, filename);
++	
++    sizefile = vstream_fopen(filename, O_RDONLY, 0);
++    if (!sizefile) {
++	if (msg_verbose)
++	    msg_info("%s: cannot open %s: %m (maybe file does not exist)", myname, filename);
++	    
++	return -1;
++    } else if (stat(filename, &statbuf) < 0 || statbuf.st_size > SIZEFILE_MAX) {
++        if (sizefile) {
++            vstream_fclose(sizefile);
++            unlink(filename);
++        }
++        
++        if (msg_verbose) 
++	    msg_info("%s: stat() returned < 0 or filesize > SIZEFILE_MAX (filename = %s, filesize = %ld)", myname, filename, statbuf.st_size);
++        
++        return -1;
++    }
++    
++    VSTRING *sizebuf = vstring_alloc(SIZEFILE_MAX);
++    len = vstream_fread(sizefile, STR(sizebuf), SIZEFILE_MAX);
++
++    p = STR(sizebuf);
++    *(p + len) = '\0';
++    first = 1;
++
++    while (*p) {
++        long n = 0, c = 0;
++        char *q = p;
++
++        while (*p) {
++            if (*p++ == '\n') {
++                p[-1] = 0;
++                break;
++            }
++        }
++
++        if (first) {
++            first = 0;
++            continue;
++        }
++
++        if (sscanf(q, "%ld %ld", &n, &c) == 2) {
++            sum += n;
++            count += c;
++            /* if (msg_verbose)
++    		msg_info("%s: we read line '%s', totals: sum = %ld, count = %ld", myname, q, sum, count); */
++        }
++        else {
++            vstream_fclose(sizefile);
++            unlink(filename);
++            msg_warn("%s: invalid line '%s' found in %s, removing maildirsize file", myname, q, filename);
++            vstring_free(sizebuf);
++
++            return -1;
++        }
++    }
++
++    *countptr = count;
++    *sumptr = sum;
++        
++    if (sum < 0 || count < 0 || (sum == 0 && count != 0) || (sum != 0 && count == 0)) {
++	if (msg_verbose) {
++	    msg_info("%s: we will return -1 and unlink %s, because file count or sum is <= 0 (sum = %ld, count = %ld)", myname, filename, sum, count);
++	}
++	
++	unlink(filename);
++	ret_value = -1;
++    } else {
++	if (msg_verbose) 
++	    msg_info("%s: we will return Maildir size = %ld, count = %ld", myname, *sumptr, *countptr);
++
++	ret_value = sum;	
++    }
++
++    vstream_fclose(sizefile);
++    vstring_free(sizebuf);
++    
++    return ret_value;
++}
++
++/*
++ * 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 to determine the exact quota usage of a virtual
++ * maildir box. To achieve maximum possible speed while doing this, it takes
++ * advantage of the maildirsize file and the Maildir++ extensions to filenames,
++ * when applicable and configured to be used. In all other cases it simply
++ * stats all the files as needed to get the size information.
++ *
++ * Arguments:
++ *  dirname: the name of the directory
++ *  countptr: where to add the file count (because this function recurses)
++ *
++ * Returns the sum of the sizes of all measurable files,
++ * zero if the directory could not be opened.
++ */
++static long check_dir_size(char *dirname, long *countptr)
++{
++    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 reopen directory: %s", 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;
++        long tmpsum = 0;
++        VSTRING *buffer;
++
++	/* do not count dot a double-dot dirs */
++        if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
++            continue;
++        /* do not count if this is the trash subdir and if we should NOT count it */
++	else if (var_virt_trash_count == 0 && strcmp(name, var_virt_trash_name) == 0)
++    	    continue;
++
++        /*
++         * Here comes the real logic behind this function.
++         * Optimized to be the most efficient possible,
++         * depending on the settings given.
++         * See above for a more detailed description.
++         */
++        if (var_virt_mailbox_limit_inbox) {
++            if (var_virt_maildir_extended && (tmpsum = maildir_parsequota(name))) {
++                sum += tmpsum;
++                (*countptr)++;
++            }
++            else {
++                buffer = vstring_alloc(1024);
++                vstring_sprintf(buffer, "%s/%s", dirname, name);
++
++                if (stat(STR(buffer), &statbuf) < 0) {
++                    vstring_free(buffer);
++                    continue;
++                }
++                if ((statbuf.st_mode & S_IFREG) != 0) {
++                    sum += (long) statbuf.st_size;
++                    (*countptr)++;
++                }
++
++                vstring_free(buffer);
++            }
++        }
++        else {
++            buffer = vstring_alloc(1024);
++            vstring_sprintf(buffer, "%s/%s", dirname, name);
++
++            if (stat(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 += (long) statbuf.st_size;
++                    (*countptr)++;
++                }
++            }
++            else if ((statbuf.st_mode & S_IFDIR) != 0) {
++                sum += check_dir_size(STR(buffer), countptr);
++            }
++
++            vstring_free(buffer);
++        }
++    }
++    closedir(dir);
++
++    if (msg_verbose)
++        msg_info("%s: full scan done: 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);
++}
++
++/* Check if maildirfilter file is up-to-date compared to SQL, (re)write it if not. */
++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=%li 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, 0640))) {
++                    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)
+ {
+     const char *myname = "deliver_maildir";
+-    char   *newdir;
+-    char   *tmpdir;
+-    char   *curdir;
+-    char   *tmpfile;
+-    char   *newfile;
++    char    *newdir;
++    char    *tmpdir;
++    char    *curdir;
++    char    *newfile;
++    char    *tmpfile;
+     DSN_BUF *why = state.msg_attr.why;
+     VSTRING *buf;
+     VSTREAM *dst;
+-    int     mail_copy_status;
+-    int     deliver_status;
+-    int     copy_flags;
+-    struct stat st;
+-    struct timeval starttime;
++    int      mail_copy_status;
++    int      deliver_status;
++    int      copy_flags;
++    struct   stat st;
++    struct   timeval starttime;
++
++    /* Maildir Quota. */
++    const char *limit_res;              /* Limit from map. */
++    char    *sizefilename = (char *) 0; /* Maildirsize file name. */
++    VSTRING *filequota;                 /* Quota setting from the maildirsize file. */
++    VSTREAM *sizefile;                  /* Maildirsize file handle. */
++    long     n = 0;                     /* Limit in long integer format. */
++    long     saved_count = 0;           /* The total number of files. */
++    long     saved_size = 0;            /* The total quota of all files. */
++    struct   stat mail_stat;            /* To check the size of the mail to be written. */
++    struct   stat sizefile_stat;        /* To check the size of the maildirsize file. */
++    time_t   tm;                        /* To check the age of the maildirsize file. */
++
++    /* Maildir Filters. */
++    const char *value, *cmd_text;       /* Filter values. */
++    char    *filtername;
++    char    *header;
++    char    *bkpnewfile;
++    char    *mdffilename = (char *) 0;  /* Maildirfolder file name. */
++    VSTRING *fltstr;
++    VSTREAM *tmpfilter;
++    VSTREAM *mdffile;                   /* Maildirfolder file handle. */
++    DICT    *FILTERS;
++    long     sqlmtime;                  /* Latest modification time from sql2file(). */
++    int      cmd_len;
++    int	    read_mds = -1;		/* read_maildirsize() returned value */
++    struct   stat mdffile_stat;         /* To check if the maildirfolder file exists. */
+ 
+     GETTIMEOFDAY(&starttime);
+ 
+@@ -94,15 +486,14 @@ int     deliver_maildir(LOCAL_STATE stat
+      */
+     state.level++;
+     if (msg_verbose)
+-	MSG_LOG_STATE(myname, state);
++	    MSG_LOG_STATE(myname, state);
+ 
+     /*
+      * Don't deliver trace-only requests.
+      */
+     if (DEL_REQ_TRACE_ONLY(state.request->flags)) {
+-	dsb_simple(why, "2.0.0", "delivers to maildir");
+-	return (sent(BOUNCE_FLAGS(state.request),
+-		     SENT_ATTR(state.msg_attr)));
++        dsb_simple(why, "2.0.0", "delivers to maildir");
++        return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr)));
+     }
+ 
+     /*
+@@ -110,18 +501,116 @@ int     deliver_maildir(LOCAL_STATE stat
+      * attribute to reflect the final recipient.
+      */
+     if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
+-	msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp));
++        msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp));
+     state.msg_attr.delivered = state.msg_attr.rcpt.address;
+     mail_copy_status = MAIL_COPY_STAT_WRITE;
+     buf = vstring_alloc(100);
+ 
+-    copy_flags = MAIL_COPY_TOFILE | MAIL_COPY_RETURN_PATH
+-	| MAIL_COPY_DELIVERED | MAIL_COPY_ORIG_RCPT;
++    copy_flags = MAIL_COPY_TOFILE | MAIL_COPY_RETURN_PATH | MAIL_COPY_DELIVERED | MAIL_COPY_ORIG_RCPT;
+ 
+-    newdir = concatenate(usr_attr.mailbox, "new/", (char *) 0);
+-    tmpdir = concatenate(usr_attr.mailbox, "tmp/", (char *) 0);
+-    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);
++    }
++
++    /* get the sizefilename, no matter if we use var_virt_maildir_extended */
++    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);
++    }
++    
++    /*
++     * Look up the virtual maildir limit size for this user.
++     * Fall back to virtual_mailbox_limit in case lookup failed.
++     * If virtual maildir limit size is negative, fall back to virtual_mailbox_limit.
++     * If it's 0, set the mailbox limit to 0, which means unlimited.
++     * 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 maildir limit can't be overridden, fall back to virtual_mailbox_limit and
++     * warn the user, else use the value directly as the maildir limit.
++     */
++    if (*var_virt_mailbox_limit_maps != 0 && (limit_res = mail_addr_find(virtual_mailbox_limit_maps, state.msg_attr.user, (char **) NULL)) != 0) {
++        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 if (n == 0) {
++                if (msg_verbose)
++                    msg_info("%s: set virtual maildir limit size for %s to %ld",
++                            myname, usr_attr.mailbox, n);
++        }
++        else {
++	    if (msg_verbose)
++		msg_info("%s: quota is negative (%ld), using default virtual_mailbox_limit (%ld)", 
++			    myname, n, var_virt_mailbox_limit);
++            /* Invalid limit size (negative). Use default virtual_mailbox_limit. */
++            n = var_virt_mailbox_limit;
++        }
++    }
++    else {
++	if (msg_verbose)
++	    msg_info("%s: no limit found in the maps, using default virtual_mailbox_limit (%ld)", 
++			myname, var_virt_mailbox_limit);
++        /* There is no limit in the maps. Use default virtual_mailbox_limit. */
++        n = var_virt_mailbox_limit;
++    }
+ 
++    /* If there should is a quota on maildir generaly, check it before delivering the mail */
++    if (n != 0) {
++        set_eugid(usr_attr.uid, usr_attr.gid);
++	/* try to read the quota from maildirsize file. Returned values by read_maildirsize:
++	x < 0  = something failed
++	x >= 0 = reading successfully finished - sum si returned, so sum size of Maildir was 0 or more */
++        if (!var_virt_mailbox_limit_inbox && var_virt_maildir_extended && (read_mds = read_maildirsize(sizefilename, &saved_size, &saved_count)) >= 0) {
++    	    if (msg_verbose)
++        	msg_info("%s: maildirsize used=%s sum=%ld count=%ld", myname, sizefilename, saved_size, saved_count);
++	} else {
++	    if (msg_verbose) 
++		msg_info("%s: We will recount the quota (var_virt_mailbox_limit = %ld, var_virt_maildir_extended = %d, read_maildirsize = %d)", 
++			    myname, var_virt_mailbox_limit, var_virt_maildir_extended, read_mds);
++
++	    /* sanity */
++	    saved_size = 0; 
++	    saved_count = 0;
++	    
++    	    if (var_virt_mailbox_limit_inbox) {
++        	/* Check Inbox only (new, cur and tmp dirs). */
++        	saved_size = check_dir_size(newdir, &saved_count);
++        	saved_size += check_dir_size(curdir, &saved_count);
++        	saved_size += check_dir_size(tmpdir, &saved_count);
++    	    } else {
++        	/* Check all boxes. */
++        	saved_size = check_dir_size(usr_attr.mailbox, &saved_count);
++    	    }
++
++    	    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
+@@ -175,46 +664,288 @@ int     deliver_maildir(LOCAL_STATE stat
+      * [...]
+      */
+     set_eugid(usr_attr.uid, usr_attr.gid);
+-    vstring_sprintf(buf, "%lu.P%d.%s",
+-		 (unsigned long) starttime.tv_sec, var_pid, get_hostname());
++    vstring_sprintf(buf, "%lu.P%d.%s", (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
+-	    || (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) {
+-	dsb_simple(why, mbox_dsn(errno, "4.2.0"),
+-		   "create maildir file %s: %m", tmpfile);
+-    } else if (fstat(vstream_fileno(dst), &st) < 0) {
++        && (errno != ENOENT
++            || make_dirs(tmpdir, 0700) < 0
++            || (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) {
++        dsb_simple(why, mbox_dsn(errno, "4.2.0"), "create maildir file %s: %m", tmpfile);
++    }
++    else if (fstat(vstream_fileno(dst), &st) < 0) {
++        /*
++         * Coverity 200604: file descriptor leak in code that never executes.
++         * Code replaced by msg_fatal(), as it is not worthwhile to continue
++         * after an impossible error condition.
++         */
++        msg_fatal("fstat %s: %m", tmpfile);
++    }
++    else {
++        vstring_sprintf(buf, "%lu.V%lxI%lxM%lu.%s",
++                (unsigned long) starttime.tv_sec,
++                (unsigned long) st.st_dev,
++                (unsigned long) st.st_ino,
++                (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. */
+ 
+-	/*
+-	 * Coverity 200604: file descriptor leak in code that never executes.
+-	 * Code replaced by msg_fatal(), as it is not worthwhile to continue
+-	 * after an impossible error condition.
+-	 */
+-	msg_fatal("fstat %s: %m", tmpfile);
+-    } else {
+-	vstring_sprintf(buf, "%lu.V%lxI%lxM%lu.%s",
+-			(unsigned long) starttime.tv_sec,
+-			(unsigned long) st.st_dev,
+-			(unsigned long) st.st_ino,
+-			(unsigned long) starttime.tv_usec,
+-			get_hostname());
+-	newfile = concatenate(newdir, STR(buf), (char *) 0);
+-	if ((mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr),
+-					  dst, copy_flags, "\n",
+-					  why)) == 0) {
+-	    if (sane_link(tmpfile, newfile) < 0
+-		&& (errno != ENOENT
+-		    || (make_dirs(curdir, 0700), make_dirs(newdir, 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 (unlink(tmpfile) < 0)
+-	    msg_warn("remove %s: %m", tmpfile);
++        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, &mail_stat) == 0) {
++                if (n != 0) {
++                    saved_size += (long) mail_stat.st_size;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-ports-all mailing list