#!/usr/bin/perl -W 

# ArielDoc.pl
#
# 10/25/04 add portability across Windows and Unix, by handling both <cr><lf> and <cr>.
# 10/25/01 retain check mark 
# 10/02/01 correct $mnth value
# 02/07/02 add file extension to url of opening documents
# 09/05/02 change opening document processing

use File::Basename;

#===============================================================================
# Configuration
#===============================================================================
$DocFilePath = "/home/ariel/docs/";		# document files dir; keep the trailing slash
$SesFilePath = "/home/ariel/tmp/";		# temporary session files dir; keep the trailing slash
$LogFilePath = "/home/ariel/logs/";		# error log files dir; keep the trailing slash

$CgiPrgm = "/cgi-bin/ariel/ArielDoc";	 			# wrapper for perl script
$LoginUrl = "http://132.248.32.120$CgiPrgm";		# login html page
$LogoutUrl = "http://132.248.32.120/ariel/ArielLogout.htm";	# logout html page

$TimeOut = 30; # minute timeout period

$LoginPage = <<LOGINPAGE;
Content-type: text/html
Expires: Thu, 01 Dec 1994 16:00:00 GMT
Pragma: no-cache 
Cache-control: no-cache

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<TITLE>Ariel&#174; Document Delivery: Logging In</TITLE>
</HEAD>
<BODY>
<blockquote>
<H2>Ariel&#174; Document Delivery: Logging In</H2>
<P>To retrieve your document(s), please follow these instructions:</p>
<UL>
<LI>Enter your complete e-mail address (e.g., gstudent\@university.edu).
<LI>Enter your PIN number (sent to you in your e-mail notification).
<LI>Click the LOGIN box.
</UL>
<p>You must have Adobe Acrobat Reader (version 3.0 or higher) installed to be able to read your document.  If you do not have Adobe Acrobat Reader, you will need to download and install it.</p>
<p>After logging in, you will see a list of your available documents.  To view a document, click on the document link.  The system will automatically remove your document after it is viewed [#] times or after [#] days/weeks have passed since you received your e-mail notification, whichever comes first.</p>
<p>By using this service you are agreeing to uphold the copyright restrictions applicable to all library materials.  This material is subject to US Copyright Law; further reproduction in violation of that law is prohibited.</p>
<br>
<CENTER>
<form method="POST" action="$CgiPrgm">
<INPUT TYPE="HIDDEN" NAME="CCC" VALUE="LOGIN">
<INPUT TYPE="HIDDEN" NAME="TTT" VALUE="##SESSTRING##">
Your complete e-mail address: <INPUT TYPE="TEXT" NAME="EMAIL"><p>
Your PIN number: <INPUT TYPE="PASSWORD" NAME="PIN"><p>
<INPUT TYPE="SUBMIT" VALUE="LOGIN"><p>
</form>
</CENTER>
</blockquote>
</BODY>
</HTML>
LOGINPAGE

$ConfigurableText = <<CONFIGURABLETEXT;
<H2>Ariel&#174; Document List</H2>
<p>The following documents are available for you to view and download.</p>
<UL>
<LI>To view a document, click on the document link.
<LI>To remove a document after it is no longer needed, select the checkbox next to the document and then click the Remove button.
<LI>Once a document has been removed, you will no longer be able to view it. The document will remain in your document list with a status of Removed until it is automatically deleted from the server.
</UL>
<p>The system will automatically remove your document after it is viewed [#] times or after [#] days/weeks have passed since you received your e-mail notification, whichever comes first.</p>
<p>By using this service you are agreeing to uphold the copyright restrictions applicable to all library materials.  This material is subject to US Copyright Law; further reproduction in violation of that law is prohibited.</p>

CONFIGURABLETEXT

$IncorrectEmailPin = <<INCORRECTEMAILPIN;
Content-type: text/html

You don't have any available documents. Please make sure that your e-mail address and/or PIN is correct 
and <a href='javascript:history.go(-1)'>login</a> again.

INCORRECTEMAILPIN

$AlreadyLogout = <<ALREADYLOGOUT;
Content-type: text/html

You already logged out. Please <a href='$LoginUrl'>login</a> again

ALREADYLOGOUT

$UserTimeOut = <<USERTIMEOUT;
Content-type: text/html

Your session has ended due to inactivity. Please <a href='$LoginUrl'>login</a> again

USERTIMEOUT

$InvalidSession = <<INVALIDSESSION;
Content-type: text/html

We are unable to process your login request. Please <a href='$LoginUrl'>login</a> again.
INVALIDSESSION

$FailToAccessDoc = <<FAILTOACCESSDOC;
Content-type: text/html

There is a problem accessing your document. Please inform your administrator of this problem.
FAILTOACCESSDOC

$IncorrectConfig = <<INCORRECTCONFIG;
Content-type: text/html

There is problem in your server configuration. Please inform your administrator of this problem.
INCORRECTCONFIG

#During the session, please refrain from clicking your browser's back and refresh (reload) buttons
#===============================================================================


# get form input, assuming a POST but handling GET as well
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});

