/* Collection of MFL functions to act upon "hdrctls.cdb" file. */ /* Uses some scratch variables: */ int hdrctls_pri_n = 0; string hdrctls_pri_s; int hdrctls_result; $CDB$ *hdrctls_cdbP; string hdrctls_s1; string *hdrctls_s1P; $HDR$ *hdrctls_hdrP; string hdrctls_hname; string *hdrctls_keydataP; // @define HDRCTLS_DEBUG 1 /* Function to lookup key in the open cdb database. Assumes that the hdrctls.cdb file is open with handle pointed to by hdrctls_cdbP. Returns the same as $cdb_get_string. This function exists to centralize debugging and header munging. */ string *hdrctls_lookup( string key ) { @ifdef HDRCTLS_DEBUG pv$ (string)"lookup: " + key; @endif if ( ( hdrctls_keydataP = $cdb_get_string( hdrctls_cdbP, key ) ) == NULL ) { return ( NULL ); } @ifdef HDRCTLS_DEBUG pv$ (string)" got: " + *hdrctls_keydataP; @endif // Annotate header sieve { addheader "X-HDRCTLS-KEY" [key]; } return ( hdrctls_keydataP ); }; /* Function to act on a general address disposition. Normally returns non-zero value (1), but can return 0 if something wasn't recognized. */ int hdrctls_generic_disp( string keydata ) { // Look for special "/xxx" switch if ( $str_byte( keydata, 0 ) == '/' ) { if ( keydata == "/keep" ) { sieve { keep; } return ( 1 ); } if ( keydata == "/discard" ) { sieve { discard; } return ( 1 ); } if ( keydata =? "/p*:*" ) { if ( ( hdrctls_pri_n == 0 ) || ( (int)$str_match(1) < hdrctls_pri_n ) ) { hdrctls_pri_n = (int)$str_match(1); hdrctls_pri_s = $str_match(2); } return ( 0 ); } return ( 0 ); // Unrecognized } // Maybe it's a [xxx] foldername to file into. if ( keydata =? "[*]" ) { sieve { fileinto [$str_match(1)]; } return ( 1 ); } // Blank will be taken to be "keep" if ( keydata == "" ) { sieve { keep; } return ( 1 ); } // Anything else is mfl code. Run it. $mfl_run_string( keydata, "Mc" ); return ( 1 ); }; /* hdrctls_1a -- check the address in a header that has a single address. hdrname is the header name to look in. It will be the name of a header that only has a single address (From, Sender, etc) or something that might get parsed the same as an address (like List-ID). Checks the hdrctls cdb file for the entire address. The key is simply the header name. Assumes that the hdrctls.cdb file is open with handle pointed to by hdrctls_cdbP. Returns 0 if no check matched; 1 if something did. */ int hdrctls_1a( string hdrname ) { /* Try the entire address. The key will be :address */ if ( sieve { address :matches [hdrname] "*" } ) { hdrctls_s1P = hdrctls_lookup( hdrname + ":" + $str_lower( $str_match(1) ) ); /* If we found something, act on it */ if ( hdrctls_s1P != NULL ) { return ( hdrctls_generic_disp( *hdrctls_s1P ) ); } } /* Nope. */ return ( 0 ); }; /* hdrctls_1a_parts -- check the different parts of an address in a header that has just a single address. hdrname is the header name to look in. It will be the name of a header that only has a single address (From, Sender, etc). (Note that it may be technically possible for some of these to have multiple addresses; we deal only in the 1-address case.) Checks the hdrctls cdb file for the entire address, the localpart, and the domain, using a key formed from the header name, a hyphen, and the word "address" or "localpart" or "domain". Assumes that the hdrctls.cdb file is open with handle pointed to by hdrctls_cdbP. Returns 0 if no check matched; 1 if something did. */ int hdrctls_1a_parts( string hdrname ) { /* We'll do several cdb lookups until we find something, and then if we have found something will act on it. */ hdrctls_s1P = NULL; /* Try the entire address. The key will be -address:address */ if ( ! sieve { address :matches [hdrname] "*" } ) return ( 0 ); // No address, no need to continue. hdrctls_s1P = hdrctls_lookup( hdrname + "-address:" + $str_lower( $str_match(1) ) ); /* Try the domain in the address. The key will be -domain:domain */ if ( ( hdrctls_s1P == NULL ) && ( sieve { address :matches :domain [hdrname] "*" } ) ) { hdrctls_s1P = hdrctls_lookup( hdrname + "-domain:" + $str_lower( $str_match(1) ) ); } /* Try the localpart in the address. The key will be -localpart:localpart */ if ( ( hdrctls_s1P == NULL ) && ( sieve { address :matches :localpart [hdrname] "*" } ) ) { hdrctls_s1P = hdrctls_lookup( hdrname + "-localpart:" + $str_lower( $str_match(1) ) ); } /* Now if we found something, act on it */ if ( hdrctls_s1P != NULL ) { return ( hdrctls_generic_disp( *hdrctls_s1P ) ); } /* Nope. */ return ( 0 ); }; /* Function to look at recipient addresses. Scans all header lines and processes addresses that it finds in To and Cc. Each address will test the hdrctls database keys: xx-address xx-localpart xx-domain */ int hdrctls_recip_addrs() { hdrctls_hdrP = $msgpart_hdr_first(); for ( ; ; ) { if ( hdrctls_hdrP == NULL ) break; hdrctls_hname = $str_lower( *$str_sub( *hdrctls_hdrP->h_nameP, 0, $str_length( *hdrctls_hdrP->h_nameP) -1 ) ); if ( ( hdrctls_hname != "to" ) && ( hdrctls_hname != "cc" ) ) { hdrctls_hdrP = $msgpart_hdr_next( hdrctls_hdrP ); continue; } $str_bx_set( *hdrctls_hdrP->h_tailP, 0 ); while ( ( hdrctls_s1 = $msg_address( *hdrctls_hdrP->h_tailP ) ) != "" ) { // Try keys -address, -localpart, and -domain hdrctls_s1P = hdrctls_lookup( hdrctls_hname + "-address:" + $str_lower( hdrctls_s1 ) ); if ( ( hdrctls_s1P == NULL ) && ( hdrctls_s1 =? "*@*" ) ) { hdrctls_s1P = hdrctls_lookup( hdrctls_hname + "-localpart:" + $str_lower( $str_match( 1 ) ) ); if ( hdrctls_s1P == NULL ) { hdrctls_s1P = hdrctls_lookup( hdrctls_hname + "-domain:" + $str_lower( $str_match( 2 ) ) ); } } // If we got a key looked up, process it. if ( hdrctls_s1P != NULL ) { return ( hdrctls_generic_disp( *hdrctls_s1P ) ); } } // Step to next header hdrctls_hdrP = $msgpart_hdr_next( hdrctls_hdrP ); } // Nothing found. return ( 0 ); }; /* Function to do all of the hdrctls checks. Returns 0 if nothing was found, non-zero if something was found and acted upon. */ int hdrctls() { /* Open the database and return if it isn't there. */ hdrctls_cdbP = $cdb_open( "hdrctls.cdb" ); if ( hdrctls_cdbP == NULL ) return ( 0 ); hdrctls_result = hdrctls_1a_parts( "from" ) || hdrctls_1a_parts( "sender" ) || hdrctls_1a( "list-id" ) || hdrctls_1a_parts( "return-path" ) || hdrctls_recip_addrs() || ( ( hdrctls_pri_n > 0 ) ? hdrctls_generic_disp( hdrctls_pri_s ) : 0 ); $cdb_close( hdrctls_cdbP ); return ( hdrctls_result ); };