X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Fsieve.c;h=db19d713be6e2a639d3e7c6bd04e7470165a4a81;hb=1b587e48d9bb95e6e7d9b3f482a9e4460b6ab130;hp=19403deddaf143e787d716a5e997acc9be18ed9e;hpb=d6a60c0f7b4ba4656bb92b9245c988de02186b02;p=exim.git diff --git a/src/src/sieve.c b/src/src/sieve.c index 19403dedd..db19d713b 100644 --- a/src/src/sieve.c +++ b/src/src/sieve.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/sieve.c,v 1.29 2007/08/17 11:16:45 ph10 Exp $ */ +/* $Cambridge: exim/src/src/sieve.c,v 1.38 2009/11/05 19:40:51 nm4 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) Michael Haardt 2003-2006 */ +/* Copyright (c) Michael Haardt 2003-2008 */ /* See the file NOTICE for conditions of use and distribution. */ /* This code was contributed by Michael Haardt. */ @@ -29,13 +29,13 @@ #undef RFC_EOL /* Define this for development of the Sieve extension "encoded-character". */ -#undef ENCODED_CHARACTER +#define ENCODED_CHARACTER /* Define this for development of the Sieve extension "envelope-auth". */ #undef ENVELOPE_AUTH /* Define this for development of the Sieve extension "enotify". */ -#undef ENOTIFY +#define ENOTIFY /* Define this for the Sieve extension "subaddress". */ #define SUBADDRESS @@ -71,6 +71,7 @@ struct Sieve int require_enotify; struct Notification *notified; #endif + uschar *enotify_mailto_owner; #ifdef SUBADDRESS int require_subaddress; #endif @@ -147,6 +148,8 @@ static uschar str_online_c[]="online"; static const struct String str_online={ str_online_c, 6 }; static uschar str_maybe_c[]="maybe"; static const struct String str_maybe={ str_maybe_c, 5 }; +static uschar str_auto_submitted_c[]="Auto-Submitted"; +static const struct String str_auto_submitted={ str_auto_submitted_c, 14 }; #endif #ifdef SUBADDRESS static uschar str_subaddress_c[]="subaddress"; @@ -379,7 +382,7 @@ Returns -1 syntax error */ -static int parse_mailto_uri(struct Sieve *filter, const uschar *uri, string_item **recipient, struct String *header, struct String *body) +static int parse_mailto_uri(struct Sieve *filter, const uschar *uri, string_item **recipient, struct String *header, struct String *subject, struct String *body) { const uschar *start; struct String to,hname,hvalue; @@ -478,13 +481,17 @@ if (*uri=='?') } else if (hname.length==4 && strcmpic(hname.character, US"body")==0) *body=hvalue; + else if (hname.length==7 && strcmpic(hname.character, US"subject")==0) + *subject=hvalue; else { static struct String ignore[]= { + {US"date",4}, {US"from",4}, - {US"subject",7}, - {US"received",8} + {US"message-id",10}, + {US"received",8}, + {US"auto-submitted",14} }; static struct String *end=ignore+sizeof(ignore)/sizeof(ignore[0]); struct String *i; @@ -605,8 +612,10 @@ return (match_prefix ? nl==0 : nl==0 && hl==0); /* Arguments: - needle pattern to search ... - haystack ... inside the haystack + needle pattern to search ... + haystack ... inside the haystack + ascii_caseless ignore ASCII case + match_octet match octets, not UTF-8 multi-octet characters Returns: 0 needle not found in haystack 1 needle found @@ -996,7 +1005,7 @@ return quoted; *************************************************/ /* -According to RFC 3028, duplicate delivery to the same address must +According to RFC 5228, duplicate delivery to the same address must not happen, so the list is first searched for the address. Arguments: @@ -1460,8 +1469,7 @@ if (*filter->pc=='"') /* quoted string */ } else if (*filter->pc=='\\' && *(filter->pc+1)) /* quoted character */ { - if (*(filter->pc+1)=='0') data->character=string_cat(data->character,&dataCapacity,&data->length,CUS "",1); - else data->character=string_cat(data->character,&dataCapacity,&data->length,filter->pc+1,1); + data->character=string_cat(data->character,&dataCapacity,&data->length,filter->pc+1,1); filter->pc+=2; } else /* regular character */ @@ -1932,7 +1940,7 @@ Grammar: Arguments: filter points to the Sieve filter including its state n total number of tests - true number of passed tests + num_true number of passed tests exec Execute parsed statements Returns: 1 success @@ -1940,14 +1948,14 @@ Returns: 1 success -1 syntax or execution error */ -static int parse_testlist(struct Sieve *filter, int *n, int *true, int exec) +static int parse_testlist(struct Sieve *filter, int *n, int *num_true, int exec) { if (parse_white(filter)==-1) return -1; if (*filter->pc=='(') { ++filter->pc; *n=0; - *true=0; + *num_true=0; for (;;) { int cond; @@ -1956,7 +1964,7 @@ if (*filter->pc=='(') { case -1: return -1; case 0: filter->errmsg=CUS "missing test"; return -1; - default: ++*n; if (cond) ++*true; break; + default: ++*n; if (cond) ++*num_true; break; } if (parse_white(filter)==-1) return -1; if (*filter->pc==',') ++filter->pc; @@ -2144,13 +2152,13 @@ else if (parse_identifier(filter,CUS "allof")) allof-test = "allof" */ - int n,true; + int n,num_true; - switch (parse_testlist(filter,&n,&true,exec)) + switch (parse_testlist(filter,&n,&num_true,exec)) { case -1: return -1; case 0: filter->errmsg=CUS "missing test list"; return -1; - default: *cond=(n==true); return 1; + default: *cond=(n==num_true); return 1; } } else if (parse_identifier(filter,CUS "anyof")) @@ -2159,13 +2167,13 @@ else if (parse_identifier(filter,CUS "anyof")) anyof-test = "anyof" */ - int n,true; + int n,num_true; - switch (parse_testlist(filter,&n,&true,exec)) + switch (parse_testlist(filter,&n,&num_true,exec)) { case -1: return -1; case 0: filter->errmsg=CUS "missing test list"; return -1; - default: *cond=(true>0); return 1; + default: *cond=(num_true>0); return 1; } } else if (parse_identifier(filter,CUS "exists")) @@ -2507,14 +2515,16 @@ else if (parse_identifier(filter,CUS "valid_notify_method")) for (u=uris; u->length!=-1 && *cond; ++u) { string_item *recipient; - struct String header,body; + struct String header,subject,body; recipient=NULL; header.length=-1; header.character=(uschar*)0; + subject.length=-1; + subject.character=(uschar*)0; body.length=-1; body.character=(uschar*)0; - if (parse_mailto_uri(filter,u->character,&recipient,&header,&body)!=1) + if (parse_mailto_uri(filter,u->character,&recipient,&header,&subject,&body)!=1) *cond=0; } } @@ -2586,15 +2596,17 @@ else if (parse_identifier(filter,CUS "notify_method_capability")) if (exec) { string_item *recipient; - struct String header,body; + struct String header,subject,body; *cond=0; recipient=NULL; header.length=-1; header.character=(uschar*)0; + subject.length=-1; + subject.character=(uschar*)0; body.length=-1; body.character=(uschar*)0; - if (parse_mailto_uri(filter,uri.character,&recipient,&header,&body)==1) + if (parse_mailto_uri(filter,uri.character,&recipient,&header,&subject,&body)==1) { if (eq_asciicase(&capa,&str_online,0)==1) for (k=keys; k->length!=-1; ++k) @@ -2934,8 +2946,11 @@ while (*filter->pc) struct Notification *already; string_item *recipient; struct String header; + struct String subject; struct String body; - uschar *envelope_from,*envelope_to; + uschar *envelope_from; + struct String auto_submitted_value; + uschar *auto_submitted_def; if (!filter->require_enotify) { @@ -2952,10 +2967,11 @@ while (*filter->pc) recipient=NULL; header.length=-1; header.character=(uschar*)0; + subject.length=-1; + subject.character=(uschar*)0; body.length=-1; body.character=(uschar*)0; - envelope_from=expand_string("$sender_address"); - envelope_to=expand_string("$local_part_prefix$local_part$local_part_suffix@$domain"); + envelope_from=(sender_address && sender_address[0]) ? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain") : US ""; for (;;) { if (parse_white(filter)==-1) return -1; @@ -3004,74 +3020,94 @@ while (*filter->pc) return -1; } if (parse_semicolon(filter)==-1) return -1; - - for (already=filter->notified; already; already=already->next) - { - if (already->method.length==method.length - && (method.length==-1 || strcmp(already->method.character,method.character)==0) - && already->importance.length==importance.length - && (importance.length==-1 || strcmp(already->importance.character,importance.character)==0) - && already->message.length==message.length - && (message.length==-1 || strcmp(already->message.character,message.character)==0)) - break; - } - if (already==(struct Notification*)0) - /* New notification, process it */ + if (parse_mailto_uri(filter,method.character,&recipient,&header,&subject,&body)!=1) + return -1; + if (exec) { - if (parse_mailto_uri(filter,method.character,&recipient,&header,&body)!=1) - return -1; - struct Notification *sent; - sent=store_get(sizeof(struct Notification)); - sent->method=method; - sent->importance=importance; - sent->message=message; - sent->next=filter->notified; - filter->notified=sent; - if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) + if (message.length==-1) message=subject; + if (message.length==-1) expand_header(&message,&str_subject); + expand_header(&auto_submitted_value,&str_auto_submitted); + auto_submitted_def=expand_string(string_sprintf("${if def:header_auto-submitted {true}{false}}")); + if (auto_submitted_value.character == NULL || auto_submitted_def == NULL) { - debug_printf("Notification to `%s'.\n",method.character); + filter->errmsg=CUS "header string expansion failed"; + return -1; } -#ifndef COMPILE_SYNTAX_CHECKER - if (exec && filter_test == FTEST_NONE) + if (Ustrcmp(auto_submitted_def,"true")!=0 || Ustrcmp(auto_submitted_value.character,"no")==0) { - string_item *p; - header_line *h; - int pid,fd; + for (already=filter->notified; already; already=already->next) + { + if (already->method.length==method.length + && (method.length==-1 || Ustrcmp(already->method.character,method.character)==0) + && already->importance.length==importance.length + && (importance.length==-1 || Ustrcmp(already->importance.character,importance.character)==0) + && already->message.length==message.length + && (message.length==-1 || Ustrcmp(already->message.character,message.character)==0)) + break; + } + if (already==(struct Notification*)0) + /* New notification, process it */ + { + struct Notification *sent; + sent=store_get(sizeof(struct Notification)); + sent->method=method; + sent->importance=importance; + sent->message=message; + sent->next=filter->notified; + filter->notified=sent; + #ifndef COMPILE_SYNTAX_CHECKER + if (filter_test == FTEST_NONE) + { + string_item *p; + int pid,fd; - if ((pid = child_open_exim2(&fd,envelope_to,envelope_to))>=1) + if ((pid = child_open_exim2(&fd,envelope_from,envelope_from))>=1) + { + FILE *f; + uschar *buffer; + int buffer_capacity; + + f = fdopen(fd, "wb"); + fprintf(f,"From: %s\n",from.length==-1 ? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain") : from.character); + for (p=recipient; p; p=p->next) fprintf(f,"To: %s\n",p->text); + fprintf(f,"Auto-Submitted: auto-notified; %s\n",filter->enotify_mailto_owner); + if (header.length>0) fprintf(f,"%s",header.character); + if (message.length==-1) + { + message.character=US"Notification"; + message.length=Ustrlen(message.character); + } + /* Allocation is larger than neccessary, but enough even for split MIME words */ + buffer_capacity=32+4*message.length; + buffer=store_get(buffer_capacity); + if (message.length!=-1) fprintf(f,"Subject: %s\n",parse_quote_2047(message.character, message.length, US"utf-8", buffer, buffer_capacity, TRUE)); + fprintf(f,"\n"); + if (body.length>0) fprintf(f,"%s\n",body.character); + fflush(f); + (void)fclose(f); + (void)child_close(pid, 0); + } + } + if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) + { + debug_printf("Notification to `%s': '%s'.\n",method.character,message.length!=-1 ? message.character : CUS ""); + } +#endif + } + else { - FILE *f; - uschar *buffer; - int buffer_capacity; - - f = fdopen(fd, "wb"); - for (h = header_list; h != NULL; h = h->next) - if (h->type == htype_received) fprintf(f,"%s",h->text); - fprintf(f,"From: %s\n",from.length==-1 ? envelope_to : from.character); - for (p=recipient; p; p=p->next) fprintf(f,"To: %s\n",p->text); - if (header.length>0) fprintf(f,"%s",header.character); - if (message.length==-1) + if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) { - message.character=US"Notification"; - message.length=Ustrlen(message.character); + debug_printf("Repeated notification to `%s' ignored.\n",method.character); } - /* Allocation is larger than neccessary, but enough even for split MIME words */ - buffer_capacity=32+4*message.length; - buffer=store_get(buffer_capacity); - fprintf(f,"Subject: %s\n\n",parse_quote_2047(message.character, message.length, US"utf-8", buffer, buffer_capacity, TRUE)); - if (body.length>0) fprintf(f,"%s\n",body.character); - fflush(f); - (void)fclose(f); - (void)child_close(pid, 0); } } -#endif - } - else - { - if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) + else { - debug_printf("Repeated notification to `%s' ignored.\n",method.character); + if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) + { + debug_printf("Ignoring notification, triggering message contains Auto-submitted: field.\n"); + } } } } @@ -3455,7 +3491,15 @@ while (parse_identifier(filter,CUS "require")) else if (eq_octet(check,&str_envelope_auth,0)) filter->require_envelope_auth=1; #endif #ifdef ENOTIFY - else if (eq_octet(check,&str_enotify,0)) filter->require_enotify=1; + else if (eq_octet(check,&str_enotify,0)) + { + if (filter->enotify_mailto_owner == NULL) + { + filter->errmsg=CUS "enotify disabled"; + return -1; + } + filter->require_enotify=1; + } #endif #ifdef SUBADDRESS else if (eq_octet(check,&str_subaddress,0)) filter->require_subaddress=1; @@ -3503,7 +3547,8 @@ Arguments: filter points to the entire file, read into store as a single string options controls whether various special things are allowed, and requests special actions (not currently used) - sieve_vacation_directory where to store vacation "once" files + vacation_directory where to store vacation "once" files + enotify_mailto_owner owner of mailto notifications useraddress string expression for :user part of address subaddress string expression for :subaddress part of address generated where to hang newly-generated addresses @@ -3519,7 +3564,8 @@ Returns: FF_DELIVERED success, a significant action was taken int sieve_interpret(uschar *filter, int options, uschar *vacation_directory, - uschar *useraddress, uschar *subaddress, address_item **generated, uschar **error) + uschar *enotify_mailto_owner, uschar *useraddress, uschar *subaddress, + address_item **generated, uschar **error) { struct Sieve sieve; int r; @@ -3545,6 +3591,20 @@ else } } +if (enotify_mailto_owner == NULL) + sieve.enotify_mailto_owner = NULL; +else + { + sieve.enotify_mailto_owner=expand_string(enotify_mailto_owner); + if (sieve.enotify_mailto_owner == NULL) + { + *error = string_sprintf("failed to expand \"%s\" " + "(sieve_enotify_mailto_owner): %s", enotify_mailto_owner, + expand_string_message); + return FF_ERROR; + } + } + sieve.useraddress = useraddress == NULL ? CUS "$local_part_prefix$local_part$local_part_suffix" : useraddress; sieve.subaddress = subaddress;