$method = "POST";
if ($buffer eq "") {
 $buffer = $ENV{'QUERY_STRING'};
 $method = "GET";
}

# Split the name-value pairs
@pairs = split(/&/, $buffer);
@docArr = ();
@rmDocArr = ();
foreach $pair (@pairs) {
 ($name, $value) = split(/=/, $pair);
 $value =~ tr/+/ /;
 $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
 $FORM{$name} = $value;
 if ($name eq "DOC") {
  push(@docArr, $value);
 }
}

$command = $FORM{'CCC'};
$email = "";
$pin = "";
$epin = "";
$sesFileName = "";
$sesString = "";
$viewFileStem = "";
$removeFile = 0;
$docHtmlCnt = "";
$logFileName = "";

($secs, $min, $hr, $mday, $mnth, $yr, $wd, $yd, $ds) = localtime();

if ($mday < 10) {
 $mday = "0$mday";
}
$mnth = $mnth+1;
if ($mnth < 10) {
 $mnth = "0$mnth";
}
$logFileName = "$LogFilePath" . "20" . substr("$yr",1,2) . "$mnth$mday.log";
$logFileName =~ /(.+)/;
$logFileName = $1;
if ($hr < 10) {
 $hr = "0$hr";
}
if ($min < 10) {
 $min = "0$min";
}
if ($secs < 10) {
 $secs = "0$secs";
}

if ($command eq "") { # startup
 srand(time^$$);
 $sesString = int(rand(60000));
 $sesString = unpack("H*", pack("Nnn", time, $$, $sesString));
 $sesFileName = "$SesFilePath$sesString.ttt";
 $sesFileName =~ /(.+)/;
 $sesFileName = $1;
 if (open(SES, ">$sesFileName")) {
  close(SES);
 } else {
  LogError("Failed to open session file $sesFileName");
  print $IncorrectConfig;
  exit;
 }
 $LoginPage =~ s/##SESSTRING##/$sesString/;
 print $LoginPage;
 exit;
} elsif ($command eq "LOGIN") {
 $email = $FORM{'EMAIL'};
 $pin = $FORM{'PIN'};
 $epin = pack("u",$pin);
 $sesString = $FORM{'TTT'};
 $sesFileName = "$SesFilePath$sesString.ttt";
 $sesFileName =~ /(.+)/;
 $sesFileName = $1;
 if (! -e $sesFileName) {
  print $InvalidSession;
  exit;
 }
} else {
 $sesString = $FORM{'TTT'};
 $sesFileName = "$SesFilePath$sesString.ttt";
 $sesFileName =~ /(.+)/;
 $sesFileName = $1;
 my $mtime = (stat($sesFileName))[9];
 if (-e $sesFileName && (time() - $mtime) > ($TimeOut * 60)) { # user session times out
  unlink($sesFileName);
  print $UserTimeOut;
  exit;
 }
 if ($command eq "LOGOUT") {
  if (-e $sesFileName) {
   unlink($sesFileName);
  }
 print <<LOGOUTDATA;
Content-type: text/html

<html><body onLoad="window.location = '$LogoutUrl'"></body></html>

LOGOUTDATA

  exit;
 } else {
  if (-e $sesFileName) {
   if (open(SES, "$sesFileName")) {
    $email = <SES>;
    chomp($email);
    $epin = <SES>;
    chomp($epin);
    $pin = unpack("u",$epin);
#    $removeFile = <SES>;
#    chomp($removeFile);
    close(SES);
    # change the modification time of sesfile
    my @tmplist = ();
    push(@tmplist, $sesFileName);
    utime(time(), time(), @tmplist);
   } else {
    LogError("Failed to open session file $sesFileName");
    print $IncorrectConfig;
    exit;
   }
  } elsif ($command eq "VVV") {
   print "Content-type: text/html\n\n";
   print "<html><body onLoad=\"window.close()\"></body></html>";
   exit;
  } else {
   print $AlreadyLogout;
   exit;
  }
 }
}

