/* Example: "str-fun-1" Illustrates some uses of strings, functions, and mixed C/SIEVE constructs. In this example, we: - define a function to prefix a header with a string. - define an array of structures containing DNSBL definitions to test. - define an array of structures containing address strings and destinations. - Test the dnsbls array, and create a new header "X-DNSBLs" that lists every DNSBL that "hits" for this message. - Optionally prefix the subject with "[SPAM]" depending on the results of the dnsbls test. - Test the "to" address against the addresses in the recipient translation array; if one is found, the message is redirected to the corresponding destination address supplied in that array. Note that every statement is executed as soon as its outermost enclosing level is parsed. */ /* Declare the sieve facilities that we use. */ sieve { require [ "editheader", "dnsbl" ]; } /* An array of structures with email addresses and recipients. */ @define REDIRCOUNT 3 /* Number of entries */ struct { string r_addr; /* Address to check */ string r_rcpt; /* Address to redirect to */ } rdirs[ REDIRCOUNT ] = { /* incoming outgoing */ { "tom@example.com", "fred@example.org" }, { "dick@example.com", "bozo@example.org" }, { "harry@example.com", "sally@example.org" } }; /* An array of DNSBLs to test against */ @define DNSBLC 3 struct { string d_name; /* dnsbl name */ string d_rslt; /* Result code to test */ int d_tag; /* Tag subject with "spam" ? */ } dnsbls[DNSBLC] = { /* name code tag? */ { "spamcop", "std", 0 }, { "spamhaus", "std", 1 }, { "sorbs", "std", 0 } }; /* Function to prefix a header value with a string. If no such header exists, create a new one with just the prefix as its new value. */ int prefix_header( string name, string prefix ) { sieve { /* See if the header exists, and as a side-effect load the match buffer with the old value. */ if header :matches [name] "*" { replaceheader :newvalue [prefix + " " + $str_match(0)] [name]; } else { /* No existing header: make a new one */ addheader [name] [prefix]; } } }; int i; /* A scratch variable */ char dnsblF = 0; /* Set if any dnsbls match */ char tagF = 0; /* Set if we should tag the subject */ string dnsblmat; /* A string with all matching DNSBL names */ /* Check against the DNSBLs in dnsbls[] */ for ( i = 0; i < DNSBLC; ++i ) { if ( sieve { dnsbl [dnsbls[i].d_name] [dnsbls[i].d_rslt] } ) { /* Got a hit on the dnsbl. Add to the string. */ if ( !dnsblF ) dnsblmat = (dnsbls[i].d_name); else dnsblmat += (string)" " + (dnsbls[i].d_name); dnsblF = 1; /* Set the tag flag if set in the array member */ if ( dnsbls[i].d_tag ) tagF = 1; } } if ( dnsblF ) { /* Some DNSBL(s) were hit. We now have a string in "dnsblmat" containing the list of DNSBL names, e.g. "spamcop sorbs". Make a new header "X-DNSBLs" with that list. */ sieve { addheader "X-DNSBLs" [dnsblmat]; } } /* We also have a flag "tagF". If this has been set, add the prefix "[SPAM] " to the subject line, using the "prefix_header" function defined above. However, don't create a new subject if one didn't exist already. (Mainly to illustrate the use of the "C" escape.) */ if ( tagF ) sieve { if exists "Subject" { C { prefix_header( "Subject", "[SPAM]" ); } } } /* Loop through the rdirs array to see if we should redirect to a matching address. */ for ( i = 0; i < REDIRCOUNT; ++i ) { sieve { if address :is "To" [rdirs[i].r_addr] { redirect [ rdirs[i].r_rcpt ]; stop; } } } /* If we get here, "implicit keep" will store the message. */