#!/usr/bin/perl -w
# -*- mode: cperl -*-
#
# MyFilter.pm -- config file for parp
#
# Copyright (c) 2000 Adam Spiers <adam@spiers.net>. All rights
# reserved. This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
#
# $Id: MyFilter.pm.adam,v 1.190 2001/11/23 19:54:28 adam Exp $
#

##############################################################################
##
## Don't edit this bit unless you know what you are doing.
##

package MyFilter;

use strict;
use vars qw(@ISA @EXPORT_OK);
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(%CONFIG %RE %lists
                &is_special &is_list_mail &is_from_daemon
                &deliver_mail);

use vars qw(%CONFIG %RE %lists &log_to_file);


##############################################################################
##
## Filenames and other miscellaneous configuration.
## These should be self-explanatory; edit at will.
##

{
  # Directory where delivery folders who do not have
  # a `/' specified live
  my $mail_dir  = "$ENV{HOME}/mail";

  # Directory containing inboxes
  my $inbox_dir = "$mail_dir/inboxes";

  %CONFIG = (
             # Leave these two alone
             mail_dir        => $mail_dir,
             inbox_dir       => $inbox_dir,

             # Main inbox
             main_folder     => "$inbox_dir/MAIN",

             # Backup folder
             backup_folder   => "$mail_dir/backup",

             # Folder where reports of parp fatal errors are
             # delivered
             fatals_folder   => "$inbox_dir/parp-fatals",

             # Name of file where parp logs everything it does
             log_file        => "$mail_dir/.parp.log",

             # Name of parp's lock file
             lock_file       => "$mail_dir/.parp.lock",

             # Filename for DBM database of your friends
             friends_db      => "$mail_dir/.friends.db",

             # Cache containing Message-ID's of recent messages,
             # used to eliminate duplicates
             id_cache        => "$mail_dir/.parp.msgid.cache",

             # Maximum number of Message-IDs in cache
             max_cache_ids   => 200,

             # Value of X-Loop header set
             loop_value      => 'Adam Spiers',

             # If the subject line or header corresponding to
             # the password_header value below match the following
             # password, the mail is given special consideration
             password        => 'fragglerock',
             password_header => 'X-Password',

             # Threshold number of recipients before an e-mail
             # is considered as spam
             max_recipients  => 100,
            );
}


##############################################################################
##
## Various Perl regular expressions and accompanying settings used
## during filtering.  These should be self-explanatory; edit at will.
##