if ($command eq "VVV") {
 $viewFileStem = "ARIEL\_$pin\_" . $FORM{"DDD"};
 my @doclist;
 $DocFilePath =~ /(.+)/;
 opendir(DIRHANDLE,$1);
 @doclist = grep {/^${viewFileStem}\./} readdir(DIRHANDLE);
 closedir(DIRHANLE);
 if (scalar(@doclist) == 0) {
  print $FailToAccessDoc;
  LogError("Failed to find the required document $DocFilePath$viewFileStem.*");
 } else {
  my $dfile;
  my $found = "";
  foreach $dfile (@doclist) {
   $dfile = "$DocFilePath$dfile";
   $viewFileStem = basename($dfile,"");
   if ($viewFileStem =~ /\.CTRL$/) { 
    next;
   } elsif ($viewFileStem =~ /\.TIF$/) { 
    print "Content-type: image/tiff\n";
    print "Content-disposition: filename=ArielDoc.tif\n\n";
   } elsif ($viewFileStem =~ /\.PDF$/) {
    print "Content-type: application/pdf\n";
    print "Content-disposition: filename=ArielDoc.pdf\n\n";
   } else {
    next;
   }
   $found = 1;
   if (open(DOC, "$dfile")) {
    binmode DOC;
    binmode STDOUT;
    while (<DOC>) {
     print;
    }
    close(DOC);
#    if ($removeFile) {
#     renameDoc($viewFileStem);
#    }
   } else {
    print $FailToAccessDoc;
    LogError("Failed to open the required document $dfile");
   }
   last;
  }
  if (! $found) {
   print $FailToAccessDoc;
   LogError("Failed to find the required document $DocFilePath$viewFileStem.*");
  }
 }
 exit;
}

$DocFilePath =~ /(.+)/;
opendir(DIRHANDLE,$1);
@filelist = grep {/^ARIEL_${pin}_/} readdir(DIRHANDLE);
closedir(DIRHANLE);

