#!/usr/bin/perl -w

# Copyright 2000 Ry4an Brase (ry4an at ry4an dot org)

use strict;
use SDBM_File;
use Fcntl qw(O_RDWR O_CREAT);
use IO::Handle;
use Mail::Mailer;  # in the Mail-tools module

#################[ configuration area ]###############################
my $dataDir = $ENV{'HOME'} . "/.cidfilter";
my $phoneBook = "$dataDir/phonebook";
my $classList = "$dataDir/classlist";
my $logFile = "$dataDir/calllog";
my $xmessage = '/usr/X11R6/bin/xmessage';
my %actions = ( 'ring' => \&ring,  # make a noise
    'display' => \&display, # display to screen
    'log' => \&log, # log to file
    'mail' => \&mail, # send email
    'cell' => \&cell); # notify phone
my $emailAddress = 'me@somewhere.com';
my $cellAddress = '6125551212@voicestream.net';

my %call = &parseCall(@ARGV);

my %phonebook = &loadPhoneBook;
my %classRights = &loadClassRights;

%call = &identify(%call);

$SIG{CHLD} = 'IGNORE';

foreach my $action (keys %actions) {
    if (&allowedTo($action, @{$call{'classes'}})) {
	&{$actions{$action}}(%call);
    }
}

####################[ subroutines ]############################

# connect phonebook to a file
sub loadPhoneBook {
    my %retval = ();
    open PHONEBOOK, "<$phoneBook"
        || die "Couldn't open '$phoneBook': $!\n";
    my $statement = join '', <PHONEBOOK>;
    close PHONEBOOK;
    eval $statement || die "Error loading '$phoneBook': $!\n";
    scalar %retval || die "Error in '$phoneBook': \%retval not set.\n";
    return %retval;
}

# connect classRights to a file
sub loadClassRights {
    my %retval = ();
    open CLASSLIST, "<$classList"
        || die "Couldn't open '$classList': $!\n";
    my $statement = join '', <CLASSLIST>;
    close CLASSLIST;
    eval $statement || die "Error loading '$classList': $!\n";
    scalar %retval || die "Error in '$classList': \%retval not set.\n";
    return %retval;
}

# takes cid output and hashifys it
sub parseCall {
    my %ret = ();
    my ($key, $val);

    foreach (@_) {
	unless (($key,$val) = (/(\w+)=(.+)$/)) {
	    print STDERR "Couldn't parse '$_'\n";
	    &helpExit;
	}
	if ($key eq "TIME") {
	    $ret{'time'}=(substr $val, 0, 2) . ":" . (substr $val, 2);
	    next;
	}
	if ($key eq "DATE") {
	    $ret{'date'}=(substr $val, 0, 2) . "/" . (substr $val, 2) . "/"
		. ((localtime())[5] + 1900);
	    next;
	}
	if ($key eq "NMBR") {
            $val = '0' x 10 if ($val eq 'OUT OF AREA');
            if ($val =~ /^\d{10}$/) {
                $ret{'number'}=(substr $val,0,3) . "-" . (substr $val,3,3) . "-"
                    . (substr $val,6);
            } else {
                $ret{'number'}=$val;
            }
	    next;
	}
	if ($key eq "NAME") {
	    $ret{'name'}=lc($val);
	    next;
	}
	print STDERR "Unrecognized param type '$key'\n";
	&helpExit;
    }

    if ((keys %ret) != 4) {
	print STDERR "DATE, TIME, NMBR, or NAME not found.\n";
	&helpExit;
    }
    
    return %ret;
}

# print usage help and exit
sub helpExit {
    print "Example: cidfiler DATE=0119 TIME=0136 NMBR=6125557352",
	" NAME='SOME ONE'\n";
    exit;
}

# takes ring info hash and fills in note, classes, and more
sub identify {
    my %thecall = @_;
    my %phoneentry;

    # extract from phone list
    if (exists $phonebook{$thecall{'number'}}) {
	my %phoneentry = %{$phonebook{$thecall{'number'}}};
        foreach my $key (keys %phoneentry) {
            $thecall{$key} = $phoneentry{$key};
        }
    } else {
	$thecall{'classes'} = ['default'];
    }
    unless ($thecall{'note'}) {
        my %areaCodes = &areaCodes;
        $thecall{'note'} = $areaCodes{substr($thecall{'number'},0,3)};
    }
    return %thecall;
}

