#!/usr/bin/perl
#
#  Duplicate Seminar Checker
#  Michael D. Powell, 4/5/2003, 2005
#
#  Copyright 2003, 2004, 2005 by Michael D. Powell
#
#  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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#
#  Description: 
#  Script attempts to identify Purdue ECE/CS Seminar announcements by looking
#  for words in the body within two groups of keywords, trying to match a known venue,
#  and trying to determine a date and time.  Output is a "X-Dupe-Seminar:" header
#  to be used by procmail.  Heading beginning with "X-Dupe-Seminar: Yes" 
#  indicates a dupe is found.
#
#  Example .procmailrc usage
#
## duplicate seminar check
#
## check body only for seminar details. headers would confuse it
#:0bw: seminar.lock
#* < 512000
#HEADER=|.procmail/seminar.pl
#
## size check for header additions too
#:0hfw: seminar.lock
#* < 512000
#|formail -A "$HEADER"
#
#:0:
#* ^X-Dupe-Seminar: Yes
#mail/dupes
#
#

use Time::Local;

$debug = 1;

$seminarlog = '.seminarlog'; # file that tracks observed seminars

# one of these must be detected unless superkeywordsrequired met
@requiredkey = ('seminar', 'distinguished lecture',
                'colloquium', 's e m i n a r');

$superkeywordsrequired = 3; # required to override not having any requiredkey
$keywordsrequired = 1;
@keywords = ('cs&e', 'acsl', 'ee694', 'ece694', 'abstract', 'title',
             'biography', 'ee 694', 'ece 694', 'the faculty', 'ee400', 
             'ee 400', 'ece 400', 'ece400',
             'professor of', 'professor in','candidate',
             'prospective faculty', 'prospective ece faculty',
             'prospective cs faculty', 'prospective ee faculty',
             'prospective computer science faculty',
             'department presents', 'engineering presents', 'speaker',
             'computing research institute', ' cri ', 'faculty host',
             'ece graduate seminar', 'ee graduate seminar','ce graduate seminar',
              'he is currently', 'wishing to speak privately','department of',
              'school of','university of');

# words to acquit seminar-like e-mails (eg let all monday memos pass)
@killwords = ('monday memo school of electrical and computer engineering');

# venues (whitespace removed).  1st entry for each is primary identifier
@venues = (['ee170', 'room170'],
           ['ee270', 'room270'],
           ['msee239', 'room239'],
           ['ee112', 'room112'],
           ['ee118', 'room118', 'facultylounge'],
           ['ee117', 'room117'],
           ['ee112', 'room112'],
           ['ee317', 'room317'],
           ['furoom','potter234','room234','potr234'],
           ['civl1144','civilbuildingroom1144','room1144'],
           ['phys112','physics112','room112'],
           ['phys114','physics114','room114'],
           ['phys201','physics201','room201'],
           ['phys220','physics220','room220'],
           ['phys242','physics242','room242'],
           ['recitation103','rec103','room103'],
           ['mseeb012','mseeb12','roomb012','roomb12'],
           ['mseeb010','mseeb10','roomb010','roomb10'],
           ['cs111', 'room111'],
           ['cs101', 'room101'],
           ['wthr104','room104','wetherill104'],
           ['wthr160','room160','wetherill160'],
           ['ee129', 'room129'],
           ['lynng167', 'room167', 'lynn167'],
           ['laeb1260', 'brng1260', 'beer1260', 'room1260'],
           ['laeb2275', 'brng2275', 'beer2275', 'room2275'],
           ['knoyb016', 'knoyroomb016','knoyhallb016','knoyhallroomb016','b016knoy'],
           ['stew314', 'stewart314', 'stewartcenterroom314',
            'stewartcenter314','stuartcenterroom314','stuartroom314',
            'stuart314'],
           ['stew312', 'stewart312', 'stewartcenterroom312',
            'stewartcenter312','stuartcenterroom312','stuartroom312',
            'stuart312'],
           ['stew310', 'stewart310', 'stewartcenterroom310',
            'stewartcenter310','stuartcenterroom310','stuartroom310',
            'stuart310'],

           ['stew214', 'stewart214', 'stewartcenterroom214',
            'stewartcenter214','stuartcenterroom214','stuartroom214',
            'stuart214'],

           ['stew212', 'stewart212', 'stewartcenterroom212',
            'stewartcenter212','stuartcenterroom212','stuartroom212',
            'stuart212'],
           ['stew322', 'stewart322', 'stewartcenterroom322',
            'stewartcenter322','stuartcenterroom322','stuartroom322',
            'stuart322'],

           ['me256','fordroom','room256']

           );


@months = ('spacefiller', 'january', 'february', 'march', 'april', 'may', 'june', 
           'july', 'august', 'september', 'october', 'november', 'december');
