* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) The Exim maintainers 2020 - 2023 */
+/* Copyright (c) The Exim maintainers 2020 - 2024 */
/* Copyright (c) University of Cambridge 1995 - 2020 */
/* See the file NOTICE for conditions of use and distribution. */
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "../exim.h"
+
+#ifdef TRANSPORT_APPENDFILE /* Remainder of file */
#include "appendfile.h"
#ifdef SUPPORT_MAILDIR
/* Dummy values */
appendfile_transport_options_block appendfile_transport_option_defaults = {0};
-void appendfile_transport_init(transport_instance *tblock) {}
+void appendfile_transport_init(driver_instance *tblock) {}
BOOL appendfile_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
#else /*!MACRO_PREDEF*/
(!ob->quota_warn_threshold_is_percent || ob->quota_value > 0))
-
/*************************************************
* Setup entry point *
*************************************************/
appendfile_transport_setup(transport_instance *tblock, address_item *addrlist,
transport_feedback *dummy, uid_t uid, gid_t gid, uschar **errmsg)
{
-appendfile_transport_options_block *ob =
- (appendfile_transport_options_block *)(tblock->options_block);
-uschar *q = ob->quota;
+appendfile_transport_options_block * ob = tblock->drinst.options_block;
+const uschar * trname = tblock->drinst.name;
+uschar * q;
double default_value = 0.0;
if (ob->expand_maildir_use_size_file)
- ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file,
- US"`maildir_use_size_file` in transport", tblock->name);
+ {
+ GET_OPTION("maildir_use_size_file");
+ ob->maildir_use_size_file =
+ expand_check_condition(ob->expand_maildir_use_size_file,
+ US"`maildir_use_size_file` in transport", trname);
+ }
/* Loop for quota, quota_filecount, quota_warn_threshold, mailbox_size,
mailbox_filecount */
+GET_OPTION("quota");
+q = ob->quota;
for (int i = 0; i < 5; i++)
{
double d = default_value;
if (!(s = expand_string(q)))
{
*errmsg = string_sprintf("Expansion of \"%s\" in %s transport failed: "
- "%s", q, tblock->name, expand_string_message);
+ "%s", q, trname, expand_string_message);
return f.search_find_defer ? DEFER : FAIL;
}
else if ((int)d < 0 || (int)d > 100)
{
*errmsg = string_sprintf("Invalid quota_warn_threshold percentage (%d)"
- " for %s transport", (int)d, tblock->name);
+ " for %s transport", (int)d, trname);
return FAIL;
}
ob->quota_warn_threshold_is_percent = TRUE;
if (*rest)
{
*errmsg = string_sprintf("Malformed value \"%s\" (expansion of \"%s\") "
- "in %s transport", s, q, tblock->name);
+ "in %s transport", s, q, trname);
return FAIL;
}
}
which = US"quota";
ob->quota_value = (off_t)d;
ob->quota_no_check = no_check;
+ GET_OPTION("quota_filecount");
q = ob->quota_filecount;
break;
which = US"quota_filecount";
ob->quota_filecount_value = (int)d;
ob->quota_filecount_no_check = no_check;
+ GET_OPTION("quota_warn_threshold");
q = ob->quota_warn_threshold;
break;
if (d >= 2.0*1024.0*1024.0*1024.0 && sizeof(off_t) <= 4)
which = US"quota_warn_threshold";
ob->quota_warn_threshold_value = (off_t)d;
+ GET_OPTION("mailbox_size");
q = ob->mailbox_size_string;
default_value = -1.0;
break;
if (d >= 2.0*1024.0*1024.0*1024.0 && sizeof(off_t) <= 4)
which = US"mailbox_size";;
ob->mailbox_size_value = (off_t)d;
+ GET_OPTION("mailbox_filecount");
q = ob->mailbox_filecount_string;
break;
if (which)
{
*errmsg = string_sprintf("%s value %.10g is too large (overflow) in "
- "%s transport", which, d, tblock->name);
+ "%s transport", which, d, trname);
return FAIL;
}
}
to be set up. */
void
-appendfile_transport_init(transport_instance *tblock)
+appendfile_transport_init(driver_instance * t)
{
-appendfile_transport_options_block *ob =
- (appendfile_transport_options_block *)(tblock->options_block);
+transport_instance * tblock = (transport_instance *)t;
+appendfile_transport_options_block * ob = tblock->drinst.options_block;
+const uschar * trname = tblock->drinst.name;
uschar * s;
/* Set up the setup entry point, to be called in the privileged state */
if (ob->filename && ob->dirname)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n "
- "only one of \"file\" or \"directory\" can be specified", tblock->name);
+ "only one of \"file\" or \"directory\" can be specified", trname);
/* If a file name was specified, neither quota_filecount nor quota_directory
must be given. */
{
if (ob->quota_filecount)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n "
- "quota_filecount must not be set without \"directory\"", tblock->name);
+ "quota_filecount must not be set without \"directory\"", trname);
if (ob->quota_directory)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n "
- "quota_directory must not be set without \"directory\"", tblock->name);
+ "quota_directory must not be set without \"directory\"", trname);
}
/* The default locking depends on whether MBX is set or not. Change the
#ifdef NO_FLOCK
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n "
"flock() support was not available in the operating system when this "
- "binary was built", tblock->name);
+ "binary was built", trname);
#endif /* NO_FLOCK */
if (!ob->set_use_fcntl) ob->use_fcntl = FALSE;
}
if (!ob->use_fcntl && !ob->use_flock && !ob->use_lockfile && !ob->use_mbx_lock)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n "
- "no locking configured", tblock->name);
+ "no locking configured", trname);
/* Unset timeouts for non-used locking types */
{
if (ob->maildir_format && ob->mailstore_format)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n "
- "only one of maildir and mailstore may be specified", tblock->name);
- if (ob->quota_filecount != NULL && ob->quota == NULL)
+ "only one of maildir and mailstore may be specified", trname);
+ if (ob->quota_filecount != NULL && !ob->quota)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n "
- "quota must be set if quota_filecount is set", tblock->name);
- if (ob->quota_directory != NULL && ob->quota == NULL)
+ "quota must be set if quota_filecount is set", trname);
+ if (ob->quota_directory != NULL && !ob->quota)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n "
- "quota must be set if quota_directory is set", tblock->name);
+ "quota must be set if quota_directory is set", trname);
}
/* If a fixed uid field is set, then a gid field must also be set. */
if (tblock->uid_set && !tblock->gid_set && !tblock->expand_gid)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
- "user set without group for the %s transport", tblock->name);
+ "user set without group for the %s transport", trname);
/* If "create_file" is set, check that a valid option is given, and set the
integer variable. */
else
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"invalid value given for \"create_file\" for the %s transport: '%s'",
- tblock->name, s);
+ trname, s);
ob->create_file = val;
}
transport_instance *
check_file_format(int cfd, transport_instance *tblock, address_item *addr)
{
-const uschar *format =
- ((appendfile_transport_options_block *)(tblock->options_block))->file_format;
+appendfile_transport_options_block * ob = tblock->drinst.options_block;
+const uschar * format = ob->file_format;
uschar data[256];
int len = read(cfd, data, sizeof(data));
int sep = 0;
if (match && tp)
{
- for (transport_instance * tt = transports; tt; tt = tt->next)
- if (Ustrcmp(tp, tt->name) == 0)
+ for (transport_instance * tt = transports; tt; tt = tt->drinst.next)
+ if (Ustrcmp(tp, tt->drinst.name) == 0)
{
DEBUG(D_transport)
- debug_printf("file format -> %s transport\n", tt->name);
+ debug_printf("file format -> %s transport\n", tt->drinst.name);
return tt;
}
addr->basic_errno = ERRNO_BADTRANSPORT;
off_t
check_dir_size(const uschar * dirname, int * countptr, const pcre2_code * re)
{
-DIR *dir;
+DIR * dir;
off_t sum = 0;
-int count = *countptr;
+int count = *countptr, lcount = REGEX_LOOPCOUNT_STORE_RESET;
+rmark reset_point = store_mark();
if (!(dir = exim_opendir(dirname))) return 0;
-for (struct dirent *ent; ent = readdir(dir); )
+for (struct dirent * ent; ent = readdir(dir); )
{
uschar * path, * name = US ent->d_name;
struct stat statbuf;
if (Ustrcmp(name, ".") == 0 || Ustrcmp(name, "..") == 0) continue;
count++;
+ if (--lcount == 0)
+ {
+ store_reset(reset_point); reset_point = store_mark();
+ lcount = REGEX_LOOPCOUNT_STORE_RESET;
+ }
/* If there's a regex, try to find the size using it */
debug_printf("check_dir_size: dir=%s sum=" OFF_T_FMT " count=%d\n", dirname,
sum, count);
+store_reset(reset_point);
*countptr = count;
return sum;
}
transport_instance *tblock, /* data for this instantiation */
address_item *addr) /* address we are working on */
{
-appendfile_transport_options_block *ob =
- (appendfile_transport_options_block *)(tblock->options_block);
+appendfile_transport_options_block * ob = tblock->drinst.options_block;
+const uschar * trname = tblock->drinst.name;
struct stat statbuf;
const uschar * deliver_dir;
-uschar *fdname = NULL;
-uschar *filename = NULL;
-uschar *hitchname = NULL;
-uschar *dataname = NULL;
-uschar *lockname = NULL;
-uschar *newname = NULL;
-uschar *nametag = NULL;
-uschar *cr = US"";
-uschar *filecount_msg = US"";
-uschar *path;
+uschar * fdname = NULL, * filename = NULL;
+uschar * hitchname = NULL, * dataname = NULL;
+uschar * lockname = NULL, * newname = NULL;
+uschar * nametag = NULL, * cr = US"";
+uschar * filecount_msg = US"";
+uschar * path;
struct utimbuf times;
struct timeval msg_tv;
-BOOL disable_quota = FALSE;
-BOOL isdirectory = FALSE;
-BOOL isfifo = FALSE;
+BOOL disable_quota = FALSE, isdirectory = FALSE, isfifo = FALSE;
BOOL wait_for_tick = FALSE;
uid_t uid = geteuid(); /* See note above */
gid_t gid = getegid();
int mbformat;
-int mode = (addr->mode > 0) ? addr->mode : ob->mode;
-off_t saved_size = -1;
-off_t mailbox_size = ob->mailbox_size_value;
+int mode = addr->mode > 0 ? addr->mode : ob->mode;
+off_t saved_size = -1, mailbox_size = ob->mailbox_size_value;
int mailbox_filecount = ob->mailbox_filecount_value;
-int hd = -1;
-int fd = -1;
-int yield = FAIL;
-int i;
+int hd = -1, fd = -1, yield = FAIL, i;
#ifdef SUPPORT_MBX
int save_fd = 0;
{
if (!(fdname = ob->filename))
{
+ GET_OPTION("directory");
fdname = ob->dirname;
isdirectory = TRUE;
}
if (!fdname)
{
addr->message = string_sprintf("Mandatory file or directory option "
- "missing from %s transport", tblock->name);
+ "missing from %s transport", trname);
goto ret_panic;
}
}
{
addr->message = string_sprintf("mail%s_format requires \"directory\" "
"to be specified for the %s transport",
- ob->maildir_format ? "dir" : "store", tblock->name);
+ ob->maildir_format ? "dir" : "store", trname);
goto ret_panic;
}
if (!(path = expand_string(fdname)))
{
addr->message = string_sprintf("Expansion of \"%s\" (file or directory "
- "name for %s transport) failed: %s", fdname, tblock->name,
+ "name for %s transport) failed: %s", fdname, trname,
expand_string_message);
goto ret_panic;
}
{
DEBUG(D_transport)
debug_printf("*** delivery by %s transport bypassed by -N option\n",
- tblock->name);
+ trname);
addr->transport_return = OK;
return FALSE;
}
&& ob->create_file == create_belowhome)
if (is_tainted(path))
{
- DEBUG(D_transport) debug_printf("de-tainting path '%s'\n", path);
+ DEBUG(D_transport) debug_printf("below-home: de-tainting path '%s'\n", path);
path = string_copy_taint(path, GET_UNTAINTED);
}
addr->message =
string_sprintf("failed to create directories for %s: %s", path,
exim_errstr(errno));
- DEBUG(D_transport) debug_printf("%s transport: %s\n", tblock->name, path);
+ DEBUG(D_transport) debug_printf("%s transport: %s\n", trname, path);
return FALSE;
}
}
{
if (tt)
{
+ transport_info * ti = tt->drinst.info;
set_process_info("delivering %s to %s using %s", message_id,
- addr->local_part, tt->name);
+ addr->local_part, tt->drinst.name);
debug_print_string(tt->debug_string);
addr->transport = tt;
- (tt->info->code)(tt, addr);
+ (ti->code)(tt, addr);
}
return FALSE;
}
if (is_tainted(path))
if (ob->create_file == create_belowhome)
{
- DEBUG(D_transport) debug_printf("de-tainting path '%s'\n", path);
+ DEBUG(D_transport) debug_printf("below-home: de-tainting path '%s'\n", path);
path = string_copy_taint(path, GET_UNTAINTED);
}
else
/* Use an explicitly configured directory if set */
+ GET_OPTION("quota_directory");
if (ob->quota_directory)
{
if (!(check_path = expand_string(ob->quota_directory)))
{
addr->message = string_sprintf("Expansion of \"%s\" (quota_directory "
"name for %s transport) failed: %s", ob->quota_directory,
- tblock->name, expand_string_message);
+ trname, expand_string_message);
goto ret_panic;
}
DEBUG(D_transport)
debug_printf("delivering in maildir format in %s\n", path);
+ GET_OPTION("maildir_tag");
nametag = ob->maildir_tag;
/* Check that nametag expands successfully; a hard failure causes a panic
if (nametag && !expand_string(nametag) && !f.expand_string_forcedfail)
{
addr->message = string_sprintf("Expansion of \"%s\" (maildir_tag "
- "for %s transport) failed: %s", nametag, tblock->name,
+ "for %s transport) failed: %s", nametag, trname,
expand_string_message);
goto ret_panic;
}
{
addr->basic_errno = errno;
addr->message = string_sprintf("fdopen of %s ("
- "for %s transport) failed", filename, tblock->name);
+ "for %s transport) failed", filename, trname);
(void)close(fd);
Uunlink(filename);
goto ret_panic;
/* Write the envelope file, then close it. */
+ GET_OPTION("mailstore_prefix");
if (ob->mailstore_prefix)
{
- uschar *s = expand_string(ob->mailstore_prefix);
+ uschar * s = expand_string(ob->mailstore_prefix);
if (!s)
{
if (!f.expand_string_forcedfail)
{
addr->message = string_sprintf("Expansion of \"%s\" (mailstore "
"prefix for %s transport) failed: %s", ob->mailstore_prefix,
- tblock->name, expand_string_message);
+ trname, expand_string_message);
(void)fclose(env_file);
Uunlink(filename);
goto ret_panic;
for (address_item * taddr = addr; taddr; taddr = taddr->next)
fprintf(env_file, "%s@%s\n", taddr->local_part, taddr->domain);
+ GET_OPTION("mailstore_suffix");
if (ob->mailstore_suffix)
{
- uschar *s = expand_string(ob->mailstore_suffix);
+ uschar * s = expand_string(ob->mailstore_suffix);
if (!s)
{
if (!f.expand_string_forcedfail)
{
addr->message = string_sprintf("Expansion of \"%s\" (mailstore "
"suffix for %s transport) failed: %s", ob->mailstore_suffix,
- tblock->name, expand_string_message);
+ trname, expand_string_message);
(void)fclose(env_file);
Uunlink(filename);
goto ret_panic;
/* Write any configured prefix text first */
-if (yield == OK && ob->message_prefix && *ob->message_prefix)
+if (yield == OK)
{
- uschar *prefix = expand_string(ob->message_prefix);
- if (!prefix)
- {
- errno = ERRNO_EXPANDFAIL;
- addr->transport_return = PANIC;
- addr->message = string_sprintf("Expansion of \"%s\" (prefix for %s "
- "transport) failed", ob->message_prefix, tblock->name);
- yield = DEFER;
- }
- else if (!transport_write_string(fd, "%s", prefix)) yield = DEFER;
+ uschar * prefix = ob->message_prefix;
+ GET_OPTION("message_prefix");
+ if (prefix && *prefix)
+ if (!(prefix = expand_string(prefix)))
+ {
+ errno = ERRNO_EXPANDFAIL;
+ addr->transport_return = PANIC;
+ addr->message = string_sprintf("Expansion of \"%s\" (prefix for %s "
+ "transport) failed", ob->message_prefix, trname);
+ yield = DEFER;
+ }
+ else if (!transport_write_string(fd, "%s", prefix))
+ yield = DEFER;
}
/* If the use_bsmtp option is on, we need to write SMTP prefix information. The
/* Now a configured suffix. */
-if (yield == OK && ob->message_suffix && *ob->message_suffix)
+if (yield == OK)
{
- uschar *suffix = expand_string(ob->message_suffix);
- if (!suffix)
- {
- errno = ERRNO_EXPANDFAIL;
- addr->transport_return = PANIC;
- addr->message = string_sprintf("Expansion of \"%s\" (suffix for %s "
- "transport) failed", ob->message_suffix, tblock->name);
- yield = DEFER;
- }
- else if (!transport_write_string(fd, "%s", suffix)) yield = DEFER;
+ uschar * suffix = ob->message_suffix;
+ GET_OPTION("message_suffix");
+ if (suffix && *suffix)
+ if (!(suffix = expand_string(suffix)))
+ {
+ errno = ERRNO_EXPANDFAIL;
+ addr->transport_return = PANIC;
+ addr->message = string_sprintf("Expansion of \"%s\" (suffix for %s "
+ "transport) failed", ob->message_suffix, trname);
+ yield = DEFER;
+ }
+ else if (!transport_write_string(fd, "%s", suffix))
+ yield = DEFER;
}
/* If batch smtp, write the terminating dot. */
addr->transport_return = PANIC;
addr->message = string_sprintf("Expansion of \"%s\" "
"(directory_file for %s transport) failed: %s",
- ob->dirfilename, tblock->name, expand_string_message);
+ ob->dirfilename, trname, expand_string_message);
goto RETURN;
}
tainted_ret_panic:
addr->message = string_sprintf("Tainted '%s' (file or directory "
- "name for %s transport) not permitted", path, tblock->name);
+ "name for %s transport) not permitted", path, trname);
ret_panic:
addr->transport_return = PANIC;
return FALSE;
}
+
+
+
+# ifdef DYNLOOKUP
+# define appendfile_transport_info _transport_info
+# endif
+
+transport_info appendfile_transport_info = {
+.drinfo = {
+ .driver_name = US"appendfile",
+ .options = appendfile_transport_options,
+ .options_count = &appendfile_transport_options_count,
+ .options_block = &appendfile_transport_option_defaults, /* private options defaults */
+ .options_len = sizeof(appendfile_transport_options_block),
+ .init = appendfile_transport_init,
+# ifdef DYNLOOKUP
+ .dyn_magic = TRANSPORT_MAGIC,
+# endif
+ },
+.code = appendfile_transport_entry,
+.tidyup = NULL,
+.closedown = NULL,
+.local = TRUE
+};
+
#endif /*!MACRO_PREDEF*/
+#endif /*TRANSPORT_APPENDFILE*/
/* End of transport/appendfile.c */