#
# Sophos Anti Virus via Sophie
#

if ($sophie_sockname) {
    do_log(2,"Using Sophie");
    if ($child_task_count == 1) {
	socket(\*sophie_sock, AF_UNIX, SOCK_STREAM, 0)
	    or die "Can't create socket for Sophie: $!";
	connect(\*sophie_sock, pack_sockaddr_un $sophie_sockname)
	    or die "Can't connect to Sophie: $!";
    }
    my($chkdir) = "$TEMPDIR/parts/\n";

    $SIG{PIPE} = 'IGNORE';  # 'send' to broken pipe throws a signal
    my($retries) = 0;
    for (;;) {  # gracefully handle cases when Sophie child times out
	while (!defined(syswrite(\*sophie_sock, $chkdir, length($chkdir)))) {
	    my($err) = "$!"; my($errn) = 0+$!;
	    $retries++;
	    if ($errn != EPIPE && $errn != ENOTCONN) {
		die "syswrite to Sophie socket failed: $err";
	    } else {
		if ($retries > 2) { die "Too many retries to talk to Sophie" }
		if ($err =~ /^Broken pipe/i) {  # slow down a runaway loop
		    sleep(10 * ($retries-1))  if $retries > 1;
		}
		do_log( ($retries>1?0:1),
			"Re-connecting to Sophie, attempt #$retries");
		close(\*sophie_sock);  # and ignore status
		socket(\*sophie_sock, AF_UNIX, SOCK_STREAM, 0)
		    or die "Can't create socket for Sophie: $!";
		connect(\*sophie_sock, pack_sockaddr_un $sophie_sockname)
		    or die "Can't connect to Sophie: $!";
	    }
	}
	defined(sysread(\*sophie_sock, $output, 256))
	    or die "sysread from Sophie socket failed: $!";
	last  if $output ne '';
	do_log( ($retries>1?0:1),
	       "Failed to get response from Sophie, retrying ($retries)");
	sleep 10;
    }
    # LF-terminated, older Sophie filled the buffer with nulls;
    $output =~ s/[\000\r\n]+$//;
    # older Sophie didn't append colon and error text if $stat == -1
    if ($output !~ /^ ([-+]? \d*) (?: : (.*?) )? $/x) {
	do_log(0,"Virus scanner failure: can't parse Sophie output: <$output>");
    } else {
	my($stat,$rest) = ($1,$2);
	$rest = $1  if $rest =~ /^'(.*?)'$/;
	do_log(2,"Result from Sophie: $stat" . ($rest eq '' ? '' : ":$rest") );
	if ($stat == 1) {
	    @virusname = $rest;
	    $scanner_errors = 0;  # no errors, a virus was found
	    return 1;
	} elsif ($stat == 0) {
	    $scanner_errors = 0;  # no errors, no viruses
	} elsif ($stat == -1) {
	    do_log(0,"Virus scanner failure: Sophie - $stat:$rest");
	} else {
	    do_log(0,"Virus scanner failure: Sophie - OOOPS: <$output>");
	}
    }
}