%RE = (
       # Addresses I currently want to receive mail to
       me     => qr/
                    adam\@spiers\.net                                   |
                    adam\.spiers\@musician\.org                         |
                    adam\.spiers\@new\.ox(ford)?.ac.uk                  |
                    adam(-.+)?\@thelonious\.new\.ox\.ac\.uk             |
                    zsh-mirror(-.+)?\@thelonious\.new\.ox\.ac\.uk       |
                    a\.?spiers\@ram\.ac\.uk                             |
                    (adams?|aspiers|translations|bugzilla-admin|
                     cvs-admin
                    )\@guideguide\.com                                  |
                    aspiers\@cpan\.org                                  |
                    .*@(adamspiers|tigerpig)\.org                       |
                    adamspiers\@users\.sourceforge\.net                 |
#                   8439\@excite\.com|associate                         |
                    this_should_never_match
                   /ix,

       # Old addresses I don't want people to use any more
       old_me => qr/
                    adam\.spiers\@new\.ox(ford)?.ac.uk                  |
                    (irc.*|peanuts)\@thelonious\.new\.ox\.ac\.uk        |
                    it-support\@thelonious\.new\.ox\.ac\.uk             |
                    m93asp\@(.+\.)?ecs\.ox\.ac\.uk                      |
                    (adams?|aspiers)\@mediaconsult\.com                 |
                    newc0115\@sable\.ox\.ac\.uk
                   /ix,

       # Addresses similar to mine.  If an e-mail has more recipients
       # matching this than the threshold specified, it must be a spam
       # which has been sent to everyone in a massive alphabetically
       # sorted list.
       max_like_me => 4,
       like_me => qr/adam.*\@/i,

       # Decoy addresses I hand out to people who I don't trust not to
       # spam me.  e-mail to these addresses still comes to me, but makes
       # for very easy filtering.
       decoys => qr/(
                     adam-spam(-.+)?\@thelonious\.new\.ox\.ac\.uk
                    )/ix,
       
       # Work domains
       gg     => qr/(guideguide|mediaconsult)\.com/,

       # Domains I really trust
       good_domains =>
                 qr/
                    [.@]
                    (
                     [\w\.-]+\.ac\.uk        |
                     guideguide\.com         |
                     mediaconsult\.com       |
                     redhat\.com             |
                     ibm\.com                |
                     valinux\.com            |
                     mozilla\.org            |
                     infospace\.com          |
                     securityfocus\.com
                    )
                    \b
                   /ix,

       # Don't check these hosts on blacklists
       good_IPs => [ qw(
                        163.1.*
                        oxmail.ox.ac.uk
                        oxmail1.ox.ac.uk
                        oxmail1.ox.ac.uk
                        oxmail1.ox.ac.uk
                       ) ],

       # If a subject matches this, I want to see the e-mail. 
       subject_buzzwords =>
                 qr/\b(
                       cello                   |
                       chess                   |
                       dbm                     |
                       fmscore                 |
                       freshmeat               |
                       guideguide              |
                       jazz                    |
#                       juggling                |
                       Linux                   |
                       logfilterd              |
                       mozilla                 |
                       mysqldiff               |
                       nick.?o.?met(er|re)     |
                       palm(source)?           |
                       parp                    |
                       Perl                    |
                       pjb                     |
                       plig                    |
                       plucker                 |
                       quietrun                |
                       sawfish                 |
                       seamonkey               |
                       shells?                 |
                       thinkpad                |
                       tigerpig                |
                       ttm                     |
                       uri                     |
                       visor                   |
                       zsh 
                      )\b/ix,

       bad_from =>
                 qr/(
                     adotson                           |
                     gpaparian\@earthlink\.net         |
                     grandmasters\@.*\.nl              |
                     gmc.*grandmasters                 |
                     marketing                         |
                     mjiwyuez                          |
                     santhigirihealth                  |
                     travelincentives                  |
                     dont_ever_match_this_one_it_comes_last
                    )/ix,

       # If a subject matches this, I don't want to see the e-mail. 
       bad_subjects =>
                 qr/(
                     \b adv? \b                   |
                     \${3}                        |
                     \$\d{1,3}(,\d{3})+ \b        |
                     \b GUARANTEED \b             |
                     \b bad \s+ credit \b         |
                     \b beauty \s+ secret \b      |
                     \b bulk \s+ (e.?)? mail      |
                     \b cheerleaders \b           |
                     \b chance \s+ to \s+ win \b  |
                     \b credit \b                 |
                     \b free \s+ for .* limited \s+ time   |
                     \b free \s+ cash \b          |
                     \b debt \s+ reduction        |
                     \b hollywood \b              |
                     \b lose \s+ weight \b        |
                     \b money [\s-]+ back \b      |
                     \b penis.*enlarge            |
                     \b toner.*cartridge          |
                     \b weight \s+ loss \b        |
                     \b win \s+ (big|millions) \b |
                     \b (win|dream) \s+ (holiday|vacation) |
                     \b (holiday|vacation) .* \b win       |
                     \b wholesale                 |
                     \b your \s+ info \s* !!      |
                     \.biz \b                     |
                     dont_ever_match_this_one_it_comes_last
                    )/ix,

       # If a To: matches this, I don't want to see the e-mail. 
       bad_to => qr/\b(you|friend)\b/i,

       # If any of the X-Mailer, Received or Organisation headers
       # matches this, I don't want to see the e-mail.
       bad_words =>
                 qr/(
#                    Aristotle                      |
                     Avalanche                      |
#                    bulk_mailer                    |
                     click.here                     |
                     Cyber-Bomber                   |
                     Cyberpromo                     |
                     DiffondiCool                   |
                     E-Broadcaster                  |
                     Emailer.?Platinum              |
                     eMerge                         |
                     Extractor                      |
                     e-Merge                        |
                     Floodgate                      |
                     from.?stealth                  |
#                    fusion                         |
                     get.rich.quick                 |
                     Global\ Messenger              |
                     GOTO\ Software\ Sarbacane      |
                     iemmc                          |
                     i\.e\.m\.m\.c                  |
                     Mach10                         |
                     MassE-Mail                     |
                     massmail\.pl                   |
                     NetMailer                      |
                     Powermailer                    |
                     Quick\ Shot                    |
                     \b RAF \b                      |
                     Ready\ Aim\ Fire               |
                     \b RIME \b                     |
                     shoppingplanet                 |
                     stealth                        |
                     success.network                |
                     WinNT's\ Blat                  |
                     WorldMerge                     |
                     dont_ever_match_this_one_it_comes_last
                    )/ix,

       # If any of the headers which may include originating
       # domains matches this, I don't want to see the e-mail.
       bad_origins =>
                 qr/(
                     163\.com                         |
                     acba\.org                        |
                     addism                           |
#                    angelfire\.com                   |
                     answerme\.com                    |
                     apexmail\.com                    |
                     batanga\.com                     |
                     bennersgardens                   |
#                    bigfoot\.com                     |
#                    blueyonder                       |
                     bulk.{0,3}mail                   |
                     casino\.com                      |
                     centreexchange                   |
                     chinahot\.com                    |
                     chello                           |
                     clone-entertainment              |
                     clubmom\.com                     |
                     commonwealthpub\.com             |
                     ctrl-alt-del                     |
                     cyberpromo\.com                  |
                     cybertunes\.com                  |
                     debt.?free                       |
                     dragonfans\.com                  |
#                    earthlink\.net                   |
                     export2000                       |
                     fotoasia\.com                    |
                     gambling                         |
#                    geocities\.com                   |
                     greece\.com                      |
                     goodnews                         |
                     grootmeesters.nl                 |
                     hermisan                         |
                     hotelmajestic.es                 |
                     howtogetthingsdone               |
                     infosquare\.com                  |
                     interramp\.com                   |
#                    juno\.com                        |
                     keyanoc\.ab\.ca                  |
                     mailers\.com                     |
                     manbond\.com\.hk                 |
                     medicinehorizons                 |
                     melrun\.org                      |
#                    ml\.org                          |
                     monsterinallforms                |
                     mundomail                        |
                     netvigator\.com                  |
                     n75gh5\.com                      |
                     ntec\.net                        |
                     nbyprod                          |
                     oin\d\.net                       |
                     oo\.net                          |
                     pandora\.be                      |
                     paymentonline\.com               |
                     penis                            |
                     porno                            |
                     prideofamerica                   |
                     promo                            |
                     psi\.com                         |
                     public\.com                      |
                     ris\.net                         |
#                    rocketmail\.com                  |
                     rvjeep                           |
                     savetrees\.com                   |
                     sea.?river                       |
                     shoushin                         |
                     sina\.com                        |
                     specialtysalesonline.com         |
                     stadsnet                         |
                     streamlinenet\.com               |
                     stungunworld                     |
                     skymail                          |
                     tcg-corp                         |
                     tellustalk\.com                  |
                     tm\.net\.my                      |
                     trafficmagnet                    |
                     tripod\.com                      |
#                    usa\.net                         |
#                    uu\.net                          |
                     worldwideentertainmentusa        |
                     dont_ever_match_this_one_it_comes_last
                    )/ix,

       # If the body has more than ...
       max_forwards_lines => 50,
       # ... lines containing more than ...
       max_forwards => 15,
       # '>' quotation marks, I don't want to see it.

       # If the body matches this more than the given amount, I don't
       # want to see the e-mail.  Be very careful what you put in
       # here!
       max_quite_bad_words => 8,
       max_unique_quite_bad_words => 5,
       quite_bad_words =>
                 qr/\b
                    (
                     advertising                               |
                     apologies                                 |
                     bill(?:ing)?                              |
                     [bm]illions?                              |
                     break.?through                            |
#                    business(?:es)?                           |
                     catalog                                   |
                     cheap                                     |
                     classifieds?                              |
                     clearance                                 |
                     commerc(?:e|ial)                          |
                     confidential                              |
                     compliance                                |
                     credit.?(?:card|file)                     |
                     deals?                                    |
                     discount                                  |
                     earnings?                                 |
                     e.?commerce                               |
                     financial                                 |
                     fortunes?                                 |
                     free                                      |
                     gifts?                                    |
                     guaranteed?                               |
                     horny                                     |
                     hottest                                   |
                     legal                                     |
                     limited                                   |
                     income                                    |
                     inexpensive                               |
                     invest(?:ment|[oe]r)s?                    |
                     invite[ds]                                |
                     long.distance                             |
                     low.prices                                |
                     management                                |
                     marketing                                 |
                     marketee?rs                               |
                     merchants?                                |
                     money                                     |
                     multi.?media                              |
                     new\s+e.?mail\s+bill                      |
                     online                                    |
                     opportunit(?:y|ies)                       |
                     order(?:s|ing)                            |
                     payable                                   |
                     portfolio                                 |
                     potential                                 |
                     profit(?:s|able)?                         |
                     promotions?                               |
                     prosperity                                |
                     proven                                    |
                     publicity                                 |
                     purchase                                  |
                     receive                                   |
                     results                                   |
                     risk                                      |
                     sales?                                    |
                     shipping                                  |
                     spam                                      |
#                    subscribe                                 |
                     targeted                                  |
                     trial                                     |
                     viagra                                    |
                     wealth
                    )
                    \b         
                   /ix,

       # If the body matches this, I don't want to see the e-mail.
       # Be very careful what you put in here!
       very_bad_words =>
                 qr/(
                     adults.only                               |
                     bulk .{0,5} mail                          |
                     bulk.e.?mail.software                     |
                     call\s+now\s*!{2,}                        |
                     cardholders?                              |
                     cyberprofit                               |
                     debt\s+consolidation                      |
                     Extractor \s+ Pro                         |
                     free.of.charge                            |
                     grootmeesters                             |
                     million.*addresses                        |
                     \b mlm \b                                 |
                     money [\s-]+ back \s+ guarantee           |
                     multi.?[bm]illion.dollar                  |
                     multi.?level.marketing                    |
                     no.future.e?.?mail                        |
                     (one.time|once.off).(message|mail)        |
                     opt[ -](in|out)                           |
                     (live|phone).sex                          |
#                     \b promo \b                               |
                     rather not.*receive.?                     |
#                     search.engines?                           |
                     this.really.works                         |
                     toll.?free                                |
                     trolltv                                   |

                     \b \$\d{1,3}(,\d{3})+ \b                  |
                     \${4}'s                                   |

       this\s+(e?.?mail|message)\s+is\s+(being\s+)?sent\s+in\s+compliance |
       (?s:Hi!\s+How\s+are\s+you.+I\s+send\s+you\s+this\s+file\s+in\s+order\s+to\s+have\s+your\s+advice) |

                     # American phone numbers
                     \b (800|900|877|888) ([-\ ])
                     (
                       (?-i: [A-Z]{2,} (\7 [A-Z]+)* )          |
                       \d{3} \7 \d{4} \b
                     )                                         |
                     \b \(\d{3}\) \  \d{3}-\d{4} \b
                    )/ix,

       # If the body, or any nested multiparts have a Content-Type
       # matching this, I don't want to see it.
       bad_content_type => qr/charset="(ks_|.*-jp)/,
      );


