--- SweepViruses.pm	Tue Jun  5 05:37:47 2007
+++ SweepViruses.pm.mod	Tue Jun  5 08:21:49 2007
@@ -3087,34 +3087,32 @@
   my($dir, $child, $childname, $filename, $results, $virus);
 
   # Clamd MUST have the full path to the file/dir it's scanning
   # so let's build the scan dir here and remove that pesky \. at the end
-
-  my $ScanDir = $global::MS->{work}->{dir} . "/$dirname";
+    my $ScanDir = "$global::MS->{work}->{dir}/$dirname";
   $ScanDir =~ s/\/\.$//;
 
   # If we don't have the required perl libs exit in a fashion the
   # parser will understand
-  # JKF -- Should these be '' and not {} as '' are faster than {} ?
-  unless (eval { require IO::Socket::INET }) {
+	unless (eval ' require IO::Socket::INET ' ){
     print "ERROR:: You Need IO-Socket-INET To Use clamd As A " .
           "Scanner :: $dirname\n";
-    exit 1;
+		return 1;
   }
-    unless (eval { require IO::Socket::UNIX }) {
+	unless (eval ' require IO::Socket::UNIX ' ){
     print "ERROR:: You Need IO-Socket-INET To Use clamd As A " .
           "Scanner :: $dirname\n";
-    exit 1;
+		return 1;
   }
 
   # The default scan type is set here and if threading has been enabled
   # switch to threaded scanning
-  my $UseThreads = MailScanner::Config::Value('clamdusethreads');
   my $ScanType = "CONTSCAN";
-  $ScanType = "MULTISCAN" if $UseThreads;
   my $LockFile = MailScanner::Config::Value('clamdlockfile');
   my $TCP = 1;
   my $TimeOut = MailScanner::Config::Value('virusscannertimeout');
+	my $UseThreads = MailScanner::Config::Value('clamdusethreads');
+	$ScanType = "MULTISCAN" if $UseThreads;
 
   my $PingTimeOut = 90; # should respond much faster than this to PING
   my $Port = MailScanner::Config::Value('clamdport');
   my $Socket = MailScanner::Config::Value('clamdsocket');
@@ -3125,163 +3123,190 @@
 
   $TCP = 0 if $Socket =~ /^\//;
 
   # Print our current parameters if we are in debug mode
-  MailScanner::Log::DebugLog("Debug Mode Is On\n");
+	MailScanner::Log::DebugLog("Debug Mode Is On");
   MailScanner::Log::DebugLog("Use Threads : YES") if $UseThreads;
   MailScanner::Log::DebugLog("Use Threads : NO") unless $UseThreads;
-  MailScanner::Log::DebugLog("Socket    : %s\n", $Socket)  unless $TCP;
-  MailScanner::Log::DebugLog("IP        : %s\n", $Socket) if $TCP;
-  MailScanner::Log::DebugLog("IP        : Using Sockets\n") unless $TCP;
-  MailScanner::Log::DebugLog("Port      : %s\n", $Port) if $TCP;
-  MailScanner::Log::DebugLog("Lock File : %s\n", $LockFile) if $LockFile ne '';
+	MailScanner::Log::DebugLog("Socket    : %s", $Socket)  unless $TCP;
+	MailScanner::Log::DebugLog("IP        : %s", $Socket) if $TCP;
+	MailScanner::Log::DebugLog("IP        : Using Sockets") unless $TCP;
+	MailScanner::Log::DebugLog("Port      : %s", $Port) if $TCP;
+	MailScanner::Log::DebugLog("Lock File : %s", $LockFile) if $LockFile ne '';
   MailScanner::Log::DebugLog("Lock File : NOT USED", $LockFile) unless $LockFile ne '';
-  MailScanner::Log::DebugLog("Time Out  : %s\n", $TimeOut);
-  MailScanner::Log::DebugLog("Scan Dir  : %s\n", $ScanDir);
+	MailScanner::Log::DebugLog("Time Out  : %s", $TimeOut);
+	MailScanner::Log::DebugLog("Scan Dir  : %s", $ScanDir);
 
   # Exit if we cannot find the socket file, or we find the file but it's not
   # a socket file (and of course we are not using TCP sockets)
 
-  MailScanner::Log::WarnLog("Cannot find Socket %s Exiting!\n",
-                            $Socket) if !$TCP && ! -e $Socket;
-  exit 1 if !$TCP && ! -e $Socket;
+	MailScanner::Log::WarnLog("Cannot find Socket (%s) Exiting!",
+		$Socket) if! $TCP && ! -e $Socket;
+	return 1 if ! $TCP && ! -e $Socket;
 
   MailScanner::Log::WarnLog("Found %s but it is not a valid UNIX Socket. " .
-                            "Exiting\n", $Socket) if !$TCP && ! -S $Socket;
-  exit 1 if !$TCP && ! -S $Socket;
+		"Exiting", $Socket) if ! $TCP && ! -S $Socket;
+	return 1 if ! $TCP && ! -S $Socket;
 
   # If there should be a lock file, and it's missing the we assume
   # the daemon is not running and warn, pass error to parser and leave
   if ( $LockFile ne '' && ! -e $LockFile ){
     MailScanner::Log::WarnLog("Lock File %s Not Found, Assuming Clamd " .
-                              "Is Not Running\n", $LockFile);
+		"Is Not Running", $LockFile);
     print "ERROR:: Lock File $LockFile was not found, assuming Clamd  " .
           "is not currently running :: $dirname\n";
-    exit 1;
+		return 1;
   }
 