if (scalar(@filelist) > 0) {
 if ($command eq "LOGIN") {
  if (open(SES, ">$sesFileName")) {
   print SES "$email\n";
   print SES "$epin\n";
   close(SES);
  } else {
   LogError("Failed to open session file $sesFileName");
   print $IncorrectConfig;
   exit;
  }
 } elsif ($command eq "VIEWDOC") {
  @rmDocArr = @docArr;
  @docArr = ();
  push(@docArr, "ARIEL\_$pin\_" . $FORM{"DDD"});
 } elsif ($command eq "REMOVEDOC") {
  for ($i = 0; $i < scalar(@docArr); $i++) {
   $docArr[$i] = "ARIEL\_$pin\_" . $docArr[$i];
  }
 }

 my (@docData) = ();

 foreach $file (@filelist) {
  if ($file !~ m/\.CTRL$/) {
   next;
  }
  my ($patronEmail, $status, $title, $datePosted, $numViews, $maxViews);
  my ($month, $day, $year);
  my $updateFile = 0;
  $file = "$DocFilePath$file";
  if (open(CTR, "$file")) {
   $patronEmail = <CTR>;
   chomp($patronEmail);
   $patronEmail =~ s/\015//g;
   if (lc($patronEmail) ne lc($email)) {
    close(CTR);
    next;
   }
   $status = <CTR>;
   chomp($status);
   $status =~ s/\015//g;
   $title = <CTR>;
   chomp($title);
   $title =~ s/\015//g;
   $datePosted = <CTR>;
   chomp($datePosted);
   $datePosted =~ s/\015//g;
   ($month, $day, $year) = split(m"[-/]", $datePosted);
   $month =~ s/^0//;
   $day =~ s/^0//;
   $numViews = <CTR>;
   chomp($numViews);
   $numViews =~ s/\015//g;
   $maxViews = <CTR>;
   chomp($maxViews);
   $maxViews =~ s/\015//g;
   close(CTR);
  } else {
   LogError("Failed to open control file $file");
   print $IncorrectConfig;
   exit;
  }
  my $docStem = basename($file, "");
  $docStem =~ s/\.CTRL$//;

  my $ext = 'pdf';
  my @fArr = grep(m/^${docStem}(?!.CTRL)/,@filelist);
  if (scalar(@fArr) > 0) {
   if (@fArr[0] =~ /\.TIF$/) { 
    $ext = 'tif';
   }
  }

  if (matchDoc($docStem)) {
   if ($command eq "VIEWDOC") {
    if ($status ne "1") {
     $updateFile = 1;
     $numViews++;
     if ($numViews >= $maxViews) {
      $status = "1";
     }
#     if (open(SES, ">$sesFileName")) {
#      print SES "$email\n";
#      print SES "$epin\n";
#      if ($status eq "1") {
#       print SES "1\n";
#      }
#      close(SES);
#     } else {
#      LogError("Failed to open session file $sesFileName");
#      print $IncorrectConfig;
#      exit;
#     }
    }
   } elsif ($command eq "REMOVEDOC") {
    if ($status ne "2") {
     $updateFile = 1;
     $status = "2";
#     renameDoc($docStem);
    }
   }
  }

  $docStem = substr($docStem,length($pin)+7);

  push(@docData, {
   Title => $title,
   NumViews => $numViews,
   Year => $year,
   Month => $month,
   Day => $day,
   Status => $status,
   DocStem => $docStem,
   Extension => $ext
  });

  if ($updateFile) {
   $file =~ /(.+)/;
   if (open(CTR, ">$1")) {
    print CTR "$email\n";
    print CTR "$status\n";
    print CTR "$title\n";
    print CTR "$datePosted\n";
    print CTR "$numViews\n";
    print CTR "$maxViews\n";
    close(CTR);
   } else {
    LogError("Failed to open control file $1");
    print $IncorrectConfig;
    exit;
   }
  }
 } # foreach

 if (scalar(@docData) == 0) {
  unlink($sesFileName);
  print $IncorrectEmailPin;
  exit;
 }

 @docData = sort byDate @docData;
 foreach $oneDoc (@docData) {
 my $status = $oneDoc->{Status};
  $docHtmlCnt .= "<tr valign=middle bgcolor=#fffff0>\n<td width=\"1%\" align=center>";
  if ($status eq "2") {
   $docHtmlCnt .= "&nbsp;</td>\n";
  } else {
   my $checked = "";
   foreach $rmDoc (@rmDocArr) {
    if ($rmDoc eq $oneDoc->{DocStem}) {
     $checked = " checked";
     last;
    }
   }
   $docHtmlCnt .= "<input type=checkbox name=\"DOC\" value=\"$oneDoc->{DocStem}\" $checked></td>\n";
  }
  my $title2 = $oneDoc->{Title};
  $title2 =~ s/</&#60;/;
  if ($status eq "0") {
   $docHtmlCnt .= "<TD><a href='javascript:openDoc(\"$oneDoc->{DocStem}\",\"$oneDoc->{Extension}\");'>$title2</a></td>\n";
  } else {
   $docHtmlCnt .= "<TD>$title2</td>\n";
  }
  my $pDate = "$oneDoc->{Month}/$oneDoc->{Day}/$oneDoc->{Year}";
  $docHtmlCnt .= "<TD align=center>$oneDoc->{NumViews}</td>\n<TD align=center>$pDate</td>\n<TD align=center>";
  if ($status eq "0") {
   $docHtmlCnt .= "Available</td>\n";
  } elsif ($status eq "1") {
   $docHtmlCnt .= "No more views\n";
  } elsif ($status eq "2") {
   $docHtmlCnt .= "Removed</td>\n";
  } else {
   $docHtmlCnt .= "Unknown</td>\n";
  }
  $docHtmlCnt .= "</TR>\n";
 } # foreach

 print <<OUTPUTDATA1;
Content-Type: text/html
Expires: Thu, 01 Dec 1994 16:00:00 GMT
Pragma: no-cache 
Cache-control: no-cache

<HTML>
<HEAD>
<TITLE>Ariel&#174; Document List</TITLE>
<SCRIPT LANGUAGE="JavaScript">
var removeDocMsg = "Are you sure you want to Remove the selected document? You will not be able to view or download the document once it has been Removed."
function openDoc(docName, ext) {
	document.docform.DDD.value = docName
	if (navigator.appVersion.indexOf("MSIE 6")>=0) {
		document.docform.target = "doc.$min-$secs-$hr"
		document.docform.CCC.value = "VVV"
		document.docform.EXT.value = ext
		document.docform.submit()
		document.docform.target = ""
	} else if (navigator.userAgent.indexOf("Opera")>=0) {
		var url = "http://" + window.location.host + "$CgiPrgm"
		url += "?CCC=VVV&DDD=" + docName + "&TTT=$sesString&ZZZ=$min-$secs-$hr." + ext
		window.open(url,"")
		window.focus()
	} else {
		window.blur()
		var url = "http://" + window.location.host + "$CgiPrgm"
		url += "?CCC=VVV&DDD=" + docName + "&TTT=$sesString&ZZZ=$min-$secs-$hr." + ext
		var docWindow = window.open(url, "","menubar,status=yes,scrollbars,resizable")
		docWindow.focus()
//		docWindow.document.location.href = url
//		window.blur()
	}
	document.docform.CCC.value = "VIEWDOC"
	setTimeout("document.docform.submit()",60)
}
function removeDoc() {
	var hasDoc = false
	for (var i =0; i < document.docform.elements.length; i++) {
		if (document.docform.elements[i].name == "DOC") {
			if (document.docform.elements[i].checked) {
				if (confirm(removeDocMsg)) {
					document.docform.CCC.value = "REMOVEDOC"
					document.docform.submit()
				}
				return
			} else {
				hasDoc = true
			}
		}
	}
	if (hasDoc == true) {
		alert("Please select one document to remove")
	} else {
		alert("You have no documents available for removing")
	}
}
function logout() {
	document.docform.CCC.value = "LOGOUT"
	document.docform.submit()
}
</SCRIPT>
</HEAD>

OUTPUTDATA1

 print "<BODY>\n";

 print $ConfigurableText;

 print <<OUTPUTDATA2;
<BR>
<form name="docform" method="POST" action="$CgiPrgm">
<INPUT TYPE="HIDDEN" NAME="CCC" VALUE="">
<INPUT TYPE="HIDDEN" NAME="TTT" VALUE="$sesString">
<INPUT TYPE="HIDDEN" NAME="DDD" VALUE="">
<INPUT TYPE="HIDDEN" NAME="EXT" VALUE="">
<table width="100%" cellspacing=0 cellpadding=0 border=0>
<tr><td colspan=2 bgcolor=#9999CC>
<table cellpadding=2 cellspacing=0 width="100%" border=0><tr>
<td><font face="Arial,Helvetica" size=-1>
<input type=button onclick="removeDoc()" value="Remove"></font>
<font face="Arial,Helvetica">checked document(s)</font>
</td>
<td align=right><font face="Arial,Helvetica" size=-1>
<input type=button value="Close Session" onclick="logout()">
</td>
</tr></table>
</td></tr>
<tr><td colspan=2 bgcolor=#cccccc>
<table width="100%" cellpadding=2 cellspacing=1 border=0>
<tr bgcolor=#eeeecc>
<td align=center width="1%">&nbsp;</td>
<td align=center nowrap><font face="Arial,Helvetica" size=-1><b>Document</b></td>
<td align=center nowrap><font face="Arial,Helvetica" size=-1><b># Views</b></td>
<td align=center nowrap><font face="Arial,Helvetica" size=-1><b>Date Posted</b></td>
<td align=center nowrap><font face="Arial,Helvetica" size=-1><b>Status</b></td>
</tr>

OUTPUTDATA2

 print "$docHtmlCnt";

 print <<OUTPUTDATA3;
</table>
</td></tr>
<tr><td colspan=2 bgcolor=#9999CC>
<table cellpadding=2 cellspacing=0 width="100%" border=0><tr>
<td><font face="Arial,Helvetica" size=-1>
<input type=button onclick="removeDoc()" value="Remove"></font>
<font face="Arial,Helvetica">checked document(s)</font>
</td>
<td align=right><font face="Arial,Helvetica" size=-1>
<input type=button value="Close Session" onclick="logout()">
</td>
</tr></table>
</td></tr>
</table>
</form><BR></BODY></HTML>

OUTPUTDATA3

} else {
 unlink($sesFileName);
 print $IncorrectEmailPin;
}