## Define any mailing lists you're on here.
##
## The key on the left is the name of the inbox, and the regular
## expression on the right is what either the From, To, or Cc header
## should match for the mail to be identified as belonging to the
## list.  If a `subject_RE' key is given in the hash on the right, any
## mail whose subject matches the corresponding regular expression
## will also be associated with the list.
##
## For convenient typing, the %s will get replaced by the key on the
## left.

%lists =
  (
   ## hardware

   'linux-thinkpad'   => {
                           RE => '%s.*topica\.com',
                           subject_RE => qr/\[LTP\]/,
                         },
   'linux-laptop'     => { RE => '%s.*vger\.rutgers\.edu' },
   'lhd'              => { RE => 'lhd.*datapower\.com' },


   ## software

   'alsa-announce'    => { RE => '%s.*alsa-project\.org' },
   'alsa-devel'       => { RE => '%s.*alsa-project\.org' },
   'alsa-user'        => { RE => '%s.*alsa-project\.org' },
   'apmd-list'        => { RE => '%s.*worldvisions\.ca' },
   'bashprompt'       => { RE => 'bash.*current\.nu' },
   'buggies'          => { RE => '%s@landfill\.tequilarista\.org' },
   'fetchmail'        => { RE => '%s-friends.*@lists\.ccil\.org' },
   'galeon-user'      => { RE => '%s.*sourceforge\.net' },
   'galeon-devel'     => { RE => '%s.*sourceforge\.net' },
   'gconf-list'       => { RE => '%s.*gnome\.org' },
   'gimp-perl'        => { RE => 'gimp-perl.*lists\.netcentral\.net' },
   'gnokii'           => { RE => '%s@net.lut.ac.uk' },
   'gnome-pilot'      => { RE => '%s.*@gnome\.org' },
   'gphoto-devel'     => { RE => '%s.*@gphoto.(net|org)' },
   'gphoto'           => { RE => '%s@gphoto.(net|org)' },
   'gqview-users'     => { RE => '%s.*sourceforge\.net' },
   'infobot'          => { RE => '%s.*(cs\.cmu\.edu|metronomicon\.com|' .
                                      'infobot\.org)' },
   'linux-diald'      => { RE => '%s.*vger\.rutgers\.edu' },
   'linux-smp'        => { RE => '%s.*redhat\.com' },
   'mod-perl'         => { RE => 'modperl@apache.org' },
   'mozilla-announce' => { RE => '%s.*mozilla\.org' },
   'mozilla-bugzilla' => { RE => 'bugzilla-daemon@mozilla\.org' },
   'mutt-announce'    => { RE => '%s@mutt\.org' },
   'perlunit-devel'   => { RE => '%s.*sourceforge\.net' },
   'perlunit-users'   => { RE => '%s.*sourceforge\.net' },
   'pjbox'            => { RE => '%s.*@phobos\.(fs\.tum|fachschaften\.tu-muenchen)\.de' },
   'plucker-dev'      => { RE => 'plucker.*@.*rubberchicken\.org' },
   'redhat-contrib'   => { RE => '(contrib|redhat)-list.*redhat\.com' },
   'redhat-bugzilla'  => { RE => 'bugzilla@bugzilla\.redhat\.com' },
   'rep-gtk'          => { RE => '%s.*sourceforge\.net' },
   'req'              => { RE => 'req.*ccs\.neu\.edu' },
   'reqng'            => { RE => 'reqng\.ml\.org|scuttlebutt\.explore\.com|' .
                                 'reqng.*sycore\.net' },
   'sawfish'          => { RE => 'saw(mill|fish).*(aarg\.net|eazel\.com)' },
   'sitescooper'      => { RE => '%s.*lists\.sourceforge\.net' },
   'zsh/announce'     => { RE => 'zsh-announce.*(sunsite\.(auc\.)?dk|math\.gatech\.edu)' },
   'zsh/users'        => { RE => 'zsh-users.*(sunsite\.(auc\.)?dk|math\.gatech\.edu)' },
   'zsh/workers'      => { RE => 'zsh-workers.*(sunsite\.(auc\.)?dk|math\.gatech\.edu)' },


   ## chatter

   'oxford-pm'        => { RE => '%s-list.*pm\.org' },
   'london-pm'        => { RE => 'london-list.*pm\.org' },
   'unix-admin'       => { RE => '%s.*comlab\.ox(ford)?\.ac\.uk' },
   'void'             => { 
                           RE => '(void|slobber).*(slab\.org|(guideguide|mediaconsult)\.com)',
                           subject_RE => '^(Re: )?\(void\) ',
                         },


   ## security

   'bugtraq'          => { RE => '%s.*(netspace\.org|securityfocus\.com)' },
   'linux-alert'      => { RE => '%s.*redhat\.com' },
   'linux-security'   => { RE => '%s.*redhat\.com' },


   ## miscellaneous

   'cron'             => { subject_RE => 'Cron <\w+@thelonious>' },
   'interjazz'        => { RE => 'interjazz@interjazz.com' },
  );