sub allowedTo {
    my ($action, @classes);
    $action = shift;
    @classes = @_;

    foreach my $class (@classes) {
        unless (exists $classRights{$class}) {
            print STDERR "Unrecognized class '$class'\n";
            next;
        }
        foreach my $right (@{$classRights{$class}}) {
            #print "$class: Testing '$right' vs '$action'\n";
            return 1 if ($right eq $action);
        }
    }
    return 0;
}

################[ actions ]##################

sub log {
    my %call = @_;

    $| = 1;
	
    (open LOGFILE, ">>$logFile") || die $!;
    LOGFILE->autoflush();

    print LOGFILE "---[ Call Received ]---\n"
	. "Name  : $call{'name'}\n"
	. "Number: $call{'number'}\n"
	. ($call{'note'}?"Note  : $call{'note'}\n":"")
	. "When  : $call{'date'} $call{'time'}\n";

    close LOGFILE;
}

sub ring {
    # FIXME make this ring
    print "\a";
}

sub display {
    my %call = @_;
	
    defined (my $pid = fork) or die "Can't launch xmessage: $!\n";
    return if ($pid); # parent

    $SIG{CHLD} = 'DEFAULT';
#    $ENV{'DISPLAY'} = ':0.0';

    open XMESSAGE,
            "|$xmessage -file - -timeout 10 -center -title 'Call Received'"
        || die "Can't open xmessage: $!\n";
    print XMESSAGE
	"Name  : $call{'name'}\n"
	. "Number: $call{'number'}\n"
	. ($call{'note'}?"Note  : $call{'note'}\n":"")
	. "Class : " . join(',', @{$call{'classes'}}) . "\n"
	. "When  : $call{'date'} $call{'time'}\n";
    close XMESSAGE;

    # TODO fall back to write(1)
}

sub mail {
    # no need to fork, 'cause Mail::Mailer does
    my %call = @_;

    my $mailer = new Mail::Mailer;
    my %headers = ('To' => $emailAddress,
        'Subject' => "Call received: $call{'name'}");
    unless ($mailer->open(\%headers)) {
        warn "Couldn't create mailer: $!\n";
        return;
    }
    print $mailer
	"Name  : $call{'name'}\n"
	. "Number: $call{'number'}\n"
	. ($call{'note'}?"Note  : $call{'note'}\n":"")
	. "Class : " . join(',', @{$call{'classes'}}) . "\n"
	. "When  : $call{'date'} $call{'time'}\n";
    $mailer->close || warn ("Error sending mail: $!");
}

sub cell {
    # no need to fork, 'cause Mail::Mailer does
    my %call = @_;

    my $mailer = new Mail::Mailer;
    my %headers = ('To' => $cellAddress);
    unless ($mailer->open(\%headers)) {
        warn "Couldn't create mailer: $!\n";
        return;
    }
    print $mailer "$call{'name'} at $call{'number'}"
	. ($call{'note'}?" : $call{'note'}\n":"")
        . "at " . localtime;
    $mailer->close || warn ("Error sending mail: $!");
}

###################### data ######################################