@shortmonths = ('spacefiller', 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul',
                'aug', 'sep', 'oct', 'nov', 'dec');

@weekday = ('spacefiller','sunday', 'monday','tuesday','wednesday',
             'thursday','friday','saturday');
@shortweekday = ('spacefiller','sun', 'mon','tue','wed',
             'thur','fri','sat');
              
# determine what year it is
($thisyear) = (localtime(time))[5] + 1900;
#$thisyear = 2003; #manually set for debugging purposes

$requiredkeycount = 0;
$eventtime = 0;
$matchvenue = 'empty';
$eventdate = 0;
$linenum = 0;
$killword = 0;

$nextyear = $thisyear + 1;
$thisyear2d = $thisyear - 2000;
$nextyear2d = $thisyear - 2000;

# deal with 2 digit years less than 10 having leading 0
if ($thisyear2d < 10) {
  $thisyear2d = sprintf("%02d",$thisyear2d);
}
if ($nextyear2d < 10) {
  $nextyear2d = sprintf("%02d",$nextyear2d);
}

# initialize keyword match list
for ($i = 0; $i < @keywords; $i++) {
  $matchkey[$i] = 0;
}

while (<STDIN>) {


  # extra loop pairs all lines with prev lines in case a date or time
  # is split between lines
  for ($z = 0; $z < 2; $z++) {
  if (($z == 0) || ($linenum == 0)) {
    $rawline = $_;
  } else {
    chop($oldline);
    $rawline = "$oldline $_";

  }


  if ($linenum == 0) {
     $oldline = $_;
  }
  $linenum++;

  # try to avoid being confused by date headers in forwarded messages
  # any time specified to the nearest second probably not what we need
  # any time with an IN gmt offset also not what we need
  if (($rawline =~ m/\-0500/) || 
      ($rawline =~ m/[0-9]{1,2}\:[0-9]{2,2}\:[0-9]{2,2}/)) {
    next;
  }

  #retrieve event time.  assume first time seen is seminar time
  # others may be coffee, food, reception, etc

  if ($eventtime == 0) {
     $timeline = $rawline;
     $timeline =~ s/\s//g; # kill off white space
     $timeline =~ s/\.//g; # kill off periods
     $timeline =~ tr/[A-Z]/[a-z]/; # make it lower case


     # try to match first value in time ranges
     if ($timeline =~ /([0-9]{1,2})\:([0-9]{2})(am|pm){0,1}\-[0-9]{1,2}\:[0-9]{2}/) {
       $hour = $1;
       $min = $2;
       $eventtime = $hour * 100 + $min;
     } elsif ($timeline =~ /([0-9]{1,2})\:([0-9]{2})/) {
       $hour = $1;
       $min = $2;
       $eventtime = $hour * 100 + $min;
     }

    # reduce 24-hour time to 12-hour;
    if ($eventtime > 1259) {
      $eventtime = $eventtime - 1200;
    }

  } # end time retrieval

  # lower case only
  $cleanline = $rawline;
  $cleanline =~ tr/[A-Z]/[a-z]/;

  # kill commas and periods, they confuse date and keyword recognition
  $cleanline =~  s/,//g;
  $cleanline =~  s/\.//g;


  # look for keywords
  for ($i = 0; $i < @keywords; $i++) {
    if ($cleanline =~ m/${keywords[$i]}/) {
      $matchkey[$i] = 1;
    }
  }

  # look for required keywords
  if (!($requiredkeycount==1)) {
     for ($i = 0; $i < @requiredkey; $i++) {
       if ($cleanline =~ m/${requiredkey[$i]}/) {
         $requiredkeycount = 1;
       }
     }
  } 

  # look for killwords
  for ($i = 0; $i < @killwords; $i++) {
    if ($cleanline =~ m/${killwords[$i]}/) {
      $killword = 1;
    }
  }



  # find date
  # months come before days (God bless america!)
  if ($eventdate == 0) {

     # seminar announcements always put the year in the date.  kind of silly
     # but a good discriminator for dates
     if (($cleanline =~ m/$thisyear/) || ($cleanline =~/$nextyear/)) {
        # look for 4 digit years
        if ($cleanline =~ m/([0-9]{1,2})\/([0-9]{1,2})\/($thisyear)/) {
          $eventdate = $1 * 100 + $2;
        }
        if ($cleanline =~ m/([0-9]{1,2})\/([0-9]{1,2})\/($nextyear)/) {
          $eventdate = $1 * 100 + $2;
        }
        if ($cleanline =~ m/($thisyear)\/([0-9]{1,2})\/([0-9]{1,2})/) {
          $eventdate = $2 * 100 + $3;
        }
        if ($cleanline =~ m/($nextyear)\/([0-9]{1,2})\/([0-9]{1,2})/) {
          $eventdate = $2 * 100 + $3;
        }
        for ($i = 1; $i < 13; $i++) {

           if ($cleanline =~ m/($months[$i]) +([0-9]{1,2}) +($thisyear)/) {
             $eventdate = $i * 100 + $2;
           }
           if ($cleanline =~ m/($shortmonths[$i]) +([0-9]{1,2}) +($thisyear)/) {
             $eventdate = $i * 100 + $2;
           }
           if ($cleanline =~ m/($months[$i]) +([0-9]{1,2}) +($nextyear)/) {
             $eventdate = $i * 100 + $2;
           }
           if ($cleanline =~ m/($shortmonths[$i]) +([0-9]{1,2}) +($nextyear)/) {
             $eventdate = $i * 100 + $2;
           }
           if ($cleanline =~ m/([0-9]{1,2}) +($months[$i]) +($thisyear)/) {
             $eventdate = $i * 100 + $1;
           }
           if ($cleanline =~ m/([0-9]{1,2}) +($shortmonths[$i]) +($thisyear)/) {
             $eventdate = $i * 100 + $1;
           }
           if ($cleanline =~ m/([0-9]{1,2}) +($months[$i]) +($nextyear)/) {
             $eventdate = $i * 100 + $1;
           }
           if ($cleanline =~ m/([0-9]{1,2}) +($shortmonths[$i]) +($nextyear)/) {
             $eventdate = $i * 100 + $1;
           }
        }   
     }
     if (($eventdate == 0) && (($cleanline =~ m/$thisyear2d/) || ($cleanline =~/$nextyear2d/))) {
        # look for 2 digit years

        if ($cleanline =~ m/([0-9]{1,2})\/([0-9]{1,2})\/($thisyear2d)/) {
          $eventdate = $1 * 100 + $2;
        }
        if ($cleanline =~ m/([0-9]{1,2})\/([0-9]{1,2})\/($nextyear2d)/) {
          $eventdate = $1 * 100 + $2;
        }
        if ($cleanline =~ m/($thisyear2d)\/([0-9]{1,2})\/([0-9]{1,2})/) {
          $eventdate = $2 * 100 + $3;
        }
        if ($cleanline =~ m/($nextyear2d)\/([0-9]{1,2})\/([0-9]{1,2})/) {
          $eventdate = $2 * 100 + $3;
        }
        for ($i = 1; $i < 13; $i++) {

           if ($cleanline =~ m/($months[$i]) +([0-9]{1,2}) +($thisyear2d)/) {
             $eventdate = $i * 100 + $2;
           }
           if ($cleanline =~ m/($shortmonths[$i]) +([0-9]{1,2}) +($thisyear2d)/) {
             $eventdate = $i * 100 + $2;
           }
           if ($cleanline =~ m/($months[$i]) +([0-9]{1,2}) +($nextyear2d)/) {
             $eventdate = $i * 100 + $2;
           }
           if ($cleanline =~ m/($shortmonths[$i]) +([0-9]{1,2}) +($nextyear2d)/) {
             $eventdate = $i * 100 + $2;
           }
           if ($cleanline =~ m/([0-9]{1,2}) +($months[$i]) +($thisyear2d)/) {
             $eventdate = $i * 100 + $1;
           }
           if ($cleanline =~ m/([0-9]{1,2}) +($shortmonths[$i]) +($thisyear2d)/) {
             $eventdate = $i * 100 + $1;
           }
           if ($cleanline =~ m/([0-9]{1,2}) +($months[$i]) +($nextyear2d)/) {
             $eventdate = $i * 100 + $1;
           }
           if ($cleanline =~ m/([0-9]{1,2}) +($shortmonths[$i]) +($nextyear2d)/) {
             $eventdate = $i * 100 + $1;
           }
        }   
     }

     if (($eventdate == 0) && (!($cleanline =~ m/$thisyear2d/)) && (!($cleanline =~ m/$nextyear2d/))) {
       # go fishing for yearless dates in dayweek month date format
       for ($i = 1; $i < 8; $i++) {
         if ($cleanline =~ m/$weekday[$i]/) {


           for ($j = 1; $j < 13; $j++) {
             if ($cleanline =~ m/$weekday[$i] $months[$j] ([0-9]{1,2})/) {
               $eventdate = $j * 100 + $1;
             }
             if ($cleanline =~ m/$weekday[$i] $shortmonths[$j] ([0-9]{1,2})/) {
               $eventdate = $j * 100 + $1;
             }
           }
         }

         if ($cleanline =~ m/$shortweekday[$i]/) {
           for ($j = 1; $j < 13; $j++) {
             if ($cleanline =~ m/$shortweekday[$i] $months[$j] ([0-9]{1,2})/) {
               $eventdate = $j * 100 + $1;
             }
             if ($cleanline =~ m/$shortweekday[$i] $shortmonths[$j] ([0-9]{1,2})/) {
               $eventdate = $j * 100 + $1;
             }
           }
         }

       # go fishing for yearless dates in dayweek date month format
         if ($cleanline =~ m/$shortweekday[$i]/) {
           for ($j = 1; $j < 13; $j++) {
             if ($cleanline =~ m/$shortweekday[$i] ([0-9]{1,2}) $months[$j]/) {
               $eventdate = $j * 100 + $1;
             }
             if ($cleanline =~ m/$shortweekday[$i] ([0-9]{1,2}) $shortmonths[$j]/) {
               $eventdate = $j * 100 + $1;
             }
           }
         }

         if ($cleanline =~ m/$shortweekday[$i]/) {
           for ($j = 1; $j < 13; $j++) {
             if ($cleanline =~ m/$shortweekday[$i] ([0-9]{1,2}) $months[$j]/) {
               $eventdate = $j * 100 + $1;
             }
             if ($cleanline =~ m/$shortweekday[$i] ([0-9]{1,2}) $shortmonths[$j]/) {
               $eventdate = $j * 100 + $1;
             }
           }
         }

       }
    }

  } # end if eventdate == 0 check

  
  # kill all non word, characters
  $cleanline =~  s/\W//g;

  # find venue
  if ($matchvenue eq 'empty') {
     for ($i = 0; $i < @venues; $i++) {
       for ($j = 0; $j < @{@venues[$i]}; $j++) {
         if ($cleanline =~ m/$venues[$i][$j]/) {
           $matchvenue = $venues[$i][0];
         }
       }
     }
  }

  # could attempt to find title/text line? would be hard to match though.
  # block lines with department, school, university, institute, dr., professor
  # purdue, speaker, center, "electrical engineering," "computer engineering",
  # "computer science," blank lines, corporation

  #  print $cleanline;
  #  print "\n";

} # for z loop

$oldline = $_;

} # while loop