##############################################################################
##
## User-defined filtering routines.
##
## They are invoked as methods, so the first parameter is always the
## Mail::Filterable object, which contains all the information you
## would normally need to perform standard tests on it.  For example,
## if $m is the object, $m->{subject} is the subject line, and
## $m->matches('ftc', $re) is a method which returns true if the regexp
## $re matches any of the e-mail addresses found in the From, To, Cc
## (or X-Mailing-List) headers.  See Mail::Filterable::new() in the
## main program for all available data.
##
## Once you have performed tests and determined what action you want
## to take for a given e-mail, there are some useful methods available
## for taking the action, including:
##
##   $m->accept_mail($reason, @details);      # tag mail as accepted
##   $m->reject_mail($reason, @details);      # tag mail as rejected
##   $m->reject_junk_mail($reason, @details); # tag mail as rejected junk
##   $m->deliver_to('foo');                   # deliver to folder `foo'
##   $m->deliver_to_inbox('bar');             # deliver to inbox `bar'
##   $m->pipe_forward('command arg1 arg2');   # pipe mail | command arg1 arg2
##
## Return values are also important; see the filter() and
## Mail::Filterable::categorize() routines in the main program to
## understand how they affect filtering.
##


#
# is_special()
#
# Handles special cases before virtually any other filtering
# occurs.  Should return 'IS_SPECIAL' in cases where you want
# to take all appropriate action yourself (e.g. delivery/forwarding).
# Other return values have the normal meaning; for more details
# see Mail::Filterable::categorize() in the main program.
#

