X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/e0eb00cd78f2dbf91aba5dffa579177b1e1815a1..9669c6e06fa8441557a70ba0759eda19287681ad:/src/src/transports/autoreply.c diff --git a/src/src/transports/autoreply.c b/src/src/transports/autoreply.c index a90a6852e..9decfbaea 100644 --- a/src/src/transports/autoreply.c +++ b/src/src/transports/autoreply.c @@ -2,7 +2,7 @@ * 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. */ @@ -62,6 +62,17 @@ address can appear in the tables drtables.c. */ 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 = { @@ -143,7 +154,6 @@ Returns: expanded string if expansion succeeds; static uschar * checkexpand(uschar *s, address_item *addr, uschar *name, int type) { -uschar *t; uschar *ss = expand_string(s); if (ss == NULL) @@ -154,15 +164,16 @@ 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; } @@ -187,7 +198,7 @@ Returns: nothing */ static void -check_never_mail(uschar **listptr, uschar *never_mail) +check_never_mail(uschar **listptr, const uschar *never_mail) { uschar *s = *listptr; @@ -266,7 +277,6 @@ autoreply_transport_entry( { 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; @@ -279,7 +289,7 @@ uschar *message_id = 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 = @@ -335,33 +345,22 @@ else 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) @@ -377,11 +376,11 @@ else /* 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 " @@ -389,11 +388,11 @@ if (ob->never_mail != NULL) 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"); @@ -403,7 +402,7 @@ if (ob->never_mail != NULL) /* 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", @@ -419,7 +418,7 @@ recipient, the effect might not be quite as envisaged. If once_file_size is 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; @@ -427,7 +426,7 @@ if (oncelog != NULL && *oncelog != 0 && to != NULL) if (ob->once_file_size > 0) { - uschar *p; + uschar * nextp; struct stat statbuf; cache_fd = Uopen(oncelog, O_CREAT|O_RDWR, ob->mode); @@ -464,18 +463,16 @@ if (oncelog != NULL && *oncelog != 0 && to != NULL) 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; } } @@ -484,8 +481,12 @@ if (oncelog != NULL && *oncelog != 0 && to != NULL) 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 " @@ -509,10 +510,9 @@ if (oncelog != NULL && *oncelog != 0 && to != NULL) 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; } } @@ -521,9 +521,10 @@ if (oncelog != NULL && *oncelog != 0 && to != NULL) 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; @@ -543,10 +544,10 @@ if (oncelog != NULL && *oncelog != 0 && to != NULL) /* 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 " @@ -567,6 +568,7 @@ if (pid < 0) 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; } @@ -574,37 +576,37 @@ if (pid < 0) 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; @@ -613,21 +615,20 @@ limit, some systems do not like headers growing beyond recognition. 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 *)); @@ -635,31 +636,31 @@ if (h != NULL || message_id != NULL) } 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) { @@ -668,13 +669,13 @@ if (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); } @@ -690,6 +691,19 @@ if (return_message) 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) { @@ -698,30 +712,23 @@ if (return_message) 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 @@ -740,30 +747,32 @@ if (cache_fd >= 0) { 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 */ @@ -785,7 +794,6 @@ try will skip, of course. However, if there were no recipients in the message, we do not fail. */ if (rc != 0) - { if (rc == EXIT_NORECIPIENTS) { DEBUG(D_any) debug_printf("%s transport: message contained no recipients\n", @@ -798,7 +806,6 @@ if (rc != 0) "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 @@ -809,7 +816,7 @@ file opened for appending, in order to avoid interleaving of output from 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) @@ -818,37 +825,37 @@ if (logfile != NULL) 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); @@ -864,7 +871,7 @@ if (logfile != NULL) } 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); @@ -872,4 +879,5 @@ DEBUG(D_transport) debug_printf("%s transport succeeded\n", tblock->name); return FALSE; } +#endif /*!MACRO_PREDEF*/ /* End of transport/autoreply.c */