* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
int autoreply_transport_options_count =
sizeof(autoreply_transport_options)/sizeof(optionlist);
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+autoreply_transport_options_block autoreply_transport_option_defaults = {0};
+void autoreply_transport_init(transport_instance *tblock) {}
+BOOL autoreply_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
+
+#else /*!MACRO_PREDEF*/
+
+
/* Default private options block for the autoreply transport. */
autoreply_transport_options_block autoreply_transport_option_defaults = {
static uschar *
checkexpand(uschar *s, address_item *addr, uschar *name, int type)
{
-uschar *t;
uschar *ss = expand_string(s);
if (ss == NULL)
return NULL;
}
-if (type != cke_text) for (t = ss; *t != 0; t++)
+if (type != cke_text) for (uschar * t = ss; *t != 0; t++)
{
int c = *t;
+ const uschar * sp;
if (mac_isprint(c)) continue;
if (type == cke_hdr && c == '\n' && (t[1] == ' ' || t[1] == '\t')) continue;
- s = string_printing(s);
+ sp = string_printing(s);
addr->transport_return = FAIL;
addr->message = string_sprintf("Expansion of \"%s\" in %s transport "
- "contains non-printing character %d", s, name, c);
+ "contains non-printing character %d", sp, name, c);
return NULL;
}
*/
static void
-check_never_mail(uschar **listptr, uschar *never_mail)
+check_never_mail(uschar **listptr, const uschar *never_mail)
{
uschar *s = *listptr;
{
int fd, pid, rc;
int cache_fd = -1;
-int log_fd = -1;
int cache_size = 0;
int add_size = 0;
EXIM_DB *dbm_file = NULL;
header_line *h;
time_t now = time(NULL);
time_t once_repeat_sec = 0;
-FILE *f;
+FILE *fp;
FILE *ff = NULL;
autoreply_transport_options_block *ob =
file_expand = ob->file_expand;
return_message = ob->return_message;
- if ((from != NULL &&
- (from = checkexpand(from, addr, tblock->name, cke_hdr)) == NULL) ||
- (reply_to != NULL &&
- (reply_to = checkexpand(reply_to, addr, tblock->name, cke_hdr)) == NULL) ||
- (to != NULL &&
- (to = checkexpand(to, addr, tblock->name, cke_hdr)) == NULL) ||
- (cc != NULL &&
- (cc = checkexpand(cc, addr, tblock->name, cke_hdr)) == NULL) ||
- (bcc != NULL &&
- (bcc = checkexpand(bcc, addr, tblock->name, cke_hdr)) == NULL) ||
- (subject != NULL &&
- (subject = checkexpand(subject, addr, tblock->name, cke_hdr)) == NULL) ||
- (headers != NULL &&
- (headers = checkexpand(headers, addr, tblock->name, cke_text)) == NULL) ||
- (text != NULL &&
- (text = checkexpand(text, addr, tblock->name, cke_text)) == NULL) ||
- (file != NULL &&
- (file = checkexpand(file, addr, tblock->name, cke_file)) == NULL) ||
- (logfile != NULL &&
- (logfile = checkexpand(logfile, addr, tblock->name, cke_file)) == NULL) ||
- (oncelog != NULL &&
- (oncelog = checkexpand(oncelog, addr, tblock->name, cke_file)) == NULL) ||
- (oncerepeat != NULL &&
- (oncerepeat = checkexpand(oncerepeat, addr, tblock->name, cke_file)) == NULL))
+ if ( from && !(from = checkexpand(from, addr, tblock->name, cke_hdr))
+ || reply_to && !(reply_to = checkexpand(reply_to, addr, tblock->name, cke_hdr))
+ || to && !(to = checkexpand(to, addr, tblock->name, cke_hdr))
+ || cc && !(cc = checkexpand(cc, addr, tblock->name, cke_hdr))
+ || bcc && !(bcc = checkexpand(bcc, addr, tblock->name, cke_hdr))
+ || subject && !(subject = checkexpand(subject, addr, tblock->name, cke_hdr))
+ || headers && !(headers = checkexpand(headers, addr, tblock->name, cke_text))
+ || text && !(text = checkexpand(text, addr, tblock->name, cke_text))
+ || file && !(file = checkexpand(file, addr, tblock->name, cke_file))
+ || logfile && !(logfile = checkexpand(logfile, addr, tblock->name, cke_file))
+ || oncelog && !(oncelog = checkexpand(oncelog, addr, tblock->name, cke_file))
+ || oncerepeat && !(oncerepeat = checkexpand(oncerepeat, addr, tblock->name, cke_file))
+ )
return FALSE;
- if (oncerepeat != NULL)
+ if (oncerepeat)
{
once_repeat_sec = readconf_readtime(oncerepeat, 0, FALSE);
if (once_repeat_sec < 0)
/* If the never_mail option is set, we have to scan all the recipients and
remove those that match. */
-if (ob->never_mail != NULL)
+if (ob->never_mail)
{
- uschar *never_mail = expand_string(ob->never_mail);
+ const uschar *never_mail = expand_string(ob->never_mail);
- if (never_mail == NULL)
+ if (!never_mail)
{
addr->transport_return = FAIL;
addr->message = string_sprintf("Failed to expand \"%s\" for "
return FALSE;
}
- if (to != NULL) check_never_mail(&to, never_mail);
- if (cc != NULL) check_never_mail(&cc, never_mail);
- if (bcc != NULL) check_never_mail(&bcc, never_mail);
+ if (to) check_never_mail(&to, never_mail);
+ if (cc) check_never_mail(&cc, never_mail);
+ if (bcc) check_never_mail(&bcc, never_mail);
- if (to == NULL && cc == NULL && bcc == NULL)
+ if (!to && !cc && !bcc)
{
DEBUG(D_transport)
debug_printf("*** all recipients removed by never_mail\n");
/* If the -N option is set, can't do any more. */
-if (dont_deliver)
+if (f.dont_deliver)
{
DEBUG(D_transport)
debug_printf("*** delivery by %s transport bypassed by -N option\n",
set, instead of a dbm file, we use a regular file containing a circular buffer
recipient cache. */
-if (oncelog != NULL && *oncelog != 0 && to != NULL)
+if (oncelog && *oncelog != 0 && to)
{
time_t then = 0;
if (ob->once_file_size > 0)
{
- uschar *p;
+ uschar * nextp;
struct stat statbuf;
cache_fd = Uopen(oncelog, O_CREAT|O_RDWR, ob->mode);
zero. If we find a match, put the time into "then", and the place where it
was found into "cache_time". Otherwise, "then" is left at zero. */
- p = cache_buff;
- while (p < cache_buff + cache_size)
+ for (uschar * p = cache_buff; p < cache_buff + cache_size; p = nextp)
{
uschar *s = p + sizeof(time_t);
- uschar *nextp = s + Ustrlen(s) + 1;
+ nextp = s + Ustrlen(s) + 1;
if (Ustrcmp(to, s) == 0)
{
memcpy(&then, p, sizeof(time_t));
cache_time = p;
break;
}
- p = nextp;
}
}
else
{
EXIM_DATUM key_datum, result_datum;
- EXIM_DBOPEN(oncelog, O_RDWR|O_CREAT, ob->mode, &dbm_file);
- if (dbm_file == NULL)
+ uschar * dirname = string_copy(oncelog);
+ uschar * s;
+
+ if ((s = Ustrrchr(dirname, '/'))) *s = '\0';
+ EXIM_DBOPEN(oncelog, dirname, O_RDWR|O_CREAT, ob->mode, &dbm_file);
+ if (!dbm_file)
{
addr->transport_return = DEFER;
addr->message = string_sprintf("Failed to open %s file %s when sending "
can be abolished. */
if (EXIM_DATUM_SIZE(result_datum) == sizeof(time_t))
- {
memcpy(&then, EXIM_DATUM_DATA(result_datum), sizeof(time_t));
- }
- else then = now;
+ else
+ then = now;
}
}
if (then != 0 && (once_repeat_sec <= 0 || now - then < once_repeat_sec))
{
+ int log_fd;
DEBUG(D_transport) debug_printf("message previously sent to %s%s\n", to,
(once_repeat_sec > 0)? " and repeat time not reached" : "");
- log_fd = Uopen(logfile, O_WRONLY|O_APPEND|O_CREAT, ob->mode);
+ log_fd = logfile ? Uopen(logfile, O_WRONLY|O_APPEND|O_CREAT, ob->mode) : -1;
if (log_fd >= 0)
{
uschar *ptr = log_buffer;
/* We are going to send a message. Ensure any requested file is available. */
-if (file != NULL)
+if (file)
{
ff = Ufopen(file, "rb");
- if (ff == NULL && !ob->file_optional)
+ if (!ff && !ob->file_optional)
{
addr->transport_return = DEFER;
addr->message = string_sprintf("Failed to open file %s when sending "
addr->message = string_sprintf("Failed to create child process to send "
"message from %s transport: %s", tblock->name, strerror(errno));
DEBUG(D_transport) debug_printf("%s\n", addr->message);
+ if (dbm_file) EXIM_DBCLOSE(dbm_file);
return FALSE;
}
as the -t option is used. The "headers" stuff *must* be last in case there
are newlines in it which might, if placed earlier, screw up other headers. */
-f = fdopen(fd, "wb");
+fp = fdopen(fd, "wb");
-if (from != NULL) fprintf(f, "From: %s\n", from);
-if (reply_to != NULL) fprintf(f, "Reply-To: %s\n", reply_to);
-if (to != NULL) fprintf(f, "To: %s\n", to);
-if (cc != NULL) fprintf(f, "Cc: %s\n", cc);
-if (bcc != NULL) fprintf(f, "Bcc: %s\n", bcc);
-if (subject != NULL) fprintf(f, "Subject: %s\n", subject);
+if (from) fprintf(fp, "From: %s\n", from);
+if (reply_to) fprintf(fp, "Reply-To: %s\n", reply_to);
+if (to) fprintf(fp, "To: %s\n", to);
+if (cc) fprintf(fp, "Cc: %s\n", cc);
+if (bcc) fprintf(fp, "Bcc: %s\n", bcc);
+if (subject) fprintf(fp, "Subject: %s\n", subject);
/* Generate In-Reply-To from the message_id header; there should
always be one, but code defensively. */
-for (h = header_list; h != NULL; h = h->next)
+for (h = header_list; h; h = h->next)
if (h->type == htype_id) break;
-if (h != NULL)
+if (h)
{
message_id = Ustrchr(h->text, ':') + 1;
while (isspace(*message_id)) message_id++;
- fprintf(f, "In-Reply-To: %s", message_id);
+ fprintf(fp, "In-Reply-To: %s", message_id);
}
/* Generate a References header if there is at least one of Message-ID:,
References:, or In-Reply-To: (see RFC 2822). */
-for (h = header_list; h != NULL; h = h->next)
+for (h = header_list; h; h = h->next)
if (h->type != htype_old && strncmpic(US"References:", h->text, 11) == 0)
break;
-if (h == NULL)
- for (h = header_list; h != NULL; h = h->next)
+if (!h)
+ for (h = header_list; h; h = h->next)
if (h->type != htype_old && strncmpic(US"In-Reply-To:", h->text, 12) == 0)
break;
Keep the first message ID for the thread root and the last few for
the position inside the thread, up to a maximum of 12 altogether. */
-if (h != NULL || message_id != NULL)
+if (h || message_id)
{
- fprintf(f, "References:");
- if (h != NULL)
+ fprintf(fp, "References:");
+ if (h)
{
uschar *s, *id, *error;
uschar *referenced_ids[12];
int reference_count = 0;
- int i;
s = Ustrchr(h->text, ':') + 1;
- parse_allow_group = FALSE;
+ f.parse_allow_group = FALSE;
while (*s != 0 && (s = parse_message_id(s, &id, &error)) != NULL)
{
- if (reference_count == sizeof(referenced_ids)/sizeof(uschar *))
+ if (reference_count == nelem(referenced_ids))
{
memmove(referenced_ids + 1, referenced_ids + 2,
sizeof(referenced_ids) - 2*sizeof(uschar *));
}
else referenced_ids[reference_count++] = id;
}
- for (i = 0; i < reference_count; ++i) fprintf(f, " %s", referenced_ids[i]);
+ for (int i = 0; i < reference_count; ++i) fprintf(fp, " %s", referenced_ids[i]);
}
/* The message id will have a newline on the end of it. */
- if (message_id != NULL) fprintf(f, " %s", message_id);
- else fprintf(f, "\n");
+ if (message_id) fprintf(fp, " %s", message_id);
+ else fprintf(fp, "\n");
}
/* Add an Auto-Submitted: header */
-fprintf(f, "Auto-Submitted: auto-replied\n");
+fprintf(fp, "Auto-Submitted: auto-replied\n");
/* Add any specially requested headers */
-if (headers != NULL) fprintf(f, "%s\n", headers);
-fprintf(f, "\n");
+if (headers) fprintf(fp, "%s\n", headers);
+fprintf(fp, "\n");
-if (text != NULL)
+if (text)
{
- fprintf(f, "%s", CS text);
- if (text[Ustrlen(text)-1] != '\n') fprintf(f, "\n");
+ fprintf(fp, "%s", CS text);
+ if (text[Ustrlen(text)-1] != '\n') fprintf(fp, "\n");
}
-if (ff != NULL)
+if (ff)
{
while (Ufgets(big_buffer, big_buffer_size, ff) != NULL)
{
uschar *s = expand_string(big_buffer);
DEBUG(D_transport)
{
- if (s == NULL)
+ if (!s)
debug_printf("error while expanding line from file:\n %s\n %s\n",
big_buffer, expand_string_message);
}
- fprintf(f, "%s", (s == NULL)? CS big_buffer : CS s);
+ fprintf(fp, "%s", s ? CS s : CS big_buffer);
}
- else fprintf(f, "%s", CS big_buffer);
+ else fprintf(fp, "%s", CS big_buffer);
}
(void) fclose(ff);
}
US"------ This is a copy of the body of the message, without the headers.\n"
:
US"------ This is a copy of the message, including all the headers.\n";
+ transport_ctx tctx = {
+ .u = {.fd = fileno(fp)},
+ .tblock = tblock,
+ .addr = addr,
+ .check_string = NULL,
+ .escape_string = NULL,
+ .options = (tblock->body_only ? topt_no_headers : 0)
+ | (tblock->headers_only ? topt_no_body : 0)
+ | (tblock->return_path_add ? topt_add_return_path : 0)
+ | (tblock->delivery_date_add ? topt_add_delivery_date : 0)
+ | (tblock->envelope_to_add ? topt_add_envelope_to : 0)
+ | topt_not_socket
+ };
if (bounce_return_size_limit > 0 && !tblock->headers_only)
{
DELIVER_IN_BUFFER_SIZE;
if (fstat(deliver_datafile, &statbuf) == 0 && statbuf.st_size > max)
{
- fprintf(f, "\n%s"
+ fprintf(fp, "\n%s"
"------ The body of the message is " OFF_T_FMT " characters long; only the first\n"
"------ %d or so are included here.\n\n", rubric, statbuf.st_size,
(max/1000)*1000);
}
- else fprintf(f, "\n%s\n", rubric);
+ else fprintf(fp, "\n%s\n", rubric);
}
- else fprintf(f, "\n%s\n", rubric);
+ else fprintf(fp, "\n%s\n", rubric);
- fflush(f);
+ fflush(fp);
transport_count = 0;
- transport_write_message(addr, fileno(f),
- (tblock->body_only? topt_no_headers : 0) |
- (tblock->headers_only? topt_no_body : 0) |
- (tblock->return_path_add? topt_add_return_path : 0) |
- (tblock->delivery_date_add? topt_add_delivery_date : 0) |
- (tblock->envelope_to_add? topt_add_envelope_to : 0),
- bounce_return_size_limit, tblock->add_headers, tblock->remove_headers,
- NULL, NULL, tblock->rewrite_rules, tblock->rewrite_existflags);
+ transport_write_message(&tctx, bounce_return_size_limit);
}
/* End the message and wait for the child process to end; no timeout. */
-(void)fclose(f);
+(void)fclose(fp);
rc = child_close(pid, 0);
/* Update the "sent to" log whatever the yield. This errs on the side of
{
uschar *from = cache_buff;
int size = cache_size;
- (void)lseek(cache_fd, 0, SEEK_SET);
- if (cache_time == NULL)
+ if (lseek(cache_fd, 0, SEEK_SET) == 0)
{
- cache_time = from + size;
- memcpy(cache_time + sizeof(time_t), to, add_size - sizeof(time_t));
- size += add_size;
-
- if (cache_size > 0 && size > ob->once_file_size)
+ if (!cache_time)
{
- from += sizeof(time_t) + Ustrlen(from + sizeof(time_t)) + 1;
- size -= (from - cache_buff);
+ cache_time = from + size;
+ memcpy(cache_time + sizeof(time_t), to, add_size - sizeof(time_t));
+ size += add_size;
+
+ if (cache_size > 0 && size > ob->once_file_size)
+ {
+ from += sizeof(time_t) + Ustrlen(from + sizeof(time_t)) + 1;
+ size -= (from - cache_buff);
+ }
}
- }
- memcpy(cache_time, &now, sizeof(time_t));
- if(write(cache_fd, from, size) != size)
- DEBUG(D_transport) debug_printf("Problem writing cache file %s for %s "
- "transport\n", oncelog, tblock->name);
+ memcpy(cache_time, &now, sizeof(time_t));
+ if(write(cache_fd, from, size) != size)
+ DEBUG(D_transport) debug_printf("Problem writing cache file %s for %s "
+ "transport\n", oncelog, tblock->name);
+ }
}
/* Update DBM file */
-else if (dbm_file != NULL)
+else if (dbm_file)
{
EXIM_DATUM key_datum, value_datum;
EXIM_DATUM_INIT(key_datum); /* Some DBM libraries need to have */
message, we do not fail. */
if (rc != 0)
- {
if (rc == EXIT_NORECIPIENTS)
{
DEBUG(D_any) debug_printf("%s transport: message contained no recipients\n",
"transport (%d)", tblock->name, rc);
goto END_OFF;
}
- }
/* Log the sending of the message if successful and required. If the file
fails to open, it's hard to know what to do. We cannot write to the Exim
different processes. The log_buffer can be used exactly as for main log
writing. */
-if (logfile != NULL)
+if (logfile)
{
int log_fd = Uopen(logfile, O_WRONLY|O_APPEND|O_CREAT, ob->mode);
if (log_fd >= 0)
DEBUG(D_transport) debug_printf("logging message details\n");
sprintf(CS ptr, "%s\n", tod_stamp(tod_log));
while(*ptr) ptr++;
- if (from != NULL)
+ if (from)
{
(void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
" From: %s\n", from);
while(*ptr) ptr++;
}
- if (to != NULL)
+ if (to)
{
(void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
" To: %s\n", to);
while(*ptr) ptr++;
}
- if (cc != NULL)
+ if (cc)
{
(void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
" Cc: %s\n", cc);
while(*ptr) ptr++;
}
- if (bcc != NULL)
+ if (bcc)
{
(void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
" Bcc: %s\n", bcc);
while(*ptr) ptr++;
}
- if (subject != NULL)
+ if (subject)
{
(void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
" Subject: %s\n", subject);
while(*ptr) ptr++;
}
- if (headers != NULL)
+ if (headers)
{
(void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
" %s\n", headers);
}
END_OFF:
-if (dbm_file != NULL) EXIM_DBCLOSE(dbm_file);
+if (dbm_file) EXIM_DBCLOSE(dbm_file);
if (cache_fd > 0) (void)close(cache_fd);
DEBUG(D_transport) debug_printf("%s transport succeeded\n", tblock->name);
return FALSE;
}
+#endif /*!MACRO_PREDEF*/
/* End of transport/autoreply.c */