#!/usr/local/bin/perl -w
#
# Matthew Wronka <onsg.pl@projects.matt.wronka.org>
# Las Modified Wed Aug 26 12:02:39 EDT 2009
# 
# Copyright (c) 2005-2009 Matthew Wronka
#
# Permission is hereby granted, free of charge, to any person obtaining 
# a copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation 
# the rights to use, copy, modify, merge, publish, distribute, sublicense, 
# and/or sell copies of the Software, and to permit persons to whom the 
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.

use Text::Wrap;
$Text::Wrap::columns = 65;

use constant True => 1;
use constant False => 0;

# command line options:
$bEditMode = False;	# suitable for passing when editing the body
			# for a reply (e.g., added sig and 'So and so said'
			# and body already quoted
$nSnipLength = 0;	# length at which to assume a quoted block is meaningless
$bNoSnide = False;	# don't add snide comments
$bTPBMode = False;	# Top-Post-Bitch mode; if TP detected, be a bitch
$bNoHeaders= False;	# body only, no headers
$bPrintBadness = False;	# print which badness the message contained

$quotregex="^> ";


while($opt = shift(@ARGV)) {
	if( $opt eq '-e' ) {
		$bEditMode = True;
	} elsif ( $opt eq '+s') {
		$bNoSnide=True;
	} elsif ( $opt eq '-nh') {
		$bNoHeaders=True;
	} elsif ( $opt eq '-tpb') {
		$bTPBMode=True;
	} elsif ( $opt eq '-pb') {
		$bPrintBadness=True;
	} elsif ( $opt eq '-sl') {
		$nSnipLength  = int(shift(@ARGV));
	} elsif ( $opt eq '-h') {
		print "WRITE ME\n";
		exit;
	}
}


# Things to look for:
# 	Long lines: wrap
$bLongLines = False;

# 	--Oringal Message-- crap (misquoting)
$bBadQuoting = False;
# 	Sigs still in there (anything with '-- ' until a new message part?
$bNoSigStrip = False;
# 	Top posting.
$bTopPost = False;
#	Badly formatted Sig.
#$bBadSig = False;
$bHasSig = False;

#	Subject has [Re:] but no In-Reply-To
#$bLooksLikeReply = False;

# For use with $bEditMode
$newHeading ="";
$newTailing ="";
$bnewHeading = True;
$bnewTailing = False;


$bHeader= True;
$message = "";
$bSig = False;
$bQuotedHeader = False;
@output = ();

if($bNoHeaders eq True) {
	$bHeader = False;
}

