X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/deaf311d9e392d30cf255cc9d10c8a2a1924de3b..7eb0e5d2b8453f753bd2d8e2e77cf4b7e0b24b1b:/src/src/sieve.c diff --git a/src/src/sieve.c b/src/src/sieve.c index e5d66d523..635d57827 100644 --- a/src/src/sieve.c +++ b/src/src/sieve.c @@ -1,11 +1,11 @@ -/* $Cambridge: exim/src/src/sieve.c,v 1.33 2008/01/28 12:18:56 michael Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) Michael Haardt 2003-2008 */ -/* See the file NOTICE for conditions of use and distribution. */ +/* Copyright (c) Michael Haardt 2003 - 2015 + * Copyright (c) The Exim Maintainers 2016 + * See the file NOTICE for conditions of use and distribution. + */ /* This code was contributed by Michael Haardt. */ @@ -71,6 +71,7 @@ struct Sieve int require_enotify; struct Notification *notified; #endif + uschar *enotify_mailto_owner; #ifdef SUBADDRESS int require_subaddress; #endif @@ -108,6 +109,38 @@ struct Notification struct Notification *next; }; +/* This should be a complete list of supported extensions, so that an external +ManageSieve (RFC 5804) program can interrogate the current Exim binary for the +list of extensions and provide correct information to a client. + +We'll emit the list in the order given here; keep it alphabetically sorted, so +that callers don't get surprised. + +List *MUST* end with a NULL. Which at least makes ifdef-vs-comma easier. */ + +const uschar *exim_sieve_extension_list[] = { + CUS"comparator-i;ascii-numeric", + CUS"copy", +#ifdef ENCODED_CHARACTER + CUS"encoded-character", +#endif +#ifdef ENOTIFY + CUS"enotify", +#endif + CUS"envelope", +#ifdef ENVELOPE_AUTH + CUS"envelope-auth", +#endif + CUS"fileinto", +#ifdef SUBADDRESS + CUS"subaddress", +#endif +#ifdef VACATION + CUS"vacation", +#endif + NULL +}; + static int eq_asciicase(const struct String *needle, const struct String *haystack, int match_prefix); static int parse_test(struct Sieve *filter, int *cond, int exec); static int parse_commands(struct Sieve *filter, int exec, address_item **generated); @@ -201,6 +234,9 @@ uschar *new = NULL; uschar ch; size_t line; +/* Two passes: one to count output allocation size, second +to do the encoding */ + for (pass=0; pass<=1; ++pass) { line=0; @@ -214,54 +250,47 @@ for (pass=0; pass<=1; ++pass) for (start=src->character,end=start+src->length; start=73) + if (line>=73) /* line length limit */ { if (pass==0) dst->length+=2; else { - *new++='='; + *new++='='; /* line split */ *new++='\n'; } line=0; } - if - ( - (ch>=33 && ch<=60) - || (ch>=62 && ch<=126) - || - ( - (ch==9 || ch==32) - && start+2='!' && ch<='<') + || (ch>='>' && ch<='~') + || ( (ch=='\t' || ch==' ') + && start+2length; else - *new++=*start; + *new++=*start; /* copy char */ ++line; } - else if (ch=='\r' && start+1length; - line=0; - } else - *new++='\n'; - line=0; - ++start; + *new++='\n'; /* NL */ + line=0; + ++start; /* consume extra input char */ } else { if (pass==0) dst->length+=3; else - { - sprintf(CS new,"=%02X",ch); + { /* encoded char */ + new += sprintf(CS new,"=%02X",ch); new+=3; } line+=3; @@ -384,7 +413,8 @@ Returns 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; +struct String to, hname; +struct String hvalue = {.character = NULL, .length = 0}; int capacity; string_item *new; @@ -393,6 +423,7 @@ if (Ustrncmp(uri,"mailto:",7)) filter->errmsg=US "Unknown URI scheme"; return 0; } + uri+=7; if (*uri && *uri!='?') for (;;) @@ -402,9 +433,9 @@ if (*uri && *uri!='?') if (uri>start) { capacity=0; - to.character=(uschar*)0; + to.character= NULL; to.length=0; - to.character=string_cat(to.character,&capacity,&to.length,start,uri-start); + to.character=string_catn(to.character, &capacity, &to.length, start, uri-start); to.character[to.length]='\0'; if (uri_decode(&to)==-1) { @@ -436,9 +467,9 @@ if (*uri=='?') if (uri>start) { capacity=0; - hname.character=(uschar*)0; + hname.character= NULL; hname.length=0; - hname.character=string_cat(hname.character,&capacity,&hname.length,start,uri-start); + hname.character = string_catn(hname.character, &capacity, &hname.length, start, uri-start); hname.character[hname.length]='\0'; if (uri_decode(&hname)==-1) { @@ -459,9 +490,9 @@ if (*uri=='?') if (uri>start) { capacity=0; - hvalue.character=(uschar*)0; + hvalue.character= NULL; hvalue.length=0; - hvalue.character=string_cat(hvalue.character,&capacity,&hvalue.length,start,uri-start); + hvalue.character=string_catn(hvalue.character,&capacity,&hvalue.length,start,uri-start); hvalue.character[hvalue.length]='\0'; if (uri_decode(&hvalue)==-1) { @@ -500,10 +531,10 @@ if (*uri=='?') { if (header->length==-1) header->length=0; capacity=header->length; - header->character=string_cat(header->character,&capacity,&header->length,hname.character,hname.length); - header->character=string_cat(header->character,&capacity,&header->length,CUS ": ",2); - header->character=string_cat(header->character,&capacity,&header->length,hvalue.character,hvalue.length); - header->character=string_cat(header->character,&capacity,&header->length,CUS "\n",1); + header->character=string_catn(header->character,&capacity,&header->length,hname.character,hname.length); + header->character=string_catn(header->character,&capacity,&header->length,CUS ": ",2); + header->character=string_catn(header->character,&capacity,&header->length,hvalue.character,hvalue.length); + header->character=string_catn(header->character,&capacity,&header->length,CUS "\n",1); header->character[header->length]='\0'; } } @@ -977,24 +1008,24 @@ while (l) { case '\0': { - quoted=string_cat(quoted,&size,&ptr,CUS "\\0",2); + quoted=string_catn(quoted,&size,&ptr,CUS "\\0",2); break; } case '$': case '{': case '}': { - quoted=string_cat(quoted,&size,&ptr,CUS "\\",1); + quoted=string_catn(quoted,&size,&ptr,CUS "\\",1); } default: { - quoted=string_cat(quoted,&size,&ptr,h,1); + quoted=string_catn(quoted,&size,&ptr,h,1); } } ++h; --l; } -quoted=string_cat(quoted,&size,&ptr,CUS "",1); +quoted=string_catn(quoted,&size,&ptr,CUS "",1); return quoted; } @@ -1015,33 +1046,36 @@ Arguments: Returns: nothing */ -static void add_addr(address_item **generated, uschar *addr, int file, int maxage, int maxmessages, int maxstorage) +static void +add_addr(address_item **generated, uschar *addr, int file, int maxage, int maxmessages, int maxstorage) { address_item *new_addr; for (new_addr=*generated; new_addr; new_addr=new_addr->next) - { - if (Ustrcmp(new_addr->address,addr)==0 && (file ? testflag(new_addr, af_pfr|af_file) : 1)) + if ( Ustrcmp(new_addr->address,addr) == 0 + && ( !file + || testflag(new_addr, af_pfr) + || testflag(new_addr, af_file) + ) + ) { if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) - { debug_printf("Repeated %s `%s' ignored.\n",file ? "fileinto" : "redirect", addr); - } + return; } - } if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) - { debug_printf("%s `%s'\n",file ? "fileinto" : "redirect", addr); - } -new_addr=deliver_make_addr(addr,TRUE); + +new_addr = deliver_make_addr(addr,TRUE); if (file) { - setflag(new_addr, af_pfr|af_file); + setflag(new_addr, af_pfr); + setflag(new_addr, af_file); new_addr->mode = 0; } -new_addr->p.errors_address = NULL; +new_addr->prop.errors_address = NULL; new_addr->next = *generated; *generated = new_addr; } @@ -1458,7 +1492,7 @@ if (*filter->pc=='"') /* quoted string */ ++filter->pc; /* that way, there will be at least one character allocated */ - data->character=string_cat(data->character,&dataCapacity,&foo,CUS "",1); + data->character=string_catn(data->character,&dataCapacity,&foo,CUS "",1); #ifdef ENCODED_CHARACTER if (filter->require_encoded_character && string_decode(filter,data)==-1) @@ -1468,7 +1502,7 @@ if (*filter->pc=='"') /* quoted string */ } else if (*filter->pc=='\\' && *(filter->pc+1)) /* quoted character */ { - data->character=string_cat(data->character,&dataCapacity,&data->length,filter->pc+1,1); + data->character=string_catn(data->character,&dataCapacity,&data->length,filter->pc+1,1); filter->pc+=2; } else /* regular character */ @@ -1478,11 +1512,11 @@ if (*filter->pc=='"') /* quoted string */ #else if (*filter->pc=='\n') { - data->character=string_cat(data->character,&dataCapacity,&data->length,US"\r",1); + data->character=string_catn(data->character,&dataCapacity,&data->length,US"\r",1); ++filter->line; } #endif - data->character=string_cat(data->character,&dataCapacity,&data->length,filter->pc,1); + data->character=string_catn(data->character,&dataCapacity,&data->length,filter->pc,1); filter->pc++; } } @@ -1524,7 +1558,7 @@ else if (Ustrncmp(filter->pc,CUS "text:",5)==0) /* multiline string */ if (*filter->pc=='\n') /* end of line */ #endif { - data->character=string_cat(data->character,&dataCapacity,&data->length,CUS "\r\n",2); + data->character=string_catn(data->character,&dataCapacity,&data->length,CUS "\r\n",2); #ifdef RFC_EOL filter->pc+=2; #else @@ -1540,7 +1574,7 @@ else if (Ustrncmp(filter->pc,CUS "text:",5)==0) /* multiline string */ int foo=data->length; /* that way, there will be at least one character allocated */ - data->character=string_cat(data->character,&dataCapacity,&foo,CUS "",1); + data->character=string_catn(data->character,&dataCapacity,&foo,CUS "",1); #ifdef RFC_EOL filter->pc+=3; #else @@ -1556,13 +1590,13 @@ else if (Ustrncmp(filter->pc,CUS "text:",5)==0) /* multiline string */ } else if (*filter->pc=='.' && *(filter->pc+1)=='.') /* remove dot stuffing */ { - data->character=string_cat(data->character,&dataCapacity,&data->length,CUS ".",1); + data->character=string_catn(data->character,&dataCapacity,&data->length,CUS ".",1); filter->pc+=2; } } else /* regular character */ { - data->character=string_cat(data->character,&dataCapacity,&data->length,filter->pc,1); + data->character=string_catn(data->character,&dataCapacity,&data->length,filter->pc,1); filter->pc++; } } @@ -1675,12 +1709,13 @@ Returns: 1 success -1 no string list found */ -static int parse_stringlist(struct Sieve *filter, struct String **data) +static int +parse_stringlist(struct Sieve *filter, struct String **data) { const uschar *orig=filter->pc; -int dataCapacity=0; -int dataLength=0; -struct String *d=(struct String*)0; +int dataCapacity = 0; +int dataLength = 0; +struct String *d = NULL; int m; if (*filter->pc=='[') /* string list */ @@ -1689,20 +1724,18 @@ if (*filter->pc=='[') /* string list */ for (;;) { if (parse_white(filter)==-1) goto error; - if ((dataLength+1)>=dataCapacity) /* increase buffer */ + if (dataLength+1 >= dataCapacity) /* increase buffer */ { struct String *new; int newCapacity; /* Don't amalgamate with next line; some compilers grumble */ - newCapacity=dataCapacity?(dataCapacity*=2):(dataCapacity=4); - if ((new=(struct String*)store_get(sizeof(struct String)*newCapacity))==(struct String*)0) - { - filter->errmsg=CUstrerror(errno); - goto error; - } + + dataCapacity = dataCapacity ? dataCapacity * 2 : 4; + new = store_get(sizeof(struct String) * dataCapacity); + if (d) memcpy(new,d,sizeof(struct String)*dataLength); - d=new; - dataCapacity=newCapacity; + d = new; } + m=parse_string(filter,&d[dataLength]); if (m==0) { @@ -2706,8 +2739,8 @@ Returns: 2 success by stop 1 other success -1 syntax or execution error */ -static int parse_commands(struct Sieve *filter, int exec, - address_item **generated) +static int +parse_commands(struct Sieve *filter, int exec, address_item **generated) { while (*filter->pc) { @@ -2939,7 +2972,6 @@ while (*filter->pc) int m; struct String from; struct String importance; - struct String *options; struct String message; struct String method; struct Notification *already; @@ -2947,7 +2979,7 @@ while (*filter->pc) 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; @@ -2960,7 +2992,6 @@ while (*filter->pc) from.length=-1; importance.character=(uschar*)0; importance.length=-1; - options=(struct String*)0; message.character=(uschar*)0; message.length=-1; recipient=NULL; @@ -2970,8 +3001,7 @@ while (*filter->pc) 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; @@ -3022,94 +3052,94 @@ while (*filter->pc) if (parse_semicolon(filter)==-1) return -1; if (parse_mailto_uri(filter,method.character,&recipient,&header,&subject,&body)!=1) return -1; - 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) - { - filter->errmsg=CUS "header string expansion failed"; - return -1; - } - if (Ustrcmp(auto_submitted_def,"true")!=0 || Ustrcmp(auto_submitted_value.character,"no")==0) + if (exec) { - for (already=filter->notified; already; already=already->next) + 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) { - 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; + filter->errmsg=CUS "header string expansion failed"; + return -1; } - if (already==(struct Notification*)0) - /* New notification, process it */ + if (Ustrcmp(auto_submitted_def,"true")!=0 || Ustrcmp(auto_submitted_value.character,"no")==0) { - 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) + for (already=filter->notified; already; already=already->next) { - debug_printf("Notification to `%s': '%s'.\n",method.character,message.length!=-1 ? message.character : CUS ""); + 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; } -#ifndef COMPILE_SYNTAX_CHECKER - if (exec && filter_test == FTEST_NONE) + if (already==(struct Notification*)0) + /* New notification, process it */ { - string_item *p; - header_line *h; - int pid,fd; - - if ((pid = child_open_exim2(&fd,envelope_to,envelope_to))>=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; + #ifndef COMPILE_SYNTAX_CHECKER + if (filter_test == FTEST_NONE) { - 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); - fprintf(f,"Auto-submitted: sieve-notify\n"); - if (header.length>0) fprintf(f,"%s",header.character); - if (message.length==-1) + string_item *p; + int pid,fd; + + if ((pid = child_open_exim2(&fd,envelope_from,envelope_from))>=1) { - message.character=US"Notification"; - message.length=Ustrlen(message.character); + 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 necessary, 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); } - /* 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 + { + if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) + { + debug_printf("Repeated notification to `%s' ignored.\n",method.character); + } + } } else { if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) { - debug_printf("Repeated notification to `%s' ignored.\n",method.character); + debug_printf("Ignoring notification, triggering message contains Auto-submitted: field.\n"); } } } - else - { - if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) - { - debug_printf("Ignoring notification, triggering message contains Auto-submitted: field.\n"); - } - } } #endif #ifdef VACATION @@ -3271,10 +3301,10 @@ while (*filter->pc) capacity=0; if (handle.length==-1) { - if (subject.length!=-1) key.character=string_cat(key.character,&capacity,&key.length,subject.character,subject.length); - if (from.length!=-1) key.character=string_cat(key.character,&capacity,&key.length,from.character,from.length); - key.character=string_cat(key.character,&capacity,&key.length,reason_is_mime?US"1":US"0",1); - key.character=string_cat(key.character,&capacity,&key.length,reason.character,reason.length); + if (subject.length!=-1) key.character=string_catn(key.character,&capacity,&key.length,subject.character,subject.length); + if (from.length!=-1) key.character=string_catn(key.character,&capacity,&key.length,from.character,from.length); + key.character=string_catn(key.character,&capacity,&key.length,reason_is_mime?US"1":US"0",1); + key.character=string_catn(key.character,&capacity,&key.length,reason.character,reason.length); } else key=handle; @@ -3289,8 +3319,8 @@ while (*filter->pc) { capacity=Ustrlen(filter->vacation_directory); start=capacity; - once=string_cat(filter->vacation_directory,&capacity,&start,US"/",1); - once=string_cat(once,&capacity,&start,hexdigest,33); + once=string_catn(filter->vacation_directory,&capacity,&start,US"/",1); + once=string_catn(once,&capacity,&start,hexdigest,33); once[start] = '\0'; /* process subject */ @@ -3305,7 +3335,7 @@ while (*filter->pc) expand_header(&subject,&str_subject); capacity=6; start=6; - subject.character=string_cat(US"Auto: ",&capacity,&start,subject.character,subject.length); + subject.character=string_catn(US"Auto: ",&capacity,&start,subject.character,subject.length); subject.length=start; } else @@ -3319,7 +3349,7 @@ while (*filter->pc) addr = deliver_make_addr(string_sprintf(">%.256s", sender_address), FALSE); setflag(addr, af_pfr); - setflag(addr, af_ignore_error); + addr->prop.ignore_error = TRUE; addr->next = *generated; *generated = addr; addr->reply = store_get(sizeof(reply_item)); @@ -3329,10 +3359,11 @@ while (*filter->pc) addr->reply->from = expand_string(US"$local_part@$domain"); else addr->reply->from = from.character; - /* Allocation is larger than neccessary, but enough even for split MIME words */ + /* Allocation is larger than necessary, but enough even for split MIME words */ buffer_capacity=32+4*subject.length; buffer=store_get(buffer_capacity); - addr->reply->subject=parse_quote_2047(subject.character, subject.length, US"utf-8", buffer, buffer_capacity, TRUE); + /* deconst cast safe as we pass in a non-const item */ + addr->reply->subject = US parse_quote_2047(subject.character, subject.length, US"utf-8", buffer, buffer_capacity, TRUE); addr->reply->oncelog=once; addr->reply->once_repeat=days*86400; @@ -3351,18 +3382,18 @@ while (*filter->pc) ); capacity = 0; start = 0; - addr->reply->headers = string_cat(NULL,&capacity,&start,reason.character,mime_body-reason.character); + addr->reply->headers = string_catn(NULL,&capacity,&start,reason.character,mime_body-reason.character); addr->reply->headers[start] = '\0'; capacity = 0; start = 0; if (mime_body+(sizeof(nlnl)-1)reply->text = string_cat(NULL,&capacity,&start,mime_body,reason_end-mime_body); + addr->reply->text = string_catn(NULL,&capacity,&start,mime_body,reason_end-mime_body); addr->reply->text[start] = '\0'; } else { - struct String qp = { NULL, 0 }; /* Keep compiler happy (PH) */ + struct String qp = { .character = NULL, .length = 0 }; /* Keep compiler happy (PH) */ capacity = 0; start = reason.length; @@ -3401,8 +3432,8 @@ Returns: 1 success -1 syntax or execution error */ -static int parse_start(struct Sieve *filter, int exec, - address_item **generated) +static int +parse_start(struct Sieve *filter, int exec, address_item **generated) { filter->pc=filter->filter; filter->line=1; @@ -3491,7 +3522,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; @@ -3539,7 +3578,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 @@ -3555,7 +3595,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; @@ -3581,6 +3622,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;