sub is_special {
  my $m = shift;

  if ($m->{to} =~ /\b(adam-.*test.*\@thelonious\.new\.ox\.ac\.uk)\b/i) {
    $m->accept_mail('test mail', $1);
    $m->deliver_to_inbox('test');
    return 'IS_SPECIAL';
  }

  if ($m->{to} =~ /\b(adam-.*auto.*\@thelonious\.new\.ox\.ac\.uk)\b/i) {
    $m->accept_mail('auto-reply', $1);
    $m->deliver_to_inbox('autoreply');
    return 'IS_SPECIAL';
  }

  if ($m->{to} =~ /\b(adam-cuteftp\@thelonious\.new\.ox\.ac\.uk)\b/i) {
    $m->ditch_mail('obsolete address', $1);
    return 'IS_SPECIAL';
  }

  if ($m->{to} =~ /\b(adam-.*\@thelonious\.new\.ox\.ac\.uk|.*\@adamspiers.org)\b/i) {
    $m->deliver_to_inbox('alt_addresses');
  }

  if (($m->matches('ftc', qr/buzzaway\.com\b/i))[0]) {
    $m->accept_mail('buzz spam');
    $m->deliver_mail();
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/dpie\.com\b/i))[0]) {
    $m->ditch_mail('Diamond Point spam');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/handspring\.p0\.com\b/i))[0]) {
    $m->accept_mail('handspring news');
    $m->deliver_to_inbox('handspring');
    return 'IS_SPECIAL';
  }

  if ($m->{to} =~ /solo string mailing list/i) {
    $m->accept_mail('solo string');
    $m->deliver_to_inbox('solo_string');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/\bowner.*topica\.com\b/i))[0]) {
    $m->accept_mail('topica');
    $m->deliver_to_inbox('topica');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/\blinux-thinkpad\@topica\.com\b/i))[0]) {
    $m->ditch_mail('no time to read');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/\bwebring\.org\b/i))[0]) {
    $m->accept_mail('webring.org');
    $m->deliver_to_inbox('webring');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/\bexcellnews.*excell\.to\b/i))[0]) {
    $m->accept_mail('eXcell news');
    $m->deliver_to_inbox('eXcell.to');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/\bquios.*\.net\b/i))[0]) {
    $m->accept_mail('quios');
    $m->deliver_to_inbox('quios');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/\bgeniemail\.co\.uk\b/i))[0]) {
    $m->accept_mail('BT Cellnet/Genie');
    $m->deliver_to_inbox('genie');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc',
                   qr/\b(
                         gc-orders.*amazon\.(com|co\.uk)                |
                         cards-bounces.*bounces\.amazon\.(com|co\.uk)
                      )\b/ix))[0]) {
    $m->accept_mail('amazon.com gift certificates');
    $m->deliver_to_inbox('amazon');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/(admin|noreply)\@sourceforge\.net\b/i))[0]) {
    $m->accept_mail('sourceforge.net');
    $m->deliver_to_inbox('sourceforge');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/\bfreshmeat-news\@.*freshmeat\.net\b/))[0]) {
    $m->deliver_to_inbox('freshmeat');
#     $m->pipe_forward('fmscore ' .
#                      ">>$CONFIG{inbox_dir}/freshmeat");
    return 'IS_SPECIAL';
  }

  if ($m->{from} =~ /(nobody|jobs|subscriber(s|\.email))\@.*jobserve\.com/i) {
    $m->pipe_forward("$ENV{HOME}/bin/jobserve");
    return 'IS_SPECIAL';
  }
  
  if ($m->{from} =~ /(jobs-filtered)\@jobserve\.com/i) {
    $m->accept_mail('jobserve jobs (filtered)');
    $m->deliver_to_inbox('jobs-filtered');
    return 'IS_SPECIAL';
  }
  
  if ($m->{subject} =~ /headlines/i and
      ($m->matches('ftc', qr/slashdot\.org/))[0]) {
    $m->accept_mail('slashdot daily news');
    $m->deliver_to_inbox('slashdot');
    return 'IS_SPECIAL';
  }

  if (($m->matches('from_addrs', qr/\@.*\.london\.guideguide\.com/))[0]) {
    $m->accept_mail('guideguide intranet');
    return 'IS_SPECIAL';
  }

  if (  
        ($m->matches('from_addrs', $RE{me}))[0]              &&
      ! ($m->matches('from_addrs', qr/auto|test/))[0] &&
        $m->{mailer}   !~ /[Mm]utt|Eudora .* for PalmOS/     &&
        $m->{reply_to} !~ /adam\@spiers\.net/                &&
        $m->{to}       !~ /cvs-notify|topica\.com|gimp-perl/ &&
        $m->{sender}   !~ /nobody\@.*guideguide\.com/ 
     )
  {
    $m->reject_junk_mail('not /really/ from me');
    return 'IS_SPAM';
  }

  if (($m->matches('ftc', qr/activesw\.com/i))[0] &&
      $m->{subject} =~ /qstat/i) {
    $m->accept_mail('qstat');
    $m->deliver_to_inbox('qstat');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/ntknow\@lists\.ntk\.net/i))[0]) {
    $m->accept_mail('NTK');
    $m->deliver_to_inbox('NTK');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/press.*release.*moneyworld\.co\.uk/i))[0]) {
    $m->ditch_mail('MoneyWorld press release');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/wstearns\@pobox\.com/i))[0]) {
    $m->accept_mail('buildkernel');
    $m->deliver_mail();
    return 'IS_SPECIAL';
  }

  if ($m->{to} =~ /\bIBM\b.*\bSupport Customer/) {
    $m->accept_mail('IBM support');
    $m->deliver_to_inbox('ibm-support');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/announcements\@vmware\.com|vmwarenews/i))[0]) {
    $m->accept_mail('vmware crap');
    $m->deliver_to_inbox('vmware');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/freerealtime\.com/i))[0]) {
    $m->ditch_mail('freerealtime crap');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/brainbench\.com/i))[0]) {
    $m->accept_mail('brainbench crap');
    $m->deliver_to_inbox('brainbench');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/setiathome/i))[0]) {
    $m->accept_mail('setiathome crap');
    $m->deliver_to_inbox('setiathome');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/raxco/i))[0]) {
    $m->ditch_mail('Raxco crap');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/reminder.*myfamily|myfamily.*reminder/i))[0]) {
    $m->ditch_mail('MyFamily reminder');
    return 'IS_SPECIAL';
  }

  if (($m->matches('ftc', qr/notifyservice.*myfamily/i))[0]) {
    $m->ditch_mail('MyFamily notification');
    return 'IS_SPECIAL';
  }

  if ($m->{from} =~ /Member.Update/i &&
      $m->{from} =~ /MyFamily/i) {
    $m->ditch_mail('MyFamily member update');
    return 'IS_SPECIAL';
  }

  if ($m->{from} =~ /news\@mail\.com/) {
    $m->ditch_mail('mail.com crap');
    return 'IS_SPECIAL';
  }

  if ($m->{from} =~ /announcement.*\@mail\.com/i) {
    $m->accept_mail('mail.com announcement');
    $m->deliver_mail();
    return 'IS_SPECIAL';
  }

  if ($m->{from} =~ /apeleg\@interjazz\.com/ &&
      $m->{subject} =~ /InterJazz mailing list/) {
    $m->accept_mail('interjazz');
    $m->deliver_to_inbox('interjazz');
    return 'IS_SPECIAL';
  }
}


