<?php
#
# dspam.php (c) 2004 Michael Thompson dspam@michaelthompson.org
# for the latest info visit http://michaelthompson.org/dspam/
#
# this php implementation of the dspam.php interface by the
# incredible folks at networkdweebs corporation is maintained
# by Michael Thompson
#
# 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
require("inc/config.inc.php");

#############################################################
# do this so no one has to run with register_globals=On
#############################################################
import_request_variables("gpc");

#######################################################################
# these are things which may be set in inc/config.inc.php file
#######################################################################
if( !isset($date_format) ) $date_format "H:i d-M-y";

if( !isset(
$bLock) ) $bLock true;
if( !isset(
$fp_prefix) ) $fp_prefix "ham-";
if( !isset(
$sp_prefix) ) $sp_prefix "spam-";
if( !isset(
$wl_prefix) ) $wl_prefix "white-";

if( !isset(
$nSkip) ) $nSkip 0;
if( !isset(
$nPage_default) ) $nPage_default=50;
if( !isset(
$nPage) ) $nPage $nPage_default;
if( 
$nPage==) unset($nPage);

if( !isset(
$bDefangPolicy) ) $bDefangPolicy=true;
if( !isset(
$bDefang) ) $bDefang true;
if( 
$bDefangPolicy $bDefang true;

#######################################################################
# these are things which we should have from the server
#######################################################################
$user trim($_SERVER["REMOTE_USER"]);
if( 
strlen($user)<$user trim($_SERVER["REDIRECT_REMOTE_USER"]);
if( 
strlen($user)<$user trim($_SERVER["PHP_AUTH_USER"]); 
if( 
strlen($user)<) die("did you authenticate?");
if( !isset(
$domain) ) $domain $_SERVER["HTTP_HOST"];

#######################################################################
# these are things which we should be able to infer
#######################################################################
$fp_user "$fp_prefix$user@$domain";
$wl_user "$wl_prefix$user@$domain";
$user_email "$user@$domain";
if( !isset(
$kp_user) ) $kp_user $user_email;

if( 
strlen(trim($find))<) unset($find);
if( isset(
$find) && isset($cmd) ) $memFind = (isset($find))?"?find=$find":"";

if( 
$LARGE_SCALE )
{
  
# in large scale user names map to dspam subdirectoriesdifferently
  # i.e. for the the user name michael normally 
  # we would expect  /etc/mail/dspam/michael/
  # but in "large scale" it maps to /etc/mail/dspam/m/i/michael/
  # and the user name "m" maps to the subdirectory /etc/mail/dspam/m/
  
$dirDSPAM .= "/" substr($user,0,1);
  if( 
strlen($user)>$dirDSPAM .= "/" substr($user,1,1);

elseif( 
$DOMAIN_SCALE 
{
  
# Switch for domain-scale implementation.  Currently only affects the
  # filesystem layout for dspam.  When used, 
  # user data will be stored as $USERDIR/domain/user 
  
$dirDSPAM .= "/$domain";
}

$spam_mbox "$dirDSPAM/$user/$user.mbox";
$stats_file "$dirDSPAM/$user/$user.stats";

#######################################################################
# functions
#######################################################################
function cleanTmp()
{
  global 
$dirWebTMP;
  global 
$user;

  if( 
is_dir($dirWebTMP) ) 
  {
    if( (
$dh opendir($dirWebTMP)) ) 
    {
      while( (
$file=readdir($dh)) ) 
      {
        if( 
strstr($file,"$user") &&  
            
strstr($file,".html") ) unlink("$dirWebTMP/$file");
      }
      
closedir($dh);
    }
  }
}

$bMailQueued false;
$arMailQueue = array();
$arEnvelope = array();
function 
queueMail($addr,$subj,$msg,$header=null)
{
  global 
$arMailQueue;
  global 
$arEnvelope;
  global 
$rs_user;

  if( 
count($arEnvelope)<
  {
    
$arEnvelope[]="X-";

    if( (
$fh=fopen("./inc/envelope.lis","r")) )
    {
      while( !
feof($fh) )
      {
        
$buff trim(fgets($fh,1024));
        if( 
strlen($buff)<) continue;
        if( 
$buff[0]=="#" ) continue;
        
        
$arEnvelope[] = $buff ": ";
      }
    }
    else
    {
      
$arEnvelope[]="Content-Class: ";
      
$arEnvelope[]="Content-Type: ";
      
$arEnvelope[]="MIME-Version: ";
      
$arEnvelope[]="Thread-Index: ";
      
$arEnvelope[]="Delivered-To: ";
      
$arEnvelope[]="Errors-To: ";
      
$arEnvelope[]="Return-Path: ";
      
$arEnvelope[]="Reply-To: ";
      
$arEnvelope[]="Received: ";
      
$arEnvelope[]="Status: ";
      
$arEnvelope[]="Date: ";
      
$arEnvelope[]="Content-Transfer-Encoding: ";
    }
  }

  
$n count($arMailQueue);
  
$arMailQueue[$n]["addr"]=$addr;
  
$arMailQueue[$n]["subj"]=$subj;
  
$arMailQueue[$n]["msg"]=$msg;
  if( 
$header==null $arMailQueue[$n]["header"]=null;
  else
  {
    
# we just want certain selected items from the header
    
$ar explode("\n",$header);
    if( 
is_array($ar) ) 
    { 
      
$bKeep false;
      foreach( 
$ar as $header_line 
      { 
        if( 
substr($header_line,0,5)=="From " ) continue;
        if( 
substr($header_line,0,9)=="Subject: " 
        {
          
$arMailQueue[$n]["subj"]=substr($header_line,9);
          continue;
        }
        if( 
$bKeep && !ctype_space($header_line[0]) ) $bKeep false;
        foreach( 
$arEnvelope as $header )
        {
          
$buff substr($header_line,0,strlen($header));
          if( 
strcasecmp($buff,$header)==
          {
            
$bKeep true;
            break;
          }
        }
        if( 
$bKeep $arMailQueue[$n]["header"] .= $header_line "\n";
      }
      
$arMailQueue[$n]["header"] .= "\n";
    }
  }
}

function 
sendMail()
{
  global 
$arMailQueue;
  foreach( 
$arMailQueue as $ar )
  { if( 
$ar["header"]==null mail($ar["addr"],$ar["subj"],$ar["msg"]);
    else 
mail($ar["addr"],$ar["subj"],$ar["msg"],$ar["header"]);
  }
}

$txtOnly "";
$nDisplayed=0;
$fhTmp null;
$bMIMEinline=false;
function 
handleMIME($value,$key)
{
  global 
$fhTmp;
  global 
$bMIMEinline;
  global 
$bMIMEattach;
  global 
$txtOnly;
  global 
$nDisplayed;

  if( 
$fhTmp 
  {
    if( 
is_array($value) || is_object($value) ) array_walk($value,handleMIME);
    else 
    {
      if( 
$key=="ctype_secondary" )
      {
        if( 
$value=="html" $bMIMEinline true;
      }
      elseif( 
$key=="body" )
      {
        if( !
$bMIMEinline $txtOnly .= $value;
        else
        {
          
$nDisplayed++;
          
$bMIMEinline false;
          
fwrite($fhTmp,"$value");
        }
      }
      elseif( 
$key=="name" fwrite($fhTmp,"Attachment: $value");
    }
  }
}

$nMsgs 0;
$bHaveTable false;
$bHaveClean false;
$row_toggle 2;
$nHandled 0;
function 
handleMsg($nMsg)
{
  
##################
  
global $cmd;
  global 
$msgRecord;
  global 
$msgHeader;
  global 
$msgBody;
  global 
$msgID;
  global 
$msgSubj;
  global 
$msgFrom;
  global 
$msgDate;
  
##################
  
global $dspamBIN;
  global 
$deliverFP;
  global 
$fp_user;
  global 
$wl_user;
  global 
$kp_user;
  global 
$user;
  global 
$user_email;
  global 
$dspamID;
  global 
$date_format;
  
##################
  
global $dirWebTMP;
  global 
$tmpfile;
  global 
$fout;
  global 
$row_toggle;
  global 
$bHaveTable;
  
##################
  
global $nHandled;
  global 
$nPage;
  global 
$nSkip;
  
##################
  
global $bDefangPolicy;
  global 
$bDefang;
  global 
$fhTmp;
  global 
$txtOnly;
  global 
$nDisplayed;
  
##################
  
global $find;
  
##################

  
if( !isset($find) && isset($nSkip) && $nMsg<=$nSkip ) return true;
  if( !isset(
$cmd) ) 
  {
    if( isset(
$find) && 
      
stristr($msgSubj,"$find")===false && 
      
stristr($msgBody,"$find")===false ) return true;
  }

  
$nHandled++;
  
$rsp true;

  
# make sure we have a msgID before we handle anything
  # if we don't have a msgID it simply means that something
  # other than DSPAM dropped it in the quarantine so make a 
  # unique ID now like this !CORPUS:00000001!
  
if( !isset($msgID) ) $msgID sprintf("!CORPUS:%08u!",$nMsg);


  
$msgShowFrom = (strlen($msgFrom)<40)?$msgFrom:
              
substr($msgFrom,0,37) . "...";
  
$msgShowFrom str_replace(">","&gt;",str_replace("<","&lt;",$msgShowFrom));

  if( 
$cmd=="view" )
  {
    if( 
$dspamID==$msgID )
    {
      
$rsp false;
      
$uskip = ($nSkip!=0)?"?nSkip=$nSkip":"";
      print <<< EPR
<hr noshade>
<table width="100%">
<tr>
<td>
[ <a href="./dspam.php$uskip">Control Center</a> ]
</td>
EPR;

    if( 
$bDefangPolicy===false )
    {
      
$tg=($bDefang)?0:1;
      
$tt=($bDefang)?"Display HTML":"Display Source";
      print <<< EPR
<td align=center>
[ <a href="./dspam.php?cmd=view&dspamID=$msgID&nSkip=$nSkip&bDefang=$tg">$tt</a> ]
</td>
EPR;
    }

    print <<< EPR
<td align=right>
[ <a href="./dspam.php?cmd=kp&dspamID=$msgID&kp_user=$kp_user">Send to $kp_user</a> ]
</td></tr></table>
<hr noshade>
<table border=1 width="100%"><tr>
<td>$nMsg</td>
<td><a href="./dspam.php?cmd=del&dspamID=$msgID" name="Delete"><img src="images/
del.gif" border=0 alt="Delete"></a></td>
<td width=2><nobr>$msgDate</nobr></td>
<td><a href="./dspam.php?cmd=wl&dspamID=$msgID" name="Whitelist"><img src="image
s/whitelist.gif" border=0 alt="Whitelist"></a></td>
<td width=2 align=right><nobr>$msgShowFrom</nobr></td>
<td><nobr>$msgSubj</nobr></td>
<td><a href="./dspam.php?cmd=fp&dspamID=$msgID" name="NOT Spam"><img src="images
/thumb-up.gif" border=0 alt="NOT Spam"></a></td>
</tr></table>
EPR;

      if( 
$bDefang ) print <<< EPR
<xmp>$msgBody</xmp>
EPR;
      else 
      {
        
$tmp tempnam("$dirWebTMP","$user");
        @
unlink($tmp);
        
$tmp .= ".html";
        if( 
is_file($tmp) ) @unlink($tmp);
        if( !(
$fhTmp=@fopen("$tmp","w")) )
        {
          print <<< EPR
<tt><pre>
###########################################################
# We could not write $tmp
# To display the messages in html format we depend on 
# the existence of a temp directory in the web space. 
# The current setting is: $dirWebTMP
# Contact your system administrator for further information.
###########################################################
</pre></tt>
<xmp>$msgBody</xmp>
<hr noshade>
<xmp>$msgHeader</xmp>
<hr noshade>
EPR;
        }
        else 
        {
          
$bHave_mimeDecode false;
          @include_once(
"Mail/mimeDecode.php");
          
$arOK get_included_files();
          foreach( 
$arOK as $inc )
          { if( 
strstr($inc,"Mail/mimeDecode.php") ) 
            { 
$bHave_mimeDecode true;
              break;
            }
          }
          if( !
$bHave_mimeDecode 
          {
            
$msg =<<<EMSG
<tt><pre>
###########################################################
# We could not load the PEARL module Mail/mimeDecode.php
# to help display this message. The dspamCC will use it 
# if is available in the "include" path. Contact your 
# system administrator for further information.
###########################################################
</pre></tt>
EMSG;
            
fwrite($fhTmp,"$msg");
            
fwrite($fhTmp,"$msgBody");
          }
          else
          {
            
$params['include_bodies'] = true;
            
$params['decode_bodies'] = true;
            
$params['decode_headers'] = true;
            
$params['input'] = $msgRecord;
            
$mime=Mail_mimeDecode::decode($params);
            if( 
is_object($mime) ) array_walk($mime,handleMIME);
            if( 
$nDisplayed<fwrite($fhTmp,"<tt><pre>$txtOnly</pre></tt>");
          }

          print <<< EPR
<hr noshade>
<iframe src="$tmp" width="100%" height=400>
<i>iframe</i> tag not supported by this browser
</iframe>
EPR;
          
fclose($fhTmp);
        }
      }
      print <<< EPR
<hr noshade>
<xmp>$msgHeader</xmp>
<hr noshade>
EPR;
    }
  }
  elseif( 
$cmd=="del" || $cmd=="fp"  || $cmd=="kp" || $cmd=="wl" )
  {
    if( 
false===strstr($dspamID,$msgID) )
    {
      
# this is NOT a message to delete|fp|kp|wl
      
fwrite($fout,$msgRecord) or die("could not write $tmpfile");
    }
    else
    {
      
# this is a message to delete and ...
      
if( $cmd=="fp" || $cmd=="wl" || $cmd=="kp" )
      {
        
# this is a message to report as a false positive|resend|whitelist
        
if( $cmd=="kp" queueMail($kp_user,"",$msgBody,$msgHeader);
        elseif( 
$cmd=="fp" queueMail($fp_user,"$msgID","$msgID",$msgHeader);
        elseif( 
$cmd=="wl" 
        {
          
$email "";
          
$ar explode(" ",trim($msgFrom));
          if( !
is_array($ar) ) $ar[]=$msgFrom;
          foreach( 
$ar as $word )
          {
            if( 
strstr($word,"@") ) 
            {
              
$n strlen($word);
              for( 
$i=$i<$n $i++ )
              {
                if( 
strstr("0123456789-_@.",$word[$i]) ) $email .= $word[$i];
                elseif( 
ctype_alpha($word[$i]) ) $email .= $word[$i]; 
              }
              break;
            }
          }
          if( 
strlen($email)<$email "#$msgFrom";
          
queueMail($wl_user,"wl-add:$user",$email);
        }

        if( 
$cmd=="fp" || $cmd=="wl" )
        {
          
# send original back to the user
          # we don't have to do this if the fp- alias calls dspam with
          # --deliver-fp ... but maybe in that case it wouldn't be
          # here in the quarantine now anyway???
          
if( $deliverFP queueMail($user,"",$msgBody,$msgHeader);
        }

        if( !
$bMailQueued 
        {
          
$bMailQueued true;

          
# we don't actually send the mail until this script
          # ends because a long list of large messages could
          # keep the mbox file open an inconveniently long time
          
register_shutdown_function(sendMail);
        }
      }
    }
  }
  else
  {
    if( !
$bHaveTable 
    {
      
$bHaveTable true;

      print <<< EPR
<table width="100%"><tr valign=top>
<td width="40%">
<input type=button value="Delete Checked Items" onClick="delChecked();">
<input type=button value="Delete ALL Items" onClick="delAll();">
</td>
<td align=right>
<input type=button value="SelectAll" onClick="selectAll();">
<input type=button value="ClearAll" onClick="clearAll();">
</td>
<td align=right>
<input type=text name="find" value="$find" size=12><input type=button value="Find" onClick='goFind();'>
</td>
<td align=right>
<input type=button value="FalsePos Checked Items" onClick="fpChecked();">
</td>
</tr></table>
<table width="100%" cellspacing=2 cellpadding=2>
EPR;
    }
    if( 
$bHaveTable && isset($nPage) && $nHandled>=$nPage $rsp false;

    
$viewmod strstr($msgID,"CORPUS") ? "corpus":"";
    
$msgDate date($date_format,strtotime($msgDate));
    
$msgSubj = (strlen($msgSubj)<50)?$msgSubj:
                
substr($msgSubj,0,47) . "...";
    
$ubgclr=($row_toggle==1)?"":"bgcolor=\"#cccccc\"";
    
$ufind=(isset($find))?"&find=$find":"";

    print <<< EPR
<tr $ubgclr>
<td align=right>$nMsg</td>
<td><a href="./dspam.php?cmd=del&dspamID=$msgID$ufind" name="Delete"><img src="images/del.gif" border=0 alt="Delete"></a></td>
<td width=2><nobr>$msgDate</nobr></td>
<td><a href="./dspam.php?cmd=wl&dspamID=$msgID$ufind" name="Whitelist"><img src="images/whitelist.gif" border=0 alt="Whitelist"></a></td>
<td width=2 align=right><nobr>$msgShowFrom</nobr></td>
<td><input type=checkbox name="$msgID"></td>
<td><a href="./dspam.php?cmd=view&dspamID=$msgID&nSkip=$nSkip&kp_user=$kp_user" name="View Contents"><img src="images/view$viewmod.gif" border=0 alt="View Contents"></a></td>
<td><nobr>$msgSubj</nobr></td>
<td><a href="./dspam.php?cmd=fp&dspamID=$msgID$ufind" name="NOT Spam"><img src="images/thumb-up.gif" border=0 alt="NOT Spam"></a></td>
</tr>
EPR;

    
$row_toggle $row_toggle;
  } 

  return 
$rsp;
}

function 
showInterface()
{
  global 
$user;
  global 
$domain;
  global 
$sp_prefix;
  global 
$date_format;
  global 
$stats_file;

  
$now date("$date_format");
  
$spam_ratio "N/A";
  
$nCaught "0";
  
$nInnocent "0";
  
$nMisses "0";
  
$nFalsePos "0";
  
$nFedSpam "0";
  
$nFedHam "0";

  
$ar = @file("$stats_file");
  if( 
is_array($ar) )
  {
    
$ar explode(",",$ar[0]);
    if( 
is_array($ar) )
    {
      
# Reference from dspam.c where it makes the stats file
      #
      # fprintf (file, "%ld,%ld,%ld,%ld,%ld,%ld\n",
      #    totals->total_spam - (totals->spam_misclassified +
      #                          totals->spam_corpusfed),
      #    totals->total_innocent - (totals->innocent_misclassified +
      #                              totals->innocent_corpusfed),
      #    totals->spam_misclassified, totals->innocent_misclassified,
      #    totals->spam_corpusfed, totals->innocent_corpusfed);
      #

      
$nFedHam $ar[5];   
      
$nFedSpam $ar[4]; 
      
$nFalsePos $ar[3];
      
$nMisses $ar[2]; 
      
$nInnocent $ar[1];
      
$nCaught $ar[0];
    }
  }

  
$div $nCaught $nInnocent;
  if( 
$div==$spam_ratio "N/A";
  else 
$spam_ratio sprintf("%.1f%%"100 * ($nCaught/$div));

  if( (
$nTotal $nCaught $nMisses $nInnocent $nFalsePos)==
  { 
$accuracy "N/A";
  }
  else
  { 
$accuracy sprintf("%.1f%%",100 - (100 * ($nMisses+$nFalsePos)/$nTotal));
  }

  if( 
is_file("inc/template.html") ) include("inc/template.html");
  else print <<< EPR
<html><head><title>DSPAM v2 Control Center</title></head>
<body>
<a href="http://www.nuclearelephant.com/projects/dspam"><img align=left src="images/dspam_logo.gif"></a>
EPR;

  
$sTotal number_format($nTotal);
  
$sCaught number_format($nCaught);
  
$sFalsePos number_format($nFalsePos);
  
$sInnocent number_format($nInnocent);
  
$sMisses number_format($nMisses);
  
$sFedSpam number_format($nFedSpam);
  
$sFedHam number_format($nFedHam);

  print <<< EPR
Welcome, <i>$user</i>! As of <b>$now</b> your<br>
SPAM ratio is <b>$spam_ratio</b> and your filtering accuracy is 
<b>$accuracy</b>
<table>
<tr>
<td align=center>Processed</td>
<td align=center>Caught</td>
<td align=center>FalsePos</td>
<td align=center>Passed</td>
<td align=center>Missed</td>
<td align=center>FedSpam</td>
<td align=center>FedHam</td>
<td rowspan=2>
&nbsp;
</td>
<td rowspan=2>
<nobr><img align=left src="images/del.gif">Discard Message</nobr>
<br clear=all>
<nobr><img align=left src="images/view.gif">View Message</nobr>
</td>
<td rowspan=2>
<nobr><img align=left src="images/thumb-up.gif">Learn this is NOT spam</nobr>
<br clear=all>
<nobr><img align=left src="images/whitelist.gif">Whitelist Sender</nobr>
</td>
</tr>
<tr>
<td align=center><b>$sTotal</b></td>
<td align=center><b>$sCaught</b></td>
<td align=center><b>[ $sFalsePos ]</b></td>
<td align=center><b>$sInnocent</b></td>
<td align=center><b>[ $sMisses ]</b></td>
<td align=center><b>$sFedSpam</b></td>
<td align=center><b>$sFedHam</b></td>
</tr>
</table>
<form>
<script>
function selectAll()
{
  var frm = document.forms[0];
  for( var i=0 ; i<frm.elements.length ; i++ )
  { if( frm.elements[i].type == "checkbox" )
    { frm.elements[i].checked = true;
    }
  }
}
function clearAll()
{
  var frm = document.forms[0];
  if( frm.elements["find"].value.length>0 ) 
  {
    window.location.replace('./dspam.php');
  }
  else
  {
    for( var i=0 ; i<frm.elements.length ; i++ )
    { if( frm.elements[i].type == "checkbox" )
      { frm.elements[i].checked = false;
      }
    }
  }
}
function goFind()
{
  var frm = document.forms[0];
  var url = "./dspam.php?find=" + frm.elements["find"].value;
  window.location.replace(url);
}
function delAll()
{
  var url = "./dspam.php?cmd=del&dspamID=*";
  if( confirm("Delete ALL?") )
  { window.location.replace(url);
  }
}

function delChecked()
{
  var n = 0;
  var frm = document.forms[0];
  var url = "./dspam.php?cmd=del&dspamID=";
  for( var i=0 ; i<frm.elements.length ; i++ )
  { if( frm.elements[i].type == "checkbox" )
    { if( frm.elements[i].checked )
      {
        n++;
        url += frm.elements[i].name;
      }
    }
  }
  if( n>0 ) window.location.replace(url);
  else alert("Nothing appears to be checked");
}
function delPage()
{
  selectAll();
  delChecked();
}
function fpChecked()
{
  var n = 0;
  var frm = document.forms[0];
  var url = "./dspam.php?cmd=fp&dspamID=";
  for( var i=0 ; i<frm.elements.length ; i++ )
  { if( frm.elements[i].type == "checkbox" )
    { if( frm.elements[i].checked )
      {
        n++;
        url += frm.elements[i].name;
      }
    }
  }
  if( n>0 ) window.location.replace(url);
  else alert("Nothing appears to be checked");
}
</script>
EPR;
}

#######################################################################
# main procedure
#######################################################################

if( !isset($cmd) ) showInterface();
if( !(
$fh=@fopen($spam_mbox,"r+")) )
{
  if( 
is_file($smap_mbox) ) print <<< EPR
$spam_mbox could not be read. 
<br clear=all>
EPR;
}
elseif( 
$cmd=="del" && $dspamID=="*" )
{
  
# if we are supposed to delete all quarantined messages just do it now
  
$fh=fopen($spam_mbox,"r+") or die("could not clear $spam_mbox");
  if( 
$bLock flock($fh,LOCK_EX) or die("could not lock $spam_mbox");
  
ftruncate($fh,0);
  if( 
$bLock flock($fh,LOCK_UN);
  
fclose($fh);
}
else
{
  if( 
$cmd=="del" || $cmd=="fp" || $cmd=="kp" || $cmd=="wl" )
  {
    
# make sure we really have a dspamID and not a typo
    
if( !isset($dspamID) || strlen($dspamID)<) unset($cmd);
    else
    {
      if( 
$bLock flock($fh,LOCK_EX) or die("could not lock $spam_mbox");
      
$tmpfile $spam_mbox "." getmypid();
      
$fout fopen($tmpfile,"w+") or die("could not open $tmpfile");
    } 
  }
  if( isset(
$cmd) ) unset($nPage);

  
$bMore false;
  
$bInBody false;
  while( !
feof($fh) )
  {
    
$buff fgets($fh,1024);

    
# messages quarantined by DSPAM start "From ..."
    #     From lwqhs@attglobal.net Sat Feb 28 11:43:07 2004
    # but messages delivered by procmail just start
    
if
    ( 
strlen(trim($buff)) && 
      (
        ( !isset(
$msgRecord) && strstr($buff,": ") )
        ||
        
preg_match("/$new_msg_mark/",$buff
      ) 
    )
    {
      
$nMsgs++;
      if( isset(
$msgRecord) ) 
      {
        if( 
$bMore 
        {
          unset(
$msgHeader);
          continue;
        }
        if( !
handleMsg($nMsgs-1) ) 
        {
          
# this cmd returned false meaning we can
          # stop processing the message file now
          # unset($msgHeader);
          
$bMore true;
        }
      }

      
$bInBody false;

      unset(
$msgID);
      unset(
$msgSubj);
      unset(
$msgFrom);
      unset(
$msgDate);
      unset(
$msgBody);
      unset(
$msgHeader);

      
$msgRecord $buff;
      continue;
    }

    
$msgRecord .= $buff;

    if( 
$bInBody $msgBody .= $buff;
    else 
$msgHeader .= $buff;

    if( !isset(
$msgDate) && substr($buff,0,6)=="Date: " )
    { 
$msgDate trim(substr($buff,6));
      continue;
    }
    if( !isset(
$msgFrom) && substr($buff,0,6)=="From: " )
    { 
$msgFrom trim(substr($buff,6));
      continue;
    }
    if( !isset(
$msgSubj) && substr($buff,0,9)=="Subject: " )
    { 
$msgSubjtrim(substr($buff,9));
      continue;
    }

    
# !DSPAM:403f2a616819133917683!
    
if( !isset($msgID) ) 
    {
      if( 
substr($buff,0,19)=="X-DSPAM-Signature: " 
      { 
$msgID"!DSPAM:" trim(substr($buff,19)) . "!";
      }
      elseif( 
substr($buff,0,7)=="!DSPAM:" && $buff[strlen($buff)-2]=="!" 
      { 
$msgID=trim($buff);
      }
      if( isset(
$msgID) ) continue;
    } 

    if( isset(
$msgHeader) && strlen(trim($buff))<$bInBody true;
  } 
# bottom of file reading loop

  # if there is a message remaining for us to handle, do it now
  
if( !$bMore && isset($msgHeader) ) handleMsg($nMsgs);

  
# if we are rewriting the spam mail box wrap it up now
  
if( isset($fout) )
  {
    
rewind($fout) or die("could not rewind $tmpfile");
    
ftruncate($fh,0) or die("could not truncate $spam_mbox");
    
rewind($fh) or die("could not rewind $spam_mbox");
    while( !
feof($fout) ) 
    {
      
$buff fread($fout,8192);
      
fwrite($fh,$buff);
    }
    if( 
$bLock flock($fh,LOCK_UN);
    
fclose($fout);
  }
  
fclose($fh);
  if( isset(
$tmpfile) ) @unlink($tmpfile);
}

if( !isset(
$cmd) ) 
{
  if( !
$bHaveTable 
  {
    if( isset(
$find) ) 
    {
      print <<< EPR
<hr noshade>
<center>
'$find' was not found in the subject or body of any message in the
quarantine.
<br clear=all>
[ <a href="./dspam.php">View All</a> ]
</center>
EPR;
    }
  }
  else
  {
    print <<< EPR
<tr><td colspan=9 align=right>
<input type=button value="Delete Page" onClick="delPage();">
</td></tr></table>
EPR;
    if( 
$bMore || $nSkip>
    {
      
$next $nSkip $nPage;
      if( (
$prev $nSkip $nPage)<$prev 0;

      print <<< EPR
[ <a href="./dspam.php?nSkip=0">top</a> ]
EPR;
      if( 
$nSkip==) print <<< EPR
[ prev ]
EPR;
      else print <<< EPR
[ <a href="./dspam.php?nSkip=$prev">prev</a> ]
EPR;
      if( !
$bMore || $nHandled<$nPage ) print <<< EPR
[ next ]
EPR;
      else print <<< EPR
[ <a href="./dspam.php?nSkip=$next">next</a> ]
EPR;
      print <<< EPR
[ <a href="./dspam.php?nPage=0">all</a> $nMsgs ]
EPR;
    }
    print <<< EPR
</form>
EPR;
  }

  
cleanTmp();
  print <<< EPR
<hr noshade>
<font size=-1>
<p align=center>
Please forward any other spam messages you have received to 
<a href="mailto:$sp_prefix$user@$domain">$sp_prefix$user@$domain</a> 
so they can be used to train DSPAM
</p>
<hr noshade>
<p align=center>
DSPAM is a trademark of Network Dweebs Corporation<br>
Copyright(c)&nbs