exit;

sub matchDoc
{
 my ($docStem) = @_;
 my $i; 
 my $return = 0;
 for ($i = 0; $i < scalar(@docArr); $i++) {
  if ($docStem eq $docArr[$i]) { 
   $return = 1;
   last;
  }
 }
 return ($return);
}

sub LogError()
{
 my ($errMsg) = @_;
 if (open(LOG, ">>$logFileName" )) {
  print LOG "$hr:$min:$secs  E-mail=$email, Error: $errMsg\n";
  close(LOG);
 }
}

sub byDate()
{
 my ($retVal);
 $retVal = $a->{Year} <=> $b->{Year};
 if ($retVal == 0) {
  $retVal = $a->{Month} <=> $b->{Month};
 }
 if ($retVal == 0) {
  $retVal = $a->{Day} <=> $b->{Day};
 }
 if ($retVal == 0) {
  $retVal = lc($a->{Title}) cmp lc($b->{Title});
 }
 return($retVal);
}

sub renameDoc
{
 my ($docStem) = @_;
 my ($remFileName, $newFileName);
 $DocFilePath =~ /(.+)/;
 opendir(DIRHANDLE,$1);
 my @remlist = grep {/^${docStem}/} readdir(DIRHANDLE);
 closedir(DIRHANLE);
 foreach $remFileName (@remlist) {
  if ($remFileName =~ /\.PDF$/) {
   $newFileName = $remFileName;
   $newFileName =~ s/\.PDF$/.REM/;
   $remFileName = "$DocFilePath$remFileName";
   $remFileName =~ /(.+)/;
   $remFileName = $1;
   $newFileName = "$DocFilePath$newFileName";
   $newFileName =~ /(.+)/;
   $newFileName = $1;
   rename $remFileName, $newFileName;
   last;
  } elsif ($remFileName =~ /\.TIF$/) {
   $newFileName = $remFileName;
   $newFileName =~ s/\.TIF$/.REM/;
   $remFileName = "$DocFilePath$remFileName";
   $remFileName =~ /(.+)/;
   $remFileName = $1;
   $newFileName = "$DocFilePath$newFileName";
   $newFileName =~ /(.+)/;
   $newFileName = $1;
   rename $remFileName, $newFileName;
   last;
  }
 }
}