#
# is_list_mail()
#
# Should true if an e-mail is from a mailing list or similar,
# and hence should be placed in an auxiliary inbox.  The routine
# is responsible for delivery, however.
#

sub is_list_mail {
  my $m = shift;

  my $rv = deliver_gg_stuff($m);
  return 1 if $rv eq 'NEXT_MAIL';   # ugh

  foreach my $list (keys %lists) {
    if (exists $lists{$list}{backup}) {
      $m->{backup} = $lists{$list}{backup};
    }

    my $dest = $lists{$list}{folder} || "$CONFIG{inbox_dir}/$list";

    if (exists $lists{$list}{RE}) {
      my $RE = $lists{$list}{RE};
      $RE =~ s/%s/$list/g;
      if (($m->matches('ftc', qr/$RE/i))[0]) {
        $m->{list_mail} = "belonged to list `$list' via ftc";
        $m->{list_mail_dest} = $dest;
        last;
      }
    }

    if (exists $lists{$list}{subject_RE}) {
      my $RE = $lists{$list}{subject_RE};
      if ($m->{subject} =~ /$RE/i) {
        $m->{list_mail} = "belonged to list `$list' via subject";
        $m->{list_mail_dest} = $dest;
        last;
      }
    }
  }

  if ($m->{list_mail}) {
    if ($m->{subject} =~ /un.?subscribe\s*$/i &&
        ! ($m->matches('from_addrs', $RE{me}))[0]) {
      $m->reject_mail("someone doesn't know how to unsubscribe");
      return 1;
    }
    else {
      $m->accept_mail($m->{list_mail});
      $m->deliver_to($m->{list_mail_dest});
      return 1;
    }
  }

  if (($m->matches('ftc', qr/hyper\.stanford\.edu/))[0]) {
    my $forum = $m->{header}->get('X-HN-Forum');
    chomp $forum;

    if ($forum eq 'PCMCIA driver beta testing') {
      $m->accept_mail('PCMCIA beta testing forum');
      $m->deliver_to_inbox('pcmcia-beta');
      return 1;
    }
    elsif ($forum eq 'Power Management and PCMCIA') {
      $m->accept_mail('APM/PCMCIA forum');
      $m->deliver_to_inbox('pcmcia-apm');
      return 1;
    }
    else {
      $m->accept_mail('unknown HyperNews forum');
      $m->deliver_mail();
      return 1;
    }
  }

  if ($m->{from} =~ /postmaster\@pdi\.com/) {
    $m->ditch_mail('cretins at pdi.com');
    return 1;
  }

  return 0;
}