while(<stdin>) {
	chop($_); $line = $_;

	if($bHeader eq True) {
		# Don't touch!
		print $line . "\n";	

		if($line) { next;}
		else { $bHeader=False;}
	} else {
		if($bEditMode eq True and $bnewHeading eq True) {
			if($line=~/$quotregex/) {
				$bnewHeading = False;
			} else {
				$newHeading .= $line ."\n";
				next;
			}
		}
		if($bEditMode eq True and not (($bnewHeading eq True) 
				or ($bnewTailing eq True))) { 
			if(not $line=~/$quotregex/) {
				$bnewTailing = True;
			}
		}
		if($bEditMode eq True and $bnewTailing eq True) {
			$newTailing .= $line . "\n";
			next;
		}
		if($bEditMode eq True) { 
			$line = substr($line, 2);
		}

		if(
			$line=~/^\s*-+\s*Original Message( Follows)?\s*-+\s*$/
			||
			$line=~/^\s*-+\s*On.*wrote:\s*$/
		  ) {
			if($#parts <= 0 && not ($message=~/^\s*$/) ) {
				$bTopPost = True;
				if($bSig eq True) {
					$bHasSig = True;
				}
			}
			$parts[$#parts+1] = $message;
			$message = "";
			$bBadQuoting = True;
			$bQuotedHeader = True;
			$QuotedHeaders = "";
			$bSig = False;
		}
		elsif ( $line=~/^\s*On.*wrote:\s*$/ ) 
		{
			if($#parts <= 0 && not ($message=~/^\s*$/) ) {
				$bTopPost = True;
				if($bSig eq True) {
					$bHasSig = True;
				}
			}
			$parts[$#parts+1] = $message;
			$message = "";
		}

		# OK Cupid
		if( $line=~/^\s*=+\s*(.*?) wrote\s*=+\s*$/ ) {
			if($#parts <= 0 && not ($message=~/^\s*$/) ) {
				$bTopPost = True;
				if($bSig eq True) {
					$bHasSig = True;
				}
			}

			$bBadQuoting = True;
			$parts[$#parts+1] = $message;
			$message = "${1} wrote:\n";
			$bSig = False;
			$bQuotedHeader = False;
			next;
		} if ( $line=~/^\s*=+\d+\s*=+\s*$/ ) {
			next;
		}

		if($bQuotedHeader eq True) {
			if(not $line) { 
				$bQuotedHeader=False; 
				$from = 'You';  $date = 'a prior instance';
				if($QuotedHeaders =~ /From:\s*(.+)/)
				{
					$from = $1;
				}
				if($QuotedHeaders =~ /(Sent|Date):\s*(.+)/)
				{
					$date = $2; 
				}
				$message = "$from said on $date:\n";
			} else {
				$QuotedHeaders .= $line . "\n";
			}
		} elsif($bSig eq False) {
			if($line eq "-- " ) {
				$bSig = True;
				$bNoSigStrip = True;
			} else {
				$message .= $line . "\n";
			}
		} 
	}

}

$parts[$#parts+1] = $message;

# Now print it back out.
$output[$#output+1] = $newHeading;

# Don't let quoted text be last!
$bHasPrintedNewText = False;

for($i= $#parts; $i >= 0;  --$i) {
	$qchar = ($i or $bEditMode eq True)?
		('>' x ($bEditMode eq True?$i+1:$i)) .' ':'';
	@lines = split(/\n/, $parts[$i]);

	if ( $bHasPrintedNewText eq False ) {
		for($j= $#lines; $j >= 0;  --$j) {
			if($lines[$j]=~/^(\s|>)*>/) {
				$lines[$j]="\0";
				$bBadQuoting = True;
				$bTopPost = True ;
			} else {
				$bHasPrintedNewText = True;
				$j=-1;
			}
		}
	}

	if($bHasPrintedNewText eq False ) { next; }
	

	if($i) { 
		if($i>1 or $bEditMode eq True) { $tqc=substr($qchar, 1); }
		else { $tqc = ""; }
		$output[$#output+1] = fill($tqc, $tqc.'    ',  shift(@lines)) . "\n"; 
	}

	$bLastLineWasBlank =  True;
	if($i && $nSnipLength > 0 && $#lines >= $nSnipLength)
	{
		$output[$#output+1] = "\n\t[long quoted section elided ($#lines lines)... ]\n\n";
	}
	else  # include all lines
	{
		foreach $p (@lines) {
			if($p eq "\0") { next; };
			if($p=~/^\s*$/) { 
				if($bLastLineWasBlank) {  next; }; 
				$bLastLineWasBlank=True;
			} else { $bLastLineWasBlank=False; }
			if(length( $p) > 80) {
				if($i && $nSnipLength)
				{
					$len = length($p);
					$output[$#output+1] = "[incredibly long line snipped (${len} chars)... ]\n";
				}
				else
				{
					$output[$#output+1] = fill($qchar, $qchar, $p) . "\n";
				}
				$bLongLines = True;
			} else {
				if(length($p) + length($qchar) >= 80) {
					$output[$#output+1] = fill($qchar, $qchar, $p) . "\n";
				} else {
					$output[$#output+1] = $qchar. $p . "\n";
				}
			}
		}
	}
	#$output[$#output + 1 ] = "\n";
}

# Be a bitch?
@output = reverse(@output) if($bTopPost && $bTPBMode);

# Print out message:
foreach $line (@output)
{
	print $line;
}

# Print out errors:
if($bPrintBadness)
{
	print "Bad Quoting: $bBadQuoting\n";
	print "Quoted Sig : $bNoSigStrip\n";
	print "Top Posting: $bTopPost\n";
	print "Long Lines : $bLongLines\n";
	print "Has Sig    : $bHasSig\n";
}

if($bEditMode eq True and $bNoSnide eq False) {
	if($bBadQuoting eq True) {
		$msg = "";
		$msg .= "In the future, please try to use a standard method for ".
			"quoting the relevant parts of the previous message.  " .
			"There is no reason to include the entire message at the " .
			"end of the current message in almost all cases.  It makes " .
			"reading the message unnatural, and if I'm the only other " .
			"person in the thread, I probably already have the message.  " .
			"You might want to try looking at the following web pages " .
			"for more information: ".
			"http://matt.wronka.org/stuff/texts/email/index.php#quote ".
			"and " .
			"http://www.catb.org/~esr/jargon/html/email-style.html. " ;
		print fill("","", $msg) . "\n\n";
	}

	if($bTopPost eq True) {
		$msg = "";
		$msg .= "Keep in mind that along with propper quoting style comes " .
			"placing your response in the correct location.  So-called ".
			"``Jeopardy-style-quoting'' or ``top-posting'' is " .
			"counter-intuitive and makes conversations difficult to " .
			"follow (especially for late-comers or when coming back to " .
			"a thread after thinking about something else.  " .
			"Please take a look at " .
			"http://www.catb.org/~esr/jargon/html/T/top-post.html " .
			"for more information, and " .
			"http://www.blakjak.demon.co.uk/gey_stv0.htm " .
			"http://www.i-hate-computers.demon.co.uk/quote.html " .
			"and " .
			"http://www.cs.tut.fi/~jkorpela/usenet/brox.html " .
			"for reasons why ``top-posting'' is a bad idea.  " .
			"It also violates the Netiquette Guidelines codified in ".
			"RFC 1855 that have defined a set of common sense rules " .
			"for how to be a well mannered individual in the wired world.";
		print fill("","", $msg) . "\n\n";
	}

	if($bNoSigStrip eq True) {
		$msg = "";
		$msg .= "RFC 1855 defines the sequence of " .
			"``newline-dash-dash-space-newline'' " .
			"as marking the start of a signature which should be stripped ".
			"(removed) when replying.  These blocks usually do not " .
			"contain any information pertinent to the discussion.  " .
			"Please configure your mail client to remove signature blocks.";
		print fill("","", $msg) . "\n\n";
	}

	if($bLongLines eq True) {
		$msg = "";
		$msg .= "Your message included excessively long lines -- longer than ".
			"most terminals which have a standard size of 80 columns.  " .
			"RFC 1855 says that you should only use 65 which means that " .
			"I've let you have almost 25% more characters per line than " .
			"you should use if you want to be polite.  This is also more ".
			"characters than most modern mail clients use by default " .
			"(most seem to have a default of 70-76).  " .
			"Please set your client to use a shorter line length so that ".
			"recipients such as myself need not scroll horizontally " .
			"excessively, thus giving me whiplash and RSI at the same time.";
		print fill("","", $msg) . "\n\n";
	}

	if($bHasSig eq True) {
		# nothing
		#print fill("","", $msg) . "\n\n";
	}
}

print $newTailing;
