X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/059ec3d9952740285fb1ebf47961b8aca2eb1b4a..0a49a7a4f1090b6f1ce1d0f9d969804c9226b53e:/src/src/filter.c diff --git a/src/src/filter.c b/src/src/filter.c index 0e8e790a4..b1fcd40b0 100644 --- a/src/src/filter.c +++ b/src/src/filter.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/filter.c,v 1.1 2004/10/07 10:39:01 ph10 Exp $ */ +/* $Cambridge: exim/src/src/filter.c,v 1.15 2009/11/16 19:50:37 nm4 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2004 */ +/* Copyright (c) University of Cambridge 1995 - 2009 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -1044,6 +1044,13 @@ switch (command) case elif_command: case else_command: case endif_command: + if (seen_force || noerror_force) + { + *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" " + "near line %d is not followed by a command", line_number); + yield = FALSE; + } + if (expect_endif > 0) had_else_endif = (command == elif_command)? had_elif : (command == else_command)? had_else : had_endif; @@ -1316,6 +1323,12 @@ switch (command) case seen_command: case unseen_command: + if (*ptr == 0) + { + *error_pointer = string_sprintf("\"seen\" or \"unseen\" " + "near line %d is not followed by a command", line_number); + yield = FALSE; + } if (seen_force) { *error_pointer = string_sprintf("\"seen\" or \"unseen\" repeated " @@ -1331,6 +1344,12 @@ switch (command) /* So does noerror */ case noerror_command: + if (*ptr == 0) + { + *error_pointer = string_sprintf("\"noerror\" " + "near line %d is not followed by a command", line_number); + yield = FALSE; + } noerror_force = TRUE; was_noerror = TRUE; break; @@ -1414,7 +1433,7 @@ Returns: TRUE if the condition is met static BOOL test_condition(condition_block *c, BOOL toplevel) { -BOOL yield; +BOOL yield = FALSE; const pcre *re; uschar *exp[2], *p, *pp; const uschar *regcomp_error = NULL; @@ -1462,7 +1481,7 @@ switch (c->type) and filter testing and verification. */ case cond_firsttime: - yield = filter_test != NULL || message_id[0] == 0 || deliver_firsttime; + yield = filter_test != FTEST_NONE || message_id[0] == 0 || deliver_firsttime; break; /* Only TRUE if a message is actually being processed; FALSE for address @@ -1503,7 +1522,7 @@ switch (c->type) if (filter_thisaddress != NULL) { - if ((filter_test != NULL && debug_selector != 0) || + if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) { indent(); @@ -1578,7 +1597,7 @@ switch (c->type) case cond_matches: case cond_MATCHES: - if ((filter_test != NULL && debug_selector != 0) || + if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) { debug_printf("Match expanded arguments:\n"); @@ -1621,7 +1640,7 @@ switch (c->type) break; } -if ((filter_test != NULL && debug_selector != 0) || +if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) { indent(); @@ -1729,7 +1748,7 @@ while (commands != NULL) } filter_n[n[1]] += n[0]; - if (filter_test != NULL) printf("Add %d to n%d\n", n[0], n[1]); + if (filter_test != FTEST_NONE) printf("Add %d to n%d\n", n[0], n[1]); break; /* A deliver command's argument must be a valid address. Its optional @@ -1777,7 +1796,7 @@ while (commands != NULL) /* Test case: report what would happen */ - if (filter_test != NULL) + if (filter_test != FTEST_NONE) { indent(); printf("%seliver message to: %s%s%s%s\n", @@ -1818,7 +1837,7 @@ while (commands != NULL) /* Test case: report what would happen */ - if (filter_test != NULL) + if (filter_test != FTEST_NONE) { indent(); if (mode < 0) @@ -1834,11 +1853,12 @@ while (commands != NULL) else { + if (s[0] != '/' && (filter_options & RDO_PREPEND_HOME) != 0 && + deliver_home != NULL && deliver_home[0] != 0) + s = string_sprintf("%s/%s", deliver_home, s); DEBUG(D_filter) debug_printf("Filter: %ssave message to: %s%s\n", (commands->seen)? "" : "unseen ", s, commands->noerror? " (noerror)" : ""); - if (s[0] != '/' && deliver_home != NULL && deliver_home[0] != 0) - s = string_sprintf("%s/%s", deliver_home, s); /* Create the new address and add it to the chain, setting the af_pfr and af_file flags, the af_ignore_error flag if necessary, and the @@ -1855,7 +1875,7 @@ while (commands != NULL) case pipe_command: s = string_copy(commands->args[0].u); - if (filter_test != NULL) + if (filter_test != FTEST_NONE) { indent(); printf("%sipe message to: %s%s\n", (commands->seen)? @@ -1907,11 +1927,11 @@ while (commands != NULL) if (log_mode == -1) log_mode = 0600; if (log_fd >= 0) { - close(log_fd); + (void)close(log_fd); log_fd = -1; } log_filename = expargs[0]; - if (filter_test != NULL) + if (filter_test != FTEST_NONE) { indent(); printf("%sogfile %s\n", (commands->seen)? "Seen l" : "L", log_filename); @@ -1921,7 +1941,7 @@ while (commands != NULL) case logwrite_command: s = expargs[0]; - if (filter_test != NULL) + if (filter_test != FTEST_NONE) { indent(); printf("%sogwrite \"%s\"\n", (commands->seen)? "Seen l" : "L", @@ -1983,7 +2003,7 @@ while (commands != NULL) int subtype = commands->args[1].i; s = expargs[0]; - if (filter_test != NULL) + if (filter_test != FTEST_NONE) printf("Headers %s \"%s\"\n", (subtype == TRUE)? "add" : (subtype == FALSE)? "remove" : "charset", string_printing(s)); @@ -2042,7 +2062,7 @@ while (commands != NULL) fmsg = string_printing(fmsg); *error_pointer = fmsg; - if (filter_test != NULL) + if (filter_test != FTEST_NONE) { indent(); printf("%c%s text \"%s\"\n", toupper(ff_name[0]), ff_name+1, fmsg); @@ -2051,7 +2071,7 @@ while (commands != NULL) return ff_ret; case finish_command: - if (filter_test != NULL) + if (filter_test != FTEST_NONE) { indent(); printf("%sinish\n", (commands->seen)? "Seen f" : "F"); @@ -2091,7 +2111,7 @@ while (commands != NULL) case vacation_command: if (return_path == NULL || return_path[0] == 0) { - if (filter_test != NULL) + if (filter_test != FTEST_NONE) printf("%s command ignored because return_path is empty\n", command_list[commands->command]); else DEBUG(D_filter) debug_printf("%s command ignored because return_path " @@ -2166,7 +2186,6 @@ while (commands != NULL) string_printing(s), command_list[commands->command]); return FF_ERROR; } - pp++; } p = pp; } @@ -2180,7 +2199,7 @@ while (commands != NULL) /* Proceed with mail or vacation command */ - if (filter_test != NULL) + if (filter_test != FTEST_NONE) { uschar *to = commands->args[mailarg_index_to].u; indent(); @@ -2207,12 +2226,17 @@ while (commands != NULL) else { uschar *tt; + uschar *log_addr = NULL; uschar *to = commands->args[mailarg_index_to].u; + int size = 0; + int ptr = 0; + int badflag = 0; + if (to == NULL) to = expand_string(US"$reply_address"); while (isspace(*to)) to++; - for (tt = to; *tt != 0; tt++) /* Get rid of newlines so that */ - if (*tt == '\n') *tt = ' '; /* the eventual log line is OK */ + for (tt = to; *tt != 0; tt++) /* Get rid of newlines */ + if (*tt == '\n') *tt = ' '; DEBUG(D_filter) { @@ -2235,10 +2259,59 @@ while (commands != NULL) } } - /* Create the "address" for the autoreply */ + /* Create the "address" for the autoreply. This is used only for logging, + as the actual recipients are extracted from the To: line by -t. We use the + same logic here to extract the working addresses (there may be more than + one). Just in case there are a vast number of addresses, stop when the + string gets too long. */ + + tt = to; + while (*tt != 0) + { + uschar *ss = parse_find_address_end(tt, FALSE); + uschar *recipient, *errmess; + int start, end, domain; + int temp = *ss; + + *ss = 0; + recipient = parse_extract_address(tt, &errmess, &start, &end, &domain, + FALSE); + *ss = temp; + + /* Ignore empty addresses and errors; an error will occur later if + there's something really bad. */ + + if (recipient != NULL) + { + log_addr = string_cat(log_addr, &size, &ptr, + (log_addr == NULL)? US">" : US",", 1); + log_addr = string_cat(log_addr, &size, &ptr, recipient, + Ustrlen(recipient)); + } + + /* Check size */ + + if (ptr > 256) + { + log_addr = string_cat(log_addr, &size, &ptr, US", ...", 5); + break; + } + + /* Move on past this address */ + + tt = ss + (*ss? 1:0); + while (isspace(*tt)) tt++; + } + + if (log_addr == NULL) + { + log_addr = string_sprintf(">**bad-reply**"); + badflag = af_bad_reply; + } + else log_addr[ptr] = 0; - addr = deliver_make_addr(string_sprintf(">%.256s", to), FALSE); - setflag(addr, af_pfr); + addr = deliver_make_addr(log_addr, FALSE); + setflag(addr, (af_pfr|badflag)); if (commands->noerror) setflag(addr, af_ignore_error); addr->next = *generated; *generated = addr; @@ -2278,10 +2351,10 @@ while (commands != NULL) break; case testprint_command: - if (filter_test != NULL || (debug_selector & D_filter) != 0) + if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0) { uschar *s = string_printing(expargs[0]); - if (filter_test == NULL) + if (filter_test == FTEST_NONE) debug_printf("Filter: testprint: %s\n", s); else printf("Testprint: %s\n", s); @@ -2321,14 +2394,42 @@ header_line *h; int to_count = 2; int from_count = 9; -/* If any header line in the message starts with "List-", it is not -a personal message. */ +/* If any header line in the message is a defined "List-" header field, it is +not a personal message. We used to check for any header line that started with +"List-", but this was tightened up for release 4.54. The check is now for +"List-Id", defined in RFC 2929, or "List-Help", "List-Subscribe", "List- +Unsubscribe", "List-Post", "List-Owner" or "List-Archive", all of which are +defined in RFC 2369. We also scan for "Auto-Submitted"; if it is found to +contain any value other than "no", the message is not personal (RFC 3834). +Previously the test was for "auto-". */ for (h = header_list; h != NULL; h = h->next) { - if (h->type != htype_old && h->slen > 5 && - strncmpic(h->text, US"List-", 5) == 0) - return FALSE; + uschar *s; + if (h->type == htype_old) continue; + + if (strncmpic(h->text, US"List-", 5) == 0) + { + s = h->text + 5; + if (strncmpic(s, US"Id:", 3) == 0 || + strncmpic(s, US"Help:", 5) == 0 || + strncmpic(s, US"Subscribe:", 10) == 0 || + strncmpic(s, US"Unsubscribe:", 12) == 0 || + strncmpic(s, US"Post:", 5) == 0 || + strncmpic(s, US"Owner:", 6) == 0 || + strncmpic(s, US"Archive:", 8) == 0) + return FALSE; + } + + else if (strncmpic(h->text, US"Auto-submitted:", 15) == 0) + { + s = h->text + 15; + while (isspace(*s)) s++; + if (strncmpic(s, US"no", 2) != 0) return FALSE; + s += 2; + while (isspace(*s)) s++; + if (*s != 0) return FALSE; + } } /* Set up "my" address */ @@ -2384,7 +2485,6 @@ yield = "^daemon@", "^root@", "^listserv@", "^majordomo@", "^.*?-request@", "^owner-[^@]+@", self, self_from, psself, psself_from) && - header_match(US"auto-submitted:", FALSE, FALSE, NULL, 1, "auto-") && header_match(US"precedence:", FALSE, FALSE, NULL, 3, "bulk","list","junk") && (sender_address == NULL || sender_address[0] != 0); @@ -2460,7 +2560,7 @@ ptr = nextsigchar(ptr, TRUE); if (read_command_list(&ptr, &lastcmdptr, FALSE)) yield = interpret_commands(commands, generated); -if (filter_test != NULL || (debug_selector & D_filter) != 0) +if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0) { uschar *s = US""; switch(yield) @@ -2493,14 +2593,14 @@ if (filter_test != NULL || (debug_selector & D_filter) != 0) break; } - if (filter_test != NULL) printf("%s\n", CS s); + if (filter_test != FTEST_NONE) printf("%s\n", CS s); else debug_printf("%s\n", s); } /* Close the log file if it was opened, and kill off any numerical variables before returning. Reset the header decoding charset. */ -if (log_fd >= 0) close(log_fd); +if (log_fd >= 0) (void)close(log_fd); expand_nmax = -1; filter_running = FALSE; headers_charset = save_headers_charset;