{
  my @gg_filters = qw/ggdev gg-dev ggnews gg-uk gg-all
                      gg-bugzilla bugzilla-daemon codereview/;

  sub deliver_gg_stuff {
    my $m = shift;
    return 0 unless ($m->matches('ftc', $RE{gg}))[0];

    if ($m->{subject} =~ /Faq-O-Matic Moderator Mail/) {
      if ($m->{body_scalar} =~ /^Who:\s*aspiers\@guideguide\.com\b/m) {
        $m->ditch_mail('my Faq-O-Matic changes');
      }
      else {
        $m->accept_mail("ggdev faqomatic");
        $m->deliver_to_inbox('gg-faqomatic');
      }
      return 'NEXT_MAIL';
    }

    foreach my $filter (@gg_filters) {
      my $RE = qr/$filter\@.*$RE{gg}/;
      $filter = 'gg-bugzilla' if $filter eq 'bugzilla-daemon';
      $filter = 'ggdev'       if $filter eq 'gg-dev';
      if (($m->matches('ftc', $RE))[0]) {
        $m->accept_mail("belonged to list `$filter'");
        $m->deliver_to("computer-work/$filter");
        $m->{backup} = 0;
        $m->deliver_to_inbox($filter);
        return 'NEXT_MAIL';
      }
    }

    # guideguide cvs commits
    if (($m->matches('ftc', qr/cvs-notify/i))[0]) {
      # keep a complete archive
      $m->accept_mail("gg-cvs-notify");
      $m->deliver_to("computer-work/gg-cvs-notify.%Y-%qq");

      if ($m->{subject} =~ m!moo/(career|images)! ||
          $m->{subject} =~ m!moo/gg/Modules/Foto! ||
          $m->{subject} =~ m!moo/gg/files/xml! ||
          $m->{subject} =~ m!moo/gg/messages! ||
#          $m->{subject} =~ m!architekt|career|friseur|gourmet|krankenhaus|
#                             moebel!ix ||
          $m->{subject} =~ m!<sybase>!)
      {
        $m->ditch_mail('uninteresting gg cvs commits');
        return 'NEXT_MAIL';
      }
      if (($m->matches('from_addrs', $RE{me}))[0]) {
        $m->ditch_mail('my gg cvs commits');
        return 'NEXT_MAIL';
      }
        
      $m->deliver_to_inbox('gg-cvs-notify');
      return 'NEXT_MAIL';
    }

    if ($m->{subject} =~ /bugzilla buglist needs attention/i) {
      $m->{backup} = 0;
      $m->accept_mail("gg bugzilla reminders");
      $m->deliver_to_inbox('gg-bugzilla-reminders');
      return 'NEXT_MAIL';
    }
  }
}