#print "keywords are: \n";

$keysum = 0;
for ($i = 0; $i < @keywords; $i++) {
  if ($matchkey[$i] == 1) {
     $keysum++;
#    print "\"${keywords[$i]}\" ";
  }
}
#print "\n";



#     if ($eventtime != 0) {
#       print "The time is ${eventtime} \n";
#     }

#print "required key count is ${requiredkeycount} \n";
#print "keywords matched is ${keysum} \n";

#print "venue identified as $matchvenue \n";

#print "eventdate is $eventdate \n";

$seminar = 0;  #flag is 1 if this is a seminar

#print "requiredkeycount $requiredkeycount keysum $keysum eventdate $eventdate eventtime $eventtime matchvenue $matchvenue\n";

# it's only a seminar if the right match of keywords found, AND
# a date, time, and venue were located

if ((($requiredkeycount > 0) && ($keysum >= $keywordsrequired)) || 
    ($keysum >= $superkeywordsrequired)) {
  if (($eventdate != 0) && (!($matchvenue eq 'empty')) &&
      ($eventtime != 0)) {
    $seminar = 1;
  }
}

# certain conditions acquit an otherwise seminar-like e-mail 
if ($killword == 1) {
 $seminar = 0;
}

if ($seminar == 0) {

   if ($debug == 0) {
     print "X-Dupe-Seminar: Not seminar \n";
   } else {

     $month = int($eventdate / 100);
     $day = $eventdate - 100 * $month;
     $hour = int($eventtime / 100);
     $minute = $eventtime - 100 * $hour;  

     printf ("X-Dupe-Seminar: Not Seminar Debug %2d:%02d %02d/%02d %s r%d k%d \n",
       $hour,$minute,$month,$day,$matchvenue,$requiredkeycount,
       $keysum);
   }


}

if ($seminar == 1) {

   # Figure out if this is a dupe

   # make the identifier for this seminar
   $identifier = "${eventtime} ${eventdate} ${matchvenue}";
   #print "identifier is ${identifier} \n";

   open (INFILE, "< ${seminarlog}");

   $dupe = 0;
   $answer = 'No';
   while (<INFILE>) {
     if ($_ =~ m/$identifier/) {
       # we've got a match
       $dupe = 1;
       $answer = 'Yes';

       last;
     }
   }

   close (INFILE);

   if ($dupe == 0) {
     # log this seminar
     open (OUTFILE, ">> ${seminarlog}");
     print OUTFILE "${identifier}\n";
     close (OUTFILE);
   }

   #output status

   $month = int($eventdate / 100);
   $day = $eventdate - 100 * $month;
   $hour = int($eventtime / 100);
   $minute = $eventtime - 100 * $hour;  

   # Seminar header output with info
   printf ("X-Dupe-Seminar: %3s %2d:%02d %02d/%02d %s r%d k%d \n",
   $answer,$hour,$minute,$month,$day,$matchvenue,$requiredkeycount,
   $keysum);

}

