-/* $Cambridge: exim/src/src/transports/appendfile.c,v 1.13 2006/02/21 16:24:20 ph10 Exp $ */
+/* $Cambridge: exim/src/src/transports/appendfile.c,v 1.22 2007/02/20 09:53:41 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2006 */
+/* Copyright (c) University of Cambridge 1995 - 2007 */
/* See the file NOTICE for conditions of use and distribution. */
(void *)offsetof(appendfile_transport_options_block, maildir_tag) },
{ "maildir_use_size_file", opt_bool,
(void *)offsetof(appendfile_transport_options_block, maildir_use_size_file ) } ,
+ { "maildirfolder_create_regex", opt_stringptr,
+ (void *)offsetof(appendfile_transport_options_block, maildirfolder_create_regex ) },
#endif /* SUPPORT_MAILDIR */
#ifdef SUPPORT_MAILSTORE
{ "mailstore_format", opt_bool,
NULL, /* mailbox_filecount_string */
US"^(?:cur|new|\\..*)$", /* maildir_dir_regex */
NULL, /* maildir_tag */
+ NULL, /* maildirfolder_create_regex */
NULL, /* mailstore_prefix */
NULL, /* mailstore_suffix */
NULL, /* check_string (default changed for non-bsmtp file)*/
until one succeeds. However, it appears that at least on some systems, comsat
doesn't listen on the ::1 address. So for the moment, just force the address to
be 127.0.0.1. At some future stage, when IPv6 really is superseding IPv4, this
-can be changed. */
+can be changed. (But actually, comsat is probably dying out anyway.) */
/******
-if (host_find_byname(&host, NULL, NULL, FALSE) == HOST_FIND_FAILED)
+if (host_find_byname(&host, NULL, 0, NULL, FALSE) == HOST_FIND_FAILED)
{
DEBUG(D_transport) debug_printf("\"localhost\" unknown\n");
return;
uschar *path;
struct utimbuf times;
struct timeval msg_tv;
+BOOL disable_quota = FALSE;
BOOL isdirectory = FALSE;
BOOL isfifo = FALSE;
BOOL wait_for_tick = FALSE;
return FALSE;
}
-/* For a file delivery, make sure the local part in the address is updated to
-the true local part. */
+/* For a file delivery, make sure the local part in the address(es) is updated
+to the true local part. */
-if (testflag(addr, af_file)) addr->local_part = string_copy(path);
+if (testflag(addr, af_file))
+ {
+ address_item *addr2;
+ for (addr2 = addr; addr2 != NULL; addr2 = addr2->next)
+ addr2->local_part = string_copy(path);
+ }
/* The available mailbox formats depend on whether it is a directory or a file
delivery. */
}
}
- mbx_lockfd = Uopen(mbx_lockname, O_RDWR | O_CREAT, 0600);
+ mbx_lockfd = Uopen(mbx_lockname, O_RDWR | O_CREAT, ob->lockfile_mode);
if (mbx_lockfd < 0)
{
addr->basic_errno = ERRNO_LOCKFAILED;
goto RETURN;
}
- (void)Uchmod(mbx_lockname, 0600);
+ (void)Uchmod(mbx_lockname, ob->lockfile_mode);
if (apply_lock(mbx_lockfd, F_WRLCK, ob->use_fcntl,
ob->lock_fcntl_timeout, ob->use_flock, ob->lock_flock_timeout) >= 0)
}
#ifdef SUPPORT_MAILDIR
- /* For a maildir delivery, ensure that all the relevant directories exist */
+ /* For a maildir delivery, ensure that all the relevant directories exist,
+ and a maildirfolder file if necessary. */
if (mbformat == mbf_maildir && !maildir_ensure_directories(path, addr,
- ob->create_directory, ob->dirmode))
+ ob->create_directory, ob->dirmode, ob->maildirfolder_create_regex))
return FALSE;
#endif /* SUPPORT_MAILDIR */
const uschar *error;
int offset;
- /* Compile the regex if there is one */
+ /* Compile the regex if there is one. */
if (ob->quota_size_regex != NULL)
{
ob->quota_size_regex);
return FALSE;
}
- else
- {
- DEBUG(D_transport) debug_printf("using regex for file sizes: %s\n",
- ob->quota_size_regex);
- }
+ DEBUG(D_transport) debug_printf("using regex for file sizes: %s\n",
+ ob->quota_size_regex);
}
/* Use an explicitly configured directory if set */
{
*slash = 0;
check_path = new_check_path;
+ DEBUG(D_transport) debug_printf("maildirfolder file exists: "
+ "quota check directory changed to %s\n", check_path);
}
}
}
if (ob->maildir_dir_regex != NULL)
{
+ int check_path_len = Ustrlen(check_path);
+
dir_regex = pcre_compile(CS ob->maildir_dir_regex, PCRE_COPT,
(const char **)&error, &offset, NULL);
if (dir_regex == NULL)
ob->maildir_dir_regex);
return FALSE;
}
- else
+
+ DEBUG(D_transport)
+ debug_printf("using regex for maildir directory selection: %s\n",
+ ob->maildir_dir_regex);
+
+ /* Check to see if we are delivering into an ignored directory, that is,
+ if the delivery path starts with the quota check path, and the rest
+ of the deliver path matches the regex; if so, set a flag to disable quota
+ checking and maildirsize updating. */
+
+ if (Ustrncmp(path, check_path, check_path_len) == 0)
{
- DEBUG(D_transport)
- debug_printf("using regex for maildir directory selection: %s\n",
- ob->maildir_dir_regex);
+ uschar *s = path + check_path_len;
+ while (*s == '/') s++;
+ s = (*s == 0)? US "new" : string_sprintf("%s/new", s);
+ if (pcre_exec(dir_regex, NULL, CS s, Ustrlen(s), 0, 0, NULL, 0) < 0)
+ {
+ disable_quota = TRUE;
+ DEBUG(D_transport) debug_printf("delivery directory does not match "
+ "maildir_quota_directory_regex: disabling quota\n");
+ }
}
}
/* if (???? || ob->quota_value > 0) */
+ if (!disable_quota)
{
off_t size;
int filecount;
}
#endif /* SUPPORT_MAILDIR */
- /* Otherwise (mailbox_size is not yet set), if we are going to do a quota
- check later on, find the current size of the mailbox. (We don't need to check
- ob->quota_filecount_value, because it can only be set if ob->quota_value is
- set.) */
+ /* Otherwise if we are going to do a quota check later on, and the mailbox
+ size is not set, find the current size of the mailbox. Ditto for the file
+ count. Note that ob->quota_filecount_value cannot be set without
+ ob->quota_value being set. */
- if ((mailbox_size < 0 || mailbox_filecount < 0) &&
- (ob->quota_value > 0 || THRESHOLD_CHECK))
+ if (!disable_quota &&
+ (ob->quota_value > 0 || THRESHOLD_CHECK) &&
+ (mailbox_size < 0 ||
+ (mailbox_filecount < 0 && ob->quota_filecount_value > 0)))
{
off_t size;
int filecount = 0;
is for the mailbox already being over quota (i.e. the current message is not
included in the check). */
-if (ob->quota_value > 0)
+if (!disable_quota && ob->quota_value > 0)
{
DEBUG(D_transport)
{
/* Force out the remaining data to check for any errors; some OS don't allow
fsync() to be called for a FIFO. */
-if (yield == OK && !isfifo && fsync(fd) < 0) yield = DEFER;
+if (yield == OK && !isfifo && EXIMfsync(fd) < 0) yield = DEFER;
/* Update message_size to the accurate count of bytes written, including
added headers. */
message_size = transport_count;
/* If using a maildir++ quota file, add this message's size to it, and
-close the file descriptor. */
+close the file descriptor, except when the quota has been disabled because we
+are delivering into an uncounted folder. */
#ifdef SUPPORT_MAILDIR
-if (yield == OK && maildirsize_fd >= 0)
- maildir_record_length(maildirsize_fd, message_size);
-
-maildir_save_errno = errno; /* Preserve errno while closing the file */
-(void)close(maildirsize_fd);
-errno = maildir_save_errno;
+if (!disable_quota)
+ {
+ if (yield == OK && maildirsize_fd >= 0)
+ maildir_record_length(maildirsize_fd, message_size);
+ maildir_save_errno = errno; /* Preserve errno while closing the file */
+ (void)close(maildirsize_fd);
+ errno = maildir_save_errno;
+ }
#endif /* SUPPORT_MAILDIR */
/* If there is a quota warning threshold and we are have crossed it with this
message, set the SPECIAL_WARN flag in the address, to cause a warning message
to be sent. */
-if (THRESHOLD_CHECK)
+if (!disable_quota && THRESHOLD_CHECK)
{
off_t threshold = ob->quota_warn_threshold_value;
if (ob->quota_warn_threshold_is_percent)
#else
addr->message = string_sprintf("mailbox is full");
#endif /* EDQUOT */
+ addr->user_message = US"mailbox is full";
DEBUG(D_transport) debug_printf("System quota exceeded for %s%s%s\n",
dataname,
isdirectory? US"" : US": time since file read = ",