#!/usr/bin/perl -w
#this script parses an mbox (pine) style mail folder, and makes an html 
#file with links to individual messages
#
# WISHLIST:
#  o add search capability
#  o view by thread
#  o show 'To:' and 'Cc:' fields 
#  o RSS feed!
#  o show dates in index list
#  o sort by date, subject, sender
#  o save all the trouble of generating the file when it already exists 
#    (and we're not going to rewrite it because of the scrub option)
#  o display attached images!  if we could do this, this would be a
#    very convenient alternative to creating a blog -- just send to a mailing
#    list and mboxparser auto-bloggifies it!
#  o allow reverse sorting to show most recent first
#  o maybe all styles should use a fixed-width font for displaying the emails?
# TODOLIST:
#  o last modified date is 10 months ago for some reason
#  o put the "valid CSS" links somewhere less obtrusive
#  o message 9 from Martin (for example) is ugly, unwrapped, etc
#  o and i figured out why the headers are blank!  scroll right and you'll 
#    see them!
#  o message 144 from Lisa Hsu: long URLs not getting parsed right
#  o BUG: when people purposefully put something in angle brackets (which
#    I have done at least once that I know of) it gets stripped out.
#  o randomize $at symbol 

use strict;
use Text::Wrap;  # standard module which does text wrapping

my $at = '&AElig'; #substitute for @ sign in e-mails 

my $outfile = "links.html";
$Text::Wrap::columns = 80;

my $infile = shift;  # grab input file from command line.

# If this script is changed -- ie, the way the archives are generated -- 
# then run this once with an additional cmd line arg (scrub) to purge the 
# old files otherwise this doesn't regenerate any files that already exist.
my $scrub = defined($ARGV[0]);

print STDERR "[START mboxparser]";
open(INFILE, "<$infile");
my $mbox = do { local $/; <INFILE> };
my @emails = split(/[\r\n]From .*?[\r\n]/, $mbox);
#for my $e (@emails) { print "$e\n-----------------------\n"; }
#die $folder_reader unless ref $folder_reader;

# Any newlines or such before the start of the first email
#my $prologue = $folder_reader->prologue;
#print $prologue;

my $link;
my $head = " <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
<html>\n<head>\n<title>ImproveTheWorld Archives</title>
  <meta http-equiv='content-type' content='text/html; charset=utf-8' />
<link rel='stylesheet' type='text/css' href='../style/archive.css' media='screen' />
<link rel='stylesheet' type='text/css' href='../style/greenOnBlack.css' title='greenOnBlack' />
<link rel='alternate stylesheet' type='text/css' href='../style/blackOnWhite.css' title='blackOnWhite' />
<link rel='alternate stylesheet' type='text/css' href='../style/whiteOnBlack.css' title='whiteOnBlack' />
<link rel='alternate stylesheet' type='text/css' href='../style/blues.css' title='blues' />
<link rel='alternate stylesheet' type='text/css' href='../style/different.css' title='different' />
<script type='text/javascript' src='../functions.js'></script></head>\n";

my $optionsAndLinks=" 
<div style='margin:0'>Change font size:<br /><input class='fontChange smaller' type='button' value='-' />
<input type='button' class='fontChange default' value='default' />
<input type='button' class='fontChange bigger' value='+' /></div>
  <div style='margin:0'>
  Set website style:<br />
  <select id='styleSelector' >
  <!-- onchange='setActiveStyleSheet(this.options[this.selectedIndex].value)'>-->
    <option value='blackOnWhite' <?php if (\$_COOKIE['stylesheet']=='blackOnWhite') echo \"selected='selected'\"; ?> >black on white</option>
    <option value='whiteOnBlack' <?php if (\$_COOKIE['stylesheet']=='whiteOnBlack') echo \"selected='selected'\"; ?> >white on black</option>
    <option value='greenOnBlack' <?php if (\$_COOKIE['stylesheet']=='greenOnBlack') echo \"selected='selected'\"; ?> >green on black</option>
    <option value='blues' <?php if (\$_COOKIE['stylesheet']=='blues') echo \"selected='selected'\"; ?> >blues</option>
  <option value='different' <?php if (\$_COOKIE['stylesheet']=='different') echo \"selected='selected'\"; ?> >something completely different</option>
  </select>
  </div>
  <div id='modified'>
  last modified<br />
  <?php
   echo date ('Y.m.d H:i:s', 
  getlastmod());
  ?>
  </div>
  <div id='validate'>
    <a href='http://validator.w3.org/check?uri=referer'><img
    src='valid-xhtml11.png' alt='Valid XHTML 1.1!' style='height:20px;
    width:65px; border:0;' /></a>
    <a href='http://jigsaw.w3.org/css-validator/check/referer'><img
    style='border:0;width:65px;height:20px;' src='vcss.gif' alt='Valid
    CSS!' /></a>
  </div>\n";