sub areaCodes {
    (
        201 => 'Hackensack/Jersey City, NJ',
        202 => 'Washington D.C.',
        203 => 'New Haven, Stamford, southwestern CT',
        204 => 'Manitoba',
        205 => 'Central Alabama',
        206 => 'Seattle, WA',
        207 => 'Maine',
        208 => 'Idaho',
        209 => 'Modesto/Stockton, CA',
        210 => 'San Antonio, TX',
        212 => 'Manhattan, NY',
        213 => 'Los Angeles, CA',
        214 => 'Dallas, TX',
        215 => 'Philadelphia, PA',
        216 => 'Cleveland, OH',
        217 => 'Champaign/Springfield, IL',
        218 => 'Northern Minnesota',
        219 => 'Northern Indiana',
        224 => 'Chicago, IL',
        225 => 'Baton Rouge, LA',
        228 => 'Mississippi Gulf Coast',
        240 => 'Maryland (DC Suburbs)',
        242 => 'Bahamas',
        246 => 'Barbados',
        248 => 'Detroit, MI',
        250 => 'Vancouver Island, BC',
        252 => 'North Carolina Coast',
        253 => 'Tacoma, WA',
        254 => 'Waco, TX',
        256 => 'Northern Alabama',
        264 => 'Anguilla',
        267 => 'Philadelphia, PA',
        268 => 'Antigua, Barbuda',
        270 => 'Western Kentucky',
        281 => 'Houston, TX',
        284 => 'British Virgin Islands',
        301 => 'Maryland DC Suburbs',
        302 => 'Delaware',
        303 => 'Denver, CO',
        304 => 'West Virginia',
        305 => 'Miami, FL',
        306 => 'Saskatchewan',
        307 => 'Wyoming',
        308 => 'Western Nebraska',
        309 => 'West Central Illinois',
        310 => 'Los Angeles, CA',
        312 => 'Chicago, IL',
        313 => 'Detroit, MI',
        314 => 'St. Louis, MO',
        315 => 'North Central NY',
        316 => 'Southern Kansas',
        317 => 'Indianapolis, IN',
        318 => 'Northern Louisiana',
        319 => 'Eastern Iowa',
        320 => 'West Central Minnesota',
        323 => 'Los Angeles, CA',
        330 => 'Akron/Canton, OH',
        334 => 'Southern Alabama',
        336 => 'Greensboro, NC',
        340 => 'US Virgin Islands',
        345 => 'Cayman Islands',
        347 => 'New York City',
        352 => 'Gainesville/Ocala, FL',
        360 => 'Southwestern Washington',
        401 => 'Rhode Island',
        402 => 'Eastern Nebraska',
        403 => 'Alberta',
        404 => 'Atlanta, GA',
        405 => 'Western Oklahoma',
        406 => 'Montana',
        407 => 'Orlando, FL',
        408 => 'San Jose, CA',
        409 => 'Southeast Texas',
        410 => 'Baltimore, MD',
        412 => 'Pittsburgh, PA',
        413 => 'Western Massachusetts',
        414 => 'Milwaukee, WI',
        415 => 'San Francisco, CA',
        416 => 'Toronto, ON',
        417 => 'Southwestern Missouri',
        418 => 'Eastern Quebec',
        419 => 'Northwestern Ohio',
        423 => 'Eastern Tennessee',
        424 => 'Los Angeles, CA',
        425 => 'Redmond, WA',
        435 => 'Utah',
        440 => 'Cleveland, OH',
        441 => 'Bermuda',
        443 => 'Baltimore, MD',
        450 => 'Montreal Suburbs',
        473 => 'Grenada',
        484 => 'Allentown, PA',
        501 => 'Central/Northwestern Arkansas',
        502 => 'Western Kentucky',
        503 => 'Northwestern Oregon',
        504 => 'New Orleans, LA',
        505 => 'New Mexico',
        506 => 'New Brunswick',
        507 => 'Southern Minnesota',
        508 => 'Southeastern Massachusetts',
        509 => 'Eastern Washington',
        510 => 'Oakland, CA',
        512 => 'Austin/Corpus Christi, TX',
        513 => 'Cincinnati, OH',
        514 => 'Montreal, PQ',
        515 => 'Central Iowa',
        516 => 'Long Island, NY',
        517 => 'Lansing/Saginaw, MI',
        518 => 'Northeastern New York',
        519 => 'Ontario Panhandle',
        520 => 'Arizona',
        530 => 'Northeastern California',
        540 => 'Western Viginia',
        541 => 'Oregon',
        559 => 'Fresno, CA',
        561 => 'East Central Florida',
        562 => 'Los Angeles, CA',
        570 => 'Scranton, PA',
        573 => 'Central Missouri',
        580 => 'Nortwestern Oklahoma',
        601 => 'Mississippi',
        602 => 'Phoenix, AZ',
        603 => 'New Hampshire',
        604 => 'Vancouver, BC',
        605 => 'South Dakota',
        606 => 'Eastern Kentucky',
        607 => 'South Central New York',
        608 => 'Southwestern Wisconsin',
        609 => 'Southern New Jersey',
        610 => 'Allentown, PA',
        612 => 'Minneapolis, MN',
        613 => 'Ottawa, ON',
        614 => 'Columbus, OH',
        615 => 'Nashville, TN',
        616 => 'Western Michigan',
        617 => 'Boston, MA',
        618 => 'Southern Illinois',
        619 => 'San Diego, CA',
        626 => 'Los Angeles, CA',
        630 => 'Chicago Suburbs, IL',
        646 => 'New York City',
        649 => 'Turks & Caicos Islands',
        650 => 'San Francisco, CA',
        651 => 'St. Paul, MN',
        660 => 'North Central Missouri',
        661 => 'Los Angeles, CA',
        664 => 'Montserrat',
        670 => 'Northern Mariana Islands',
        671 => 'Guam',
        678 => 'Atlanta, GA',
        701 => 'North Dakota',
        702 => 'Las Vegas, NV',
        703 => 'Arlington, VA',
        704 => 'Charlotte, NC',
        705 => 'North Central Ontario',
        706 => 'Northern Georgia',
        707 => 'Northwestern California',
        708 => 'Chicago Suburbs, IL',
        709 => 'Newfoundland',
        712 => 'Western Iowa',
        713 => 'Houston, TX',
        714 => 'Anaheim, CA',
        715 => 'Northern Wisconsin',
        716 => 'Western New York',
        717 => 'Harrisburg, PA',
        718 => 'New York City',
        719 => 'Southeastern Colorado',
        720 => 'Denver, CO',
        724 => 'Western Pennsylvania',
        727 => 'St. Petersburg, FL',
        732 => 'Northern Jersey Shore region',
        734 => 'Detroit, MI',
        740 => 'Southeastern Ohio',
        757 => 'Norfolk, VA',
        758 => 'St. Lucia',
        760 => 'Southeastern California',
        763 => 'North/West Twin Cities, MN',
        765 => 'Lafayette/Muncie IL',
        767 => 'Dominica',
        770 => 'Atlanta, GA',
        773 => 'Chicago, IL',
        775 => 'Nevada',
        780 => 'Northern Alberta',
        781 => 'Boston, MA',
        784 => 'St. Vincent & the Grenadines',
        784 => 'Northwestern Kansas',
        786 => 'Miami, FL',
        787 => 'Puerto Rico',
        801 => 'Salt Lake City, UT',
        802 => 'Vermont',
        803 => 'Central South Carolina',
        804 => 'Richmond, VA',
        805 => 'Oxnard, CA',
        806 => 'Texas Panhandle',
        807 => 'Northwestern Ontario',
        808 => 'Hawaii',
        809 => 'Dominican Republic',
        810 => 'Detroit, MI',
        812 => 'Southern Indiana',
        813 => 'Tampa, FL',
        814 => 'Altoona/Erie, PA',
        815 => 'Northern Illinois',
        816 => 'Kansas City, MO',
        817 => 'Ft. Worth, TC',
        818 => 'San Fernando, CA',
        819 => 'Quebec',
        828 => 'Asheville, NC',
        830 => 'San Antonio, TX',
        831 => 'Monterey, CA',
        843 => 'Coastal South Carolina',
        847 => 'Chicago, IL',
        850 => 'Florida Panhandle',
        858 => 'San Diego, CA',
        860 => 'Northern Connecticut',
        864 => 'Northwestern South Carolina',
        867 => 'The Great Frozen North of Canada',
        868 => 'Trinidad & Tobago',
        869 => "St. Kitt's & Nevis",
        870 => 'Eastern Arkansas',
        876 => 'Jamaica',
        901 => 'Western Tennessee',
        902 => 'Nova Scotia',
        903 => 'Northeastern Texas',
        904 => 'Northeastern Florida',
        905 => 'Toronto, ON',
        906 => 'UP Michigan',
        907 => 'Alaska',
        908 => 'Elizabeth, NJ',
        909 => 'San Bernardino, CA',
        910 => 'Southeastern North Carolina',
        912 => 'Southern Georgia',
        913 => 'Kansas City, KS',
        914 => 'New York City',
        915 => 'Western Texas',
        916 => 'Sacramento, CA',
        917 => 'New York City Wireless',
        918 => 'Northeastern Oklahoma',
        919 => 'Raleigh, NC',
        920 => 'Northeastern Wisconsin',
        925 => 'Concord, CA',
        931 => 'Central Tennessee',
        935 => 'San Diego, CA',
        937 => 'Dayton, OH',
        940 => 'Wichita Falls, TX',
        941 => 'Southwestern Florida',
        949 => 'Irvine, CA',
        952 => 'South/West Twin Cities, MN',
        954 => 'Broward County, FL',
        956 => 'Brownsville/Laredo, TX',
        970 => 'Colorado Western Slope',
        972 => 'Dallas, TX',
        973 => 'Newark, NJ',
        978 => 'Northeastern Massachusetts',
    );
}

Generated by GNU enscript 1.6.1.