#! /usr/bin/perl # # $Id$ # Copyright (C) 2002-2003 Jan Kratochvil # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA package PerlMail::Config; use vars qw($VERSION); $VERSION=do { my @r=(q$Revision$=~/\d+/g); sprintf "%d.".("%03d"x$#r),@r; }; use strict; use warnings; require Exporter; use vars qw(@ISA @EXPORT); @ISA=qw(Exporter); @EXPORT=qw( $HOME $Mail @ValidUsers $IdleMax $MaxBodySMS @SMSwebRcpt $SMSwebRcpt_username $Lock_pathname $PeerAddr $Socket_timeout $DB_table $DBI_database $DBI_user $DBI_pwd $sendmail_orig @addr_addon &FromAddress @h_rcpt @h_from %audit_profile @sms_squeezes @alternates_host @dnsbl_whitelist $Audit $is_pgp $opt_F $procmailFROM_MAILER $store_ignore $store_ignorenewmail $store_profile ); require Mail::Alias; BEGIN { for (qw(headerhas store headeris did dnsbl store_muttrc_alternates Received_for parts_linear mime_type body_first mimehead spamassassin header_remap)) { eval 'sub '.$_.' { return ::'.$_.'(@_); }'; } } # perlmail-accept & perlmail-sendmail # Various configuration files location is derived from it: our $HOME="/home/USERNAME"; # perlmail-accept # Mail folder: our $Mail="$HOME/Mail"; # Users respected for the 'idle' state (see $IdleMax): our @ValidUsers=qw(root USERNAME _local); # Maximum number of local console idle seconds while still considered as 'active user': our $IdleMax=10; # Maxium number of bytes to pass to Lingua::EN::Squeeze (performance optimization): our $MaxBodySMS=0x1000; # Telephone number to send SMSes by WWW::SMS to: our @SMSwebRcpt=qw(123 456 789123); # Some WWW::SMS modules require username: our $SMSwebRcpt_username="SMSUSERNAME"; # perlmail-submit # Global system lock for exclusive $DB_table access: our $Lock_pathname="/tmp/PerlMail.lock"; # 'workstation' hostname and port. Hostname may be dyndns: our $PeerAddr="workstation.hostname.tld.:852"; #our $PeerAddr="127.0.0.1:2852"; # 15sec is NOT enough as the remote peer must complete mail store: our $Socket_timeout=7600; # MySQL table name: our $DB_table="PerlMail_folder"; # MySQL database name: our $DBI_database="USERNAME"; # MySQL user name: our $DBI_user="USERNAME"; # MySQL user password: our $DBI_pwd=$ENV{"HOME"}."/priv/mysql.".$DBI_user.".pwd"; # perlmail-sendmail # Pathname of the original sendmail(8) binary: our $sendmail_orig=(-x ($_="/usr/sbin/sendmail-orig") ? $_ : "/usr/sbin/sendmail"); # List of addresses to locally Bcc all mails to: # Mail-Alias-1.12 defaults to "/etc/mail/aliases" which does not exist on RedHat sendmail-8.12.5-7 # Mail-Alias-1.12 will clutter $_ ! our @addr_addon=(Mail::Alias->new("/etc/aliases")->exists("sentout") ? ("sentout") : ()); our $opt_F; # imported our $is_pgp; # imported # Generate new From address for the target $rcpt of type Mail::Address. # $iserror is true for "MAIL FROM" RFC821 address, false for "From:" RFC822 address. # Returns: Mail::Address instance. sub FromAddress { my($rcpt,$iserror)=@_; my $phrase=(defined $opt_F ? $opt_F : "FULL NAME"); return Mail::Address->new($phrase,'USER@DOMAIN.TLD'); } # RedHat sendmail-8.9.3-20/src/conf.c/HdrInfo[]/\Q/* destination fields */\E # FIXME: Recognize "Resent-$_" headers for -t but when we are in 'resent' mode? our @h_rcpt=( # case in-sensitive! "To", "Cc", "Bcc", "Apparently-To", ); # ordering matters; first header found is substituted # last header is subsituted if no one is found our @h_from=( "Resent-From", "From", ); # My-Audit # Setup profile names. # First element of /^=/ form copies it referenced profile to be extended. # 'did' =>did() subroutine will return true for it. # 'syslog' =>Use syslog(3). # 'bell' =>Bell sound. # 'sms=\d+'=>Send SMS by WWW::SMS with specified maximum # of parts our %audit_profile=( "btw" =>[], "silent"=>["=btw" ,"did"], "log" =>["=silent","syslog"], "bell" =>["=log" ,"bell"], "sms" =>["=bell" ,"sms=1"], "crit" =>["=sms" ,"sms=3"], ); # Try the squeezing methods in this order: our @sms_squeezes=( { "SqueezeControl"=>"noconv" }, { "SqueezeControl"=>"conv" ,"SQZ_OPTIMIZE_LEVEL"=>0 }, { "SqueezeControl"=>"conv" ,"SQZ_OPTIMIZE_LEVEL"=>1 }, { "SqueezeControl"=>"med" ,"SQZ_OPTIMIZE_LEVEL"=>0 }, { "SqueezeControl"=>"med" ,"SQZ_OPTIMIZE_LEVEL"=>1 }, { "SqueezeControl"=>"max" ,"SQZ_OPTIMIZE_LEVEL"=>0 }, { "SqueezeControl"=>"max" ,"SQZ_OPTIMIZE_LEVEL"=>1 }, ); # Hostnames where we had old/alternate e-mail addresses: our @alternates_host=( ); # Override DNS blacklists: our @dnsbl_whitelist=( "64.49.222.22", # mail.pm.org: rackspace.com.spam-support.blackholes.five-ten-sg.com. "208.147.243.5", # gambit.liquidcomm.net: cw.net.spam-support.blackholes.five-ten-sg.com. "205.139.198.11", # eniac.disaster.com: cw.net.spam-support.blackholes.five-ten-sg.com. "127.0.0.2", # 2.0.0.127.relays.ordb.org. "65.113.40.131", # bozo.vmware.com: qwest.net.spam-support.blackholes.five-ten-sg.com. "66.218.85.33", # mta2.wss.scd.yahoo.com: yahoo.com.spam.blackholes.five-ten-sg.com. ); our $Audit; # imported our $procmailFROM_MAILER; # imported our $store_ignorenewmail; # imported our $store_profile; # imported our $store_ignore; # imported sub audit { $store_profile=undef(); # never spawn new mail if FROM_MAILER # $isFROM_MAILER postponed after maillists as they may look as FROM_MAILER #use re 'debug'; my $isFROM_MAILER=$Audit->header()=~/$procmailFROM_MAILER/mio; $store_ignorenewmail=(0 || $isFROM_MAILER || headerhas "From",'' ); # spam honeypots return if did sub { local $_; # Do not local $store_file as it is our-imported $store_profile="silent"; store "=spam" if headeris "From",''; store "=spam" if headeris "From",''; { # weak detection: files with text/html w/o text/plain are usually a spam my @types_linear=map({ mime_type($_); } parts_linear()); store "=spam" if grep({ $_ eq "text/html"; } @types_linear) && !grep({ $_ eq "text/plain"; } @types_linear); } store "=spam" if ($_=mimehead(body_first())->mime_attr("Content-Type.charset")) && /^big5/i; }; $store_profile=undef(); # spam detection return if did sub { # Do not local $store_file as it is our-imported $store_profile="silent"; local $_; store "=spam".($_ eq 1 ? "" : ";$_") if $_=spamassassin(); }; $store_profile=undef(); return if did sub { # Do not local $store_file as it is our-imported $store_profile="silent"; local $_; store "=spam" .";$_","log" if $_=dnsbl '.relays.ordb.org.' ,1; # all hosts store "=spam" .";$_","log" if $_=dnsbl '.blackholes.mail-abuse.org.' ,1; # all hosts # we don't check all hosts as they can be "dialup" category, FIXME: check for it store "=spam" .";$_","log" if $_=dnsbl '.blackholes.five-ten-sg.com.',0; # just first # I don't send viruses but viruses propagate mails of mine store "=spam" if headeris "X-Mailer",'ravmd/8.3.2'; }; $store_profile=undef(); # ppl-wished foreign remapping, Reply-To is left untouched! # FIXME: modifications are now being dropped by &write_message! header_remap("From",{ 'RECEIVED@ADDRESS.TLD'=>'MAP_TO@ADDRESS.TLD', }); # My obsolete e-mail addresses store_muttrc_alternates "=redirect-","btw"; # nasty public lists with $store_ignore { # Do not local $store_file as it is our-imported $store_profile="log"; local $store_ignore; $store_ignore="smsmail" if 1==$Audit->body() && length(join "",$Audit->body())<180; # SMS mail $store_ignore="list-moron" if grep { headeris "From",$_; } qw( ); store "=LOCALNAME" if headeris "Sender" ,''; } $store_profile=undef(); # lists store "=LIST","log" if headeris "List-Id" ,''; store "=errm","bell" if $isFROM_MAILER && !did(); store "==","sms" if !did; } sub audit_sms_address { my($obj)=@_; my $address=$obj->address(); if (my $alternates=muttrc_get("alternates")) { return "I" if $address=~/$alternates/si; } my %aliases=muttrc_aliases(); if (my $alias=$aliases{lc $address}) { local $_=$alias; s/\b(Bus)siness$/$1/i; s/\.ident$//i; return $_; } local $_=$address; s/\.cz$//i; return $_; } # $args{"from"} # $args{"subject"} # $args{"body"} sub audit_sms { my(%args)=@_; my $from=(@{$args{"from"}} ? join(",",map({ audit_sms_address($_); } @{$args{"from"}})) : "?"); local $_; $_=$args{"subject"}; # headers s/(?:Re|Aw|Odp|Fw|Fwd|OT)(?:\[\d+\])?://ig; # former subject s/\bbylo:.*$//i; s/\[\s*WAS:.*\]\s*$//i; # trim s/^\s*//s; s/\s*$//s; my $subject=$_; $_=$args{"body"}; # max. 9 lines of .sig s/\n-- (?:\n[^\n]*){0,9}$//gs; # "Original Message"/"Puvodni zprava" etc. up to empty line # "- - - Original message: - - -" is by "Lotus Notes Release 5.0.5 September 22, 2000" s/(^|\n)[\s^\n]*(?:-----[\w\s]*-----|- - - Original message: - - -)[\s^\n]*(?:\n[^\n]+)*\n{2,}(?:\s*[^>\s].*$)?/\n/gs; # Remove "..." lines (is it used by anyone except me?) s/^\Q...\E$/*/gm; # quoting "> " s/^(?:\s*[[:upper:]]{0,3}>)+.*$/*/gm; s/(?:^|\n)(?:\*\n+)+/\n*\n/gs; # attributions s/^.*\b(?:wrote|writes|napsal jste):\s*$//gm; my $body=$_; return [$from,"($subject)$body"]; } 1;