my $firstline = 0;
my (@ids, @subjects, @froms, @dates, @messages, @messageNums);
my $entry = 0;
# This is the main loop. It’s executed once for each email
#while(!$folder_reader->end_of_file()) {
for my $email (@emails) {
  if ($firstline==0) {
    $firstline=1;
    #my $email = $folder_reader->read_next_email();
    print STDERR "[skipping first line]";
  } else {
    #my $email = $folder_reader->read_next_email();
    #$_ = $$email;
    #the header should end with a blank line, i.e. two line feeds
    #so we split it up that way, and then just the first part of that to go
    #through the headers
    my @parts = split(/[\r\n][\r\n]+/, $email);
    my $header = $parts[0];
    my @headers = split(/[\r\n]/, $header);
    my ($id, $subject, $from, $date, $message, $fromlink, $subjectlink);
    $email=~/\n\n(.*)/s;
    $message=$1;
   #remove white space
    #$message =~ s|([\r\n])[\s]+| |gis;
   ##remove common message entities
    $message =~ s/&(quot|#34);/"/gis;
    $message =~ s/ & / &amp; /gis;
    #$message =~ s/&(lt|#60);/ /gis;
    #$message =~ s/&(gt|#62);/ /gis;
    $message =~ s/&(nbsp|#160);/ /gis;
    #$message =~ s/&(iexcl|#161);/ /gis;
    #$message =~ s/&(cent|#162);/ /gis;
    #$message =~ s/&(pound|#163);/ /gis;
    #$message =~ s/&(copy|#169);/ /gis;
    $message =~ s/&#(\d+);/ /gis;
   ## remove comments, scripts, and stylesheets.
    $message =~ s|<!--.*?-->| |gis;
    $message =~ s|<script.*?>.*?</script>| |gis;
    $message =~ s|<style.*?>.*?</style>| |gis;
   #
   ## remove the rest of the tags, leaving everything else behind.
    $message =~ s|<.*?>| |gis;
    #get rid of escape sequences
    $message =~s/\=+\s*\=*\d{2}/ /gs;
    $message =~s/\=+\n(\w*)/$1 /gs;
    #try to avoid spam
    $message=~s/\@/ $at /g;   # cleverly disguise email addresses
    #wrap the text to 80 columns
    $message=wrap('', '', $message);
    #automatically insert hyperlinks
    #if ($message =~ /((http\:\/\/)?([A-Za-z][\w\-]*\.[\w\-]+\S*))/gis) {
      #my $linktext = $1;;
      #if (length($1)>50) {
      #  $linktext=substr($1,0,50) . ' ...';
      #}
      $message =~ s/((http\:\/\/)?([A-Za-z][\w\-]*\.[\w\-]+\S*))/("<a href='http\:\/\/$3'>" . substr($1,0,70) . (length($1)>70?"...":"") . "<\/a>")/gise;
    #}
    #eval{"<a href='http\:\/\/$3'>" . substr($1,0,50) . "<\/a>"}/gise;

    $message="<tr>\n  <td colspan='2'><pre>$message</pre></td>\n</tr>\n";
    #$message=~s/\n\n+/<\/br>\n/g;
    
    $messages[$entry]=$message;
    #print @headers[0] . "\n";
    for my $line (@headers) {
      if ($line=~/^Subject: (.*)$/i) {
        $subject= $1;
        $subject=~s/^\s+|\s+$//g;
        $subjectlink= $subject;
        $subjectlink=~s/^\s+|\s+$//g;
	$subject="<tr>\n  <td><strong>Subject:</strong></td>\n   <td>$subject</td>\n</tr>\n";
        $subjects[$entry]=$subject;
      }
      if ($line=~/^from: (.*?)$/i) {
        my $address=$1;
        $address=~s/\[mailto:.*?\]//g;
        $address=~s/\@/ $at /g;
        $address=~s/^\s+|\s+$//g;
        $fromlink = $address;
        $fromlink=~s/<.*?>//g;
        $address=~s/</&lt;/g;
        $address=~s/>/&gt;/g;
	$from ="<tr>\n  <td><strong>From:</strong></td>\n  <td>$address</td>\n</tr>\n";
        $froms[$entry]=$from;
      }
      if ($line=~/^date: (.*?)$/i) {
        $date=$1;
        $date=~s/^\s+|\s+$//g;
	$date ="<tr>\n  <td><strong>Date:</strong></td>\n  <td>$date</td>\n</tr>\n";
        $dates[$entry]=$date;
      }
      if ($line=~/^Message-id: (.*?)$/i) {
	$id=$1; 
	$id=~s/[\.\@\%\$\#\!\^\&\*\\\/\(\)]/_/g;
	$id=~s/[<>]//g;
        $ids[$entry]=$id;
      }
    }
    my $num = $entry+1;
    my $rawfilename="emails/" . $num . ".txt";
    my $plaintext=$email;
    $plaintext=~s/\@/ $at /g;
 
    if ($scrub || !(-e $rawfilename)) {
      open (RAWFILE, ">$rawfilename") || die ("could not open $rawfilename");
      print RAWFILE $plaintext;
      close(RAWFILE);
    }
    #my $filename="emails/" . $id . ".php";
    $entry++;
    my $filename="emails/" . $entry . ".php";
    $link .= "<li><a href='$filename'>$fromlink ---  $subjectlink</a></li>\n";
    $messageNums[$entry-1]="<tr>\n  <td>Message Number:</td>\n  <td>$entry</td>\n</tr>\n";
  }
}
my $i=0;
my ($nav, $page, $body);
while ($i<$entry) {
  my $prev=$i;
  my $this=$i+1;
  my $next=$i+2;
  if ($i==0) {
    $nav = "<p><a href='../'><input type='button' value='index' /></a> <a
    href='$next.php'><input type='button' value='next' /></a><br />
    <a href='$this.txt'>raw text</a></p>";
  } elsif ($i==$entry-1) {
    $nav = "<p><a href='$prev.php'><input type='button' value='prev' />
    </a><a href='../'><input type='button' value='index' /></a> <br />
    <a href='$this.txt'>raw text</a></p>";
  } else {
    $nav = "<p><a href='$prev.php'><input type='button' value='prev' />
    </a><a href='../'><input type='button' value='index' /></a> <a href=
    '$next.php'><input type='button' value='next' /></a><br />
    <a href='$this.txt'>raw text</a></p>";
  }
  $body = "<body>\n<div id='optionsAndLinks'><div id='nav'>$nav</div>$optionsAndLinks</div>\n<div id='content'> \n<table style='width:100%'>" . $messageNums[$i] . $froms[$i] . $dates[$i] . $subjects[$i] . "</table>\n" . $messages[$i] . "</div>\n</body>\n</html>"; 
  $page = $head . $body;
  my $num=$i+1;
  my $filename="emails/" . $num . ".php";
  if ($scrub || !(-e $filename)) {
    open(OUTFILE, ">$filename") || die ("could not open $filename");
    print OUTFILE $page;
    close(OUTFILE);
  }
  $i++;
}
#print out index page
open(LINKS, ">$outfile") || die('could not open $outfile for writing');
print LINKS $link;
close(LINKS);

print STDERR "[END mboxparser]\n";
