--- SweepViruses.pm	Mon Mar 31 17:16:25 2003
+++ SweepViruses.pm.new	Thu Apr  3 22:34:31 2003
@@ -757,9 +757,11 @@
 }
 
 # Initialise any state variables the F-Secure output parser uses
-my ($fsecure_InCruft);
+my ($fsecure_InHeader, $fsecure_Version, %fsecure_Seen);
 sub InitFSecureParser {
-  $fsecure_InCruft=(-1);
+  $fsecure_InHeader=(-1);
+  $fsecure_Version = 0;
+  %fsecure_Seen = ();
 }
 
 # Initialise any state variables the F-Prot output parser uses
@@ -1165,51 +1167,88 @@
   return 0;
 }
 
+# Sample output from version 4.50 of F-Secure:
+# [./eicar2/eicar.zip] eicar.com: Infected: EICAR-Test-File [AVP]
+# ./eicar2/eicar.co: Infected: EICAR_Test_File [F-Prot]
 sub ProcessFSecureOutput {
   my($line, $infections, $types, $BaseDir, $Name) = @_;
-  #my($line) = @_;
 
   my($report, $infected, $dot, $id, $part, @rest);
-  my($logout, $virus);
+  my($logout, $virus, $BeenSeen);
 
   chomp $line;
-
-  # Lose cruft
-  return 0 if $fsecure_InCruft > 0;
+  print STDERR "$line\n";
+  print STDERR "InHeader $fsecure_InHeader\n";
+  #system("echo -n '$line' | od -c");
+
+  # Lose header
+  if ($fsecure_InHeader < 0 && $line =~ /version ([\d.]+)/i) {
+    $fsecure_Version = $1 + 0.0;
+    #MailScanner::Log::InfoLog("Found F-Secure version $1=$fsecure_Version\n");
+    return 0;
+  }
   if ($line eq "") {
-    $fsecure_InCruft += 1;
+    $fsecure_InHeader++;
     return 0;
   }
-  $fsecure_InCruft == 0 or return 0;
+  $fsecure_InHeader == 0 or return 0;
 
-  # Prefer s/// to m// as less likely to do unpredictable things.
-  # We hope.
-  if ($line =~ /\tinfection:\s/) {
-    $report = $line;
-    $logout = $line;
-    $logout =~ s/%/%%/g;
-    MailScanner::Log::InfoLog($logout);
-    # Get to relevant filename in a reasonably but not
-    # totally robust manner (*impossible* to be totally robust
-    # if we have square brackets and spaces in filenames)
-    # Strip archive bits if present
-    $line =~ s/^\[(.*?)\] .+(\tinfection:.*)/$1$2/;
-
-    # Get to the meat or die trying...
-    $line =~ s/\tinfection:([^:]*).*$//
-      or MailScanner::Log::DieLog("Dodgy things going on in F-Secure output:\n$report\n");
-    $virus = $1;
-    $virus =~ s/^\s*(\S+).*$/$1/; # 1st word after Infection: is the virus
-    MailScanner::Log::InfoLog("Virus Scanning: F-Secure found virus %s",$virus);
+  $report = $line;
+  $logout = $line;
+  $logout =~ s/%/%%/g;
+  MailScanner::Log::InfoLog($logout);
 
+  # If we are running the new version then there's a totally new parser here
+  if ($fsecure_Version >= 4.50) {
+
+    #./g4UFLJR23090/Keld Jrn Simonsen: Infected: EICAR_Test_File [F-Prot]
+    #./g4UFLJR23090/Keld Jrn Simonsen: Infected: EICAR-Test-File [AVP]
+    #./g4UFLJR23090/cokegift.exe: Infected:   is a joke program [F-Prot]
+
+    return 0 unless $line =~ /: Infected: /;
+    # The last 3 words are "Infected:" + name of virus + name of scanner
+    $line =~ s/: Infected: +(.+) \[.*?\]$//;
+    #print STDERR "Line is \"$line\"\n";
+    MailScanner::Log::InfoLog("Virus Scanning: F-Secure found virus %s", $1);
+    # We are now left with the filename, or
+    # then archive name followed by the filename within the archive.
+    $line =~ s/^\[(.*?)\] .*$/$1/; # Strip signs of an archive
+
+    # We now just have the filename
     ($dot,$id,$part,@rest) = split(/\//, $line);
     $report = $Name . ': ' . $report if $Name;
     $infections->{"$id"}{"$part"} .= $report . "\n";
     $types->{"$id"}{"$part"} .= "v"; # so we know what to tell sender
+    # Only report results once for each file
+    return 0 if $fsecure_Seen{$line};
+    $fsecure_Seen{$line} = 1;
     return 1;
+  } else {
+    # We are running the old version, so use the old parser
+    # Prefer s/// to m// as less likely to do unpredictable things.
+    # We hope.
+    if ($line =~ /\tinfection:\s/) {
+      # Get to relevant filename in a reasonably but not
+      # totally robust manner (*impossible* to be totally robust
+      # if we have square brackets and spaces in filenames)
+      # Strip archive bits if present
+      $line =~ s/^\[(.*?)\] .+(\tinfection:.*)/$1$2/;
+  
+      # Get to the meat or die trying...
+      $line =~ s/\tinfection:([^:]*).*$//
+        or MailScanner::Log::DieLog("Dodgy things going on in F-Secure output:\n$report\n");
+      $virus = $1;
+      $virus =~ s/^\s*(\S+).*$/$1/; # 1st word after Infection: is the virus
+      MailScanner::Log::InfoLog("Virus Scanning: F-Secure found virus %s",$virus);
+  
+      ($dot,$id,$part,@rest) = split(/\//, $line);
+      $report = $Name . ': ' . $report if $Name;
+      $infections->{"$id"}{"$part"} .= $report . "\n";
+      $types->{"$id"}{"$part"} .= "v"; # so we know what to tell sender
+      return 1;
+    }
+    MailScanner::Log::DieLog("Either you've found a bug in MailScanner's F-Secure output parser, or F-Secure's output format has changed! Please mail the author of MailScanner!\n");
   }
-
-  MailScanner::Log::DieLog("Either you've found a bug in MailScanner's F-Secure output parser, or F-Secure's output format has changed! Please mail the author of MailScanner!\n");
 }
 
 sub ProcessFProtOutput {