-  # Attempt to open the appropriate socket depending on the time (TCP/UNIX)
-  if ($TCP) {
-    $sock = IO::Socket::INET->new(PeerAddr => $Socket,
-                                  PeerPort => $Port,
-                                  Timeout  => $TimeOut,
-                                  Proto    => 'tcp');
-  } else {
-    $sock = IO::Socket::UNIX->new(Timeout => $TimeOut,
-                                  Peer    => $Socket );
-  }
+	# Connect to the clamd daemon, If we don't connect send the log and
+	# parser an error message and exit.
+	$sock = ConnectToClamd($TCP,$Socket,$Port, $TimeOut);
+	print "ERROR:: COULD NOT CONNECT TO CLAMD, RECOMMEND RESTARTING DAEMON " .
+		  ":: $dirname\n" unless $sock;
+	MailScanner::Log::WarnLog("ERROR:: COULD NOT CONNECT TO CLAMD, ".
+			"RECOMMEND RESTARTING DAEMON ") unless $sock;
+	return 1 unless $sock;
 
   # If we got here we know we have a socket file but it could be dead
   # or clamd may not be listening on the TCP socket we are using, either way
   # we exit with error if we could not open the connection
 
-  if (!$sock) {
-    # socket file from a dead clamd or clamd is not listening
+	if (!$sock ) { # socket file from a dead clamd or clamd is not listening
     MailScanner::Log::WarnLog("Could not connect to clamd");
-    print "ERROR:: COULD NOT CONNECT TO CLAMD DAEMON  :: $dirname\n";
-    exit 1;
-  } else {
-    # Make sure the daemon is responsive before passing it something to scan
-    if ($sock->connected) {
+		print "ERROR:: COULD NOT CONNECT TO CLAMD DAEMON  " .
+			":: $dirname\n";
+    	return 1;
+	}else{
+		# Make sure the daemon is responsive before passing it something to
+		# scan
+		if ( $sock->connected ) {
       MailScanner::Log::DebugLog("Clamd : Sending PING");
-      $sock->send("SESSION\n");
       $sock->send("PING\n");
       $PingTimeOut += time();
       $line = '';
 
-      while ($line eq '') {
+			while ($line eq ''){
         $line = <$sock>;
         # if we timeout then print error (if debugging) and exit with erro
         MailScanner::Log::WarnLog("ClamD Timed Out During PING " .
-                                  "Check!\n") if $PingTimeOut < time;
-        print "ERROR:: CLAM PING TIMED OUT! :: $dirname" if time > $PingTimeOut;
-        exit 1 if time > $PingTimeOut;
+					"Check!") if $PingTimeOut < time;
+				print "ERROR:: CLAM PING TIMED OUT! :: " .
+					"$dirname\n" if time > $PingTimeOut;
+				return 1 if time > $PingTimeOut;
         last if time > $PingTimeOut;
         chomp($line);
       }
 
       MailScanner::Log::DebugLog("Clamd : GOT '%s'",$line);
-      MailScanner::Log::WarnLog("ClamD Responded '%s' Instead of PONG during " .
-                                "PING Check, Recommend Restarting Daemon\n",
+			MailScanner::Log::WarnLog("ClamD Responded '%s' Instead of PONG " .
+				"During PING Check, Recommend Restarting Daemon",
                                 $line) if $line ne 'PONG';
       print "ERROR:: CLAMD DID NOT RESPOND PROPERLY TO PING! PLEASE " .
-            "RESTART DAEMON :: $dirname" unless $line eq "PONG";
-      close($sock) unless $line eq "PONG";
-      exit 1 unless $line eq "PONG";
+				"RESTART DAEMON :: $dirname\n" unless $line eq "PONG";
+			close($sock);
+			return 1 unless $line eq "PONG";
       MailScanner::Log::DebugLog("ClamD is running\n");
-      # ClamD will have closed the connection so we repopen it
-    } else {
-      MailScanner::Log::WarnLog("ClamD has an Unknown problem, recommend you re-start the daemon!\n");
+		}else{
+ 			MailScanner::Log::WarnLog("ClamD has an Unknown problem, recommend you re-start the daemon!");
       print "ERROR:: CLAMD HAS AN UNKOWN PROBLEM, RECOMMEND YOU " .
-            "RESTART THE DAEMON :: $dirname";
-      exit 1;
+			"RESTART THE DAEMON :: $dirname\n";
+			return 1;
     }
   }
 
-  if ($sock->connected) {
-    # Going to do this the same as Julian does the ClamAVModule
-    $dir   = new DirHandle;
-    $child = new DirHandle;
-    $dir->open($ScanDir)
-      or MailScanner::Log::DieLog("Can't open directory %s for scanning, %s",
-                                  "$dirname", $!);
-    # Find all the subdirectories
-    while($childname = $dir->read()) {
-      next unless -d "$ScanDir/$childname"; # Only search subdirs
-      next if $childname eq '.' || $childname eq '..';
+	# Attempt to reopen the connection to clamd
+	$sock = ConnectToClamd($TCP,$Socket,$Port, $TimeOut);
+	print "ERROR:: COULD NOT CONNECT TO CLAMD, RECOMMEND RESTARTING DAEMON " .
+		  ":: $dirname\n" unless $sock;
+	MailScanner::Log::WarnLog("ERROR:: COULD NOT CONNECT TO CLAMD, ".
+			"RECOMMEND RESTARTING DAEMON ") unless $sock;
+	return 1 unless $sock;
 
-      $child->open("$ScanDir/$childname") or
-        MailScanner::Log::DieLog("Can't open directory %s for scanning, %s",
-                                 "$ScanDir/$childname", $!);
+	if ( $sock->connected ) {
+	  # Going to Scan the entire batch at once, should really speed things
+	  # up especially on SMP hosts running mutli-threaded scaning
       $TimeOut += time();
-      while ($filename = $child->read()) {
-        next if $filename eq '.' || $filename eq '..';
-        next unless -f "$ScanDir/$childname/$filename"; # Only check files
-        $sock->send("$ScanType $ScanDir/$childname/$filename\n");
-        MailScanner::Log::DebugLog("SENT : $ScanType %s \n",
-                                   "$ScanDir/$childname/$filename");
 
+		$sock->send("$ScanType $ScanDir\n");
+		MailScanner::Log::DebugLog("SENT : $ScanType %s ", "$ScanDir");
         $results = '';
-        $results = <$sock>;
+		my $ResultString = '';
+
+		while($results = <$sock>){
         # if we timeout then print error and exit with error
-        MailScanner::Log::WarnLog("ClamD Timed Out!\n") if $TimeOut < time;
+			MailScanner::Log::WarnLog("ClamD Timed Out!") if $TimeOut < time;
         close($sock) if time > $TimeOut;
-        print "ERROR:: CLAM PING TIMED OUT! :: " .
-              "$dirname/$childname/$filename" if time > $TimeOut;
-        exit 1 if time > $TimeOut;
-        chomp($results);
+			print "ERROR:: CLAM TIMED OUT! :: " .
+				"$dirname\n" if time > $TimeOut;
+			return 1 if time > $TimeOut;
+			# Append this file to any others already found
+			$ResultString .= $results;
+		}
+
+		# Remove the trailing line feed and create an array of
+		# lines for sending to the parser
+		chomp($ResultString);
+		my @report = split("\n",$ResultString) ;
 
+		foreach $results(@report){
         # Pull the basedir out and change it to a dot for the parser
         $results =~ s/$ScanDir/\./;
+			$results =~ s/:\s/\//;
+
+			# If scanning full batch clamd returns OK on the directory
+			# name at the end of the scan so we discard that result when
+			# we get to it
+            next if $results =~ /^\.\/OK/;
+			my ($dot,$childname,$filename,$rest) = split('/',$results);
+
         unless ($results) {
-          print "ERROR:: $results" . ":: $dirname/$childname/$filename\n";
+    			print "ERROR:: $results :: $dirname/$childname/$filename\n";
           next;
         }
-        if ($results =~ /.+?:.+?\sFOUND$/) {
-          print "INFECTED:: $results" . ":: $dirname/$childname/$filename\n";
-        } elsif ($results =~ /^.+\sERROR$/) {
-          print "ERROR:: $results" . ":: $dirname/$childname/$filename\n";
+  			if ($rest =~ /.+?\sFOUND$/) {
+    			print "INFECTED::";
+    			print " $rest :: $dirname/$childname/$filename\n";
+			}elsif ($rest =~ /^.+\sERROR$/){
+				print "ERROR:: $rest :: $dirname/$childname/$filename\n";
           next;
         } else {
           print "CLEAN:: :: $dirname/$childname/$filename\n";
         }
-      } # Reading filenames
-      $child->close;
-    } # Reading $dir
-    $dir->close;
-    $sock->send("END\n");
+		}
+
     close($sock);
-  } else {
-    # Only way to get here is successfully opening the socket but not
-    # actually connecting to the daemon so there is something amiss and we
-    # leave
-    print "ERROR:: Unknown Clam Error Has Occured Suggest You Restart " .
-          "clamd :: $dirname\n";
-    MailScanner::Log::DebugLog("ClamD has an Unknown problem, recommend " .
-                               "you re-start the daemon!\n");
-    exit 1;
+	}else{
+		# We were able to open the socket but could not actually connect
+		# to the daemon so something odd is amiss and we send error to
+		# parser and log, then exit
+		print "ERROR:: UNKNOWN ERROR HAS OCCURED WITH CLAMD, SUGGEST YOU " .
+			"RESTART DAEMON :: $dirname\n";
+ 		MailScanner::Log::DebugLog("UNKNOWN ERROR HAS OCCURED WITH THE CLAMD " .
+				"DAEMON SUGGEST YOU RESTART CLAMD!");
+		return 1;
   }
 
 } # EO ClamdScan
 
+# This function just opens the connection to the clamd daemon
+# and returns either a valid resource or undef if the connection
+# fails
+sub ConnectToClamd{
+	my($TCP,$Socket,$Port, $TimeOut) = @_;
+	my $sock;
+	# Attempt to open the appropriate socket depending on the type (TCP/UNIX)
+	if ( $TCP){
+    	$sock = IO::Socket::INET->new( PeerAddr => $Socket,
+                                   	PeerPort => $Port,
+									Timeout => $TimeOut,
+                                   	Proto     => 'tcp');
+	}else{
+       	$sock = IO::Socket::UNIX->new( Timeout => $TimeOut,
+                                        	Peer => $Socket );
+
+	}
+	return undef unless $sock;
+	return $sock;
+}# EO ConnectToClamd
+
 1;
 