#
# is_from_daemon()
#
# Should return true if the mail is from any kind of mail daemon,
# and therefore presumably worth seeing.
#

sub is_from_daemon {
  my $m = shift;

  # known daemons

  if (my @m = $m->matches('from_addrs',
                    qr/(
                        MAILER-DAEMON\@
                        (?:
                         (?:thelonious\.new|oxmail)\.ox\.ac\.uk |
                         tr909\.mediaconsult\.com               |
                         bt\.net 
                        ) |
                        postmaster\@.*(
                          \.genie\.syncordia\.net
                        )
                       )
                      /ix)) {
    $m->accept_mail('from daemon', "`$m[1]'");
    return 1;
  }

  if (my @m = $m->matches('from_addrs',
                          qr/(MAILER-DAEMON\@www\.genie\.co\.uk)/)) {
    $m->accept_mail('from SMS gateway', "`$m[1]'");
    $m->{not_to_mobile} = 1;
    return 1;
  }

  # standard daemon errors
  if (
      ($m->{from} =~ /
                      Mail Delivery (Subsystem|System)    |
                      MAILER-DAEMON                       |
                      MESSAGE_ERROR_HANDLER               |
                      postmaster\@
                     /ix or
       $m->{env_from} =~ /MAILER-DAEMON/
      )
      and
      $m->{subject} =~ /(
                         Undeliverable                                    |
                         Returned\ mail:\ User unknown|subscri(be|ption)  |
                         delivery\ fail(ed|ure)                           |
                         failure\ notice                                  |
                         returning\ (mail|message)
                        )/ix
     )
  {
    $m->accept_mail('from daemon', "subject contained `$1'");
    return 1;
  }

  return 0;
}


#
# deliver_mail()
#
# This routine should implement the default action to be taken on a
# mail if no other action has been already taken.  Typically it will
# just deliver the mail to your main inbox.
#

sub deliver_mail {
  my $m = shift;

  $m->deliver_to($CONFIG{main_folder});
  deliver_to_mobile($m);
}

sub deliver_to_mobile {
  my $m = shift;
#  $m->pipe_forward('email2sms | mobile')
#    unless $m->{not_to_mobile};
}
