#!/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://biblioteca.ibt.unam.mx/cgi-bin/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>Para bajar tus documento(s), favor de seguir estas instrucciones:
</p>
<UL>
<LI>Incluye tu direcci&oacute;n de email completa (p.e. nombre\@ibt.unam.mx)
<LI>Incluye tu NIP (enviado en la notificaci&oacute;n por email).
<LI>Selecciona el bot&oacute;n de Login.
</UL>
<p>Necesitas tener instalado software para leer formato pdf, como Adobe Acrobat Reader (versi&oacute;n 3.0 o mas reciente) para poder leer tu documento.  Si no lo tienes, habr&iacute;a que bajarlo e instalarlo.</p>
<p>Despues de hacer el login, ver&aacute;s una lista de tus documentos disponibles. Para ver un documento, selecciona la liga del documento. El sistema borrar&iacute;a autom&aacute;ticamente tu documento despu&eacute;s de que lo hayas visualizado 5 veces o despues de 30 d&iacute;as de que hayas recibido la notificaci&oacute;n por email, lo que ocurra primero.</p>
<p>Cuando utilizas este servicio, te estas comprometiendo a respetar las condiciones y limitaciones impuestas por el derecho de autor a los materiales de la biblioteca.</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; Lista de documentos</H2>
<p>Los siguientes documentos se encuentran disponibles para visualizar y bajar.</p>
<UL>
<LI>Para visualizar un documento, selecciona la liga.
<LI>Para quitar un documento que ya no requieres, selecciona la casilla al lado del documento y presiona el bot&oacute;n <em>Remove</em>.
<LI>Una vez removido el documento, no vas a poder visualizarlo mas. El documento quedar&iacute;a en tu lista con el status de Removido hasta se quita autom&aacute;ticamente del servidor.
</UL>
<p>El sistema borrar&iacute;a tu documento autom&aacute;ticamente despues de visualizarlo 5 veces o despues de que hayan transcurrido 30 d&iacute;as de haberte mandado la notificaci&oacute;n por email, lo que ocurra primero.</p>
<p>Cuando utilizas este servicio, te estas comprometiendo a respetar las condiciones y limitaciones impuestas por el derecho de autor a los materiales de la biblioteca.
</p>

Si tienes dudas o sugerencias, favor de mandar un email a Shirley Ainsworth shirley\@ibt.unam.mx
<P>

CONFIGURABLETEXT

$IncorrectEmailPin = <<INCORRECTEMAILPIN;
Content-type: text/html

No tienes documentos disponibles. Favor de verificar tu direcci&oacute;n de email y/o el NIP.
y hacer <a href='javascript:history.go(-1)'>login</a> de nuevo.

INCORRECTEMAILPIN

$AlreadyLogout = <<ALREADYLOGOUT;
Content-type: text/html

Ya hiciste el logout. Favor de hacer el <a href='$LoginUrl'>login</a> de nuevo

ALREADYLOGOUT

$UserTimeOut = <<USERTIMEOUT;
Content-type: text/html

Tu sesi&oacute;n ha terminado debido a inactividad. Favor de hacer <a href='$LoginUrl'>login</a> de nuevo.

USERTIMEOUT

$InvalidSession = <<INVALIDSESSION;
Content-type: text/html

No podemos procesar tu login de sesi&oacute;n. Favor de hacer el <a href='$LoginUrl'>login</a> de nuevo.
INVALIDSESSION

$FailToAccessDoc = <<FAILTOACCESSDOC;
Content-type: text/html

Hay un problema para accesar tu documento. Favor de informar a Shirley Ainsworth
FAILTOACCESSDOC

$IncorrectConfig = <<INCORRECTCONFIG;
Content-type: text/html

Hay un problema con la configuraci&oacute;n de tu servidor. Favor de informar al administrador.
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;
  }
 }
}
