#!/usr/bin/perl -w

# Source: @RPM_PACKAGE_VERSION@-@RPM_PACKAGE_RELEASE@

BEGIN { unshift(@INC,($ENV{'POPHOME'}||'@POPHOME@').'/lib')
			unless $ENV{'KUNDE_NO_PERLPATH'};
      }

use utf8;
use strict;
use warnings;
use Umlaut qw(textmodus);

use Cf qw($LOGHOST $MAILDOM);
use File::Basename 'basename';
use POSIX '_exit';
use Umlaut qw(binmodus);

use Time::ParseDate qw(parsedate);

sub unixtime($) {
	if ( ( my $date = shift ) =~ /^\d+\z/ ) { $date }
	else { parsedate( $date, PREFER_PAST => 1, WHOLE => 1 ) }
}

sub Usage() {
	my $vers = '@RPM_PACKAGE_VERSION@-@RPM_PACKAGE_RELEASE@';

	textmodus(\*STDERR);
    die <<END;
Usage: $0 -- sendet Logdateien
    [ -d XX ]       sendet an Host XX, Default: loghost.$MAILDOM
    [ -p XX ]       sendet an Port XX, Default: 'logstore'
    [ -m XX ]       Fehlermails gehen an XX, Default: log-failed\@$MAILDOM
    [ -l XX ]       Lock mit XX
    [ -o X=Y,... ]  sendet die Datei mit Option X=Y
    [ -f ]          schickt den Dateinamen als option file= mit
    [ -F ]          dito, vollständiger Pfad
    [ -t ]          schickt die Zeit der letzten Änderung als time= mit
    [ -T Datum ]    schickt 'Datum' als Zeit der letzten Änderung mit
    [ -s ]          schickt die aktuelle Dateigröße als size= mit
    [ -n ]          löscht die Datei nach erfolgter Übertragung _NICHT_.
    [ -b N ]        generiere N lokale Backupkopien
    [ -B N ]        generiere N gezippte lokale Backupkopien
    [ -z ]          setzt die Datei auf Null
    [ -u ]          keine Warnung wenn nicht vorhanden
    [ -U ]          ignoriere wenn leer
    Datei..         sendet genau diese Dateien

Sende die Dateien an eine Logger.

'-z' ist inkompatibel mit '-s' und '-n'.

Version: $vers
END
  _exit 1;
}

my $errmail;
use vars qw( $opt_h $opt_d $opt_p $opt_o $opt_l $opt_m $opt_F $opt_f $opt_T $opt_t $opt_s $opt_n $opt_z $opt_u $opt_U $opt_b $opt_B );
use Getopt::Std;

my $exit = 0;

BEGIN {
getopts("hd:p:m:l:o:fFtT:snzuUb:B:") or Usage;
$errmail = $opt_m || "autolog-failed\@$MAILDOM";
}
use File::ShLock;
use IO::Socket;
use Time::Local;

Usage if $opt_h;
Usage if @ARGV == 0;
Usage if ( $opt_n or $opt_s ) and $opt_z;
Usage if $opt_f and $opt_F;
Usage if $opt_b and $opt_B;
if($opt_b) {
	$opt_b = 0+$opt_b; 
	Usage unless $opt_b > 0;
}
if($opt_B) {
	$opt_B = 0+$opt_B; 
	Usage unless $opt_B > 0;
}

my $host = $opt_d || $LOGHOST || ($MAILDOM ? "loghost.$MAILDOM" : "loghost");
my $port = $opt_p || "logstore";
my $opt = "host ".qx(hostname); # mit LF am Ende
if(defined $opt_o) {
	$opt_o =~ s/,/\n/g;
	$opt_o =~ s/=/ /g;
	$opt .= $opt_o;
}
$opt =~ s/\n*$/\n\n/s;

## CODE ##

if($opt_l) {
    $opt_l = new File::ShLock($opt_l);
	exit 1 unless ref $opt_l;
}
$opt_T = unixtime($opt_T) || die "Falsche Zeitangabe '$opt_T'\n" if $opt_T;

main: foreach my $f(@ARGV) {
	if($f eq "-") {
		open(F,"<&STDIN");
	} else {
		unless(-f $f) {
			warn "Could not stat $f: $!\n" unless $opt_u;
			$exit++;
			next main;
		}
		next main if $opt_U and not -s $f;
		unless(open(F,$f)) {
			warn "Could not open $f: $!\n";
			$exit++;
			next main;
		}
	}
	binmodus(\*F);

	my $sock = new IO::Socket::INET(PeerAddr => $host, PeerPort => $port,
			Timeout => 20);
	unless(ref $sock) {
		warn "No socket to $host:$port: $!\n";
		close(F);
		$exit++;
		next main;
	}
	$sock->sockopt(SO_KEEPALIVE,1);
	binmodus($sock);

	$sock->print("file ".basename($f)."\n") if $opt_f and $f ne "-";
	$sock->print("file $f\n") if $opt_F and $f ne "-";
	$sock->print("time ".(stat($f))[9]."\n") if $opt_t and $f ne "-";
	$sock->print("time $opt_T\n") if $opt_T;
	$sock->print("size ".(stat($f))[7]."\n") if $opt_s and $f ne "-";
	$sock->print("$opt\n") or die "No socket write: $!\n";

	my ( $buf, $len, $out );
	open $out, ">$f.0" if $opt_b;
	open $out, "|gzip >$f.0" if $opt_B;
	binmodus($out);
	
	while($len=read(F,$buf,8192)) {
		$sock->write($buf,$len) or do { warn "Error writing $f: $!\n"; next main; };
		print $out $buf if $opt_b or $opt_B;
	}
	close($out) if $opt_b or $opt_B;

	shutdown($sock,1);
	my $sb = <$sock>;
	if(defined $sb and chop $sb and $sb ne "OK") { ## Fehler
		print STDERR "$sb\n";
		print STDERR while <$sock>;
		$exit++;
	} else {
		if($opt_b or $opt_B) {
			$opt_b = $opt_B if $opt_B;
			rename("$f.$opt_b","$f.".($opt_b+1)) while $opt_b-- > 0;
		}
	    1 while(<$sock>);
		close(F);
		if($f ne "-") {
			if($opt_z) {
				open(F,">$f") and close(F) or warn "Error truncating $f: $!\n";
			} elsif(not $opt_n) {
				unlink($f) or warn "Error unlinking $f: $!\n";
			}
		}
	}
	close $sock;
}
exit $exit;


=head1 Name

logclient -- sendet Dateien an einen Logserver

=head1 Zusammenfassung

    logclient
        [ -d XX ]       sendet an Host XX, Default: loghost.@MAILDOM@
        [ -p XX ]       sendet an Port XX, Default: logstore
        [ -m XX ]       Fehlermails gehen an XX, Default: log-failed@@MAILDOM@
        [ -l XX ]       Lock mit XX
        [ -o X=Y,... ]  sendet die Datei mit Option X=Y
        [ -f ]          schickt den Dateinamen als option file= mit
        [ -F ]          dito, vollständiger Pfad
        [ -t ]          schickt den Zeitpunkt der letzten Änderung
                        als option time= mit
        [ -T YYYY-MM-DD ] schickt das angegebene Dateum als option time= mit
        [ -s ]          schickt die Dateigröße als option size= mit
        [ -n ]          löscht die Datei nicht
        [ -u ]          keine Warnung wenn nicht vorhanden
        [ -b N ]        generiere N lokale Backupkopien
        [ -B N ]        generiere N gezippte lokale Backupkopien
        [ -U ]          ignoriere wenn leer
        Datei..         sendet genau diese Dateien

=head1 Beschreibung

Sende eine Datei an einen Logclient. Der 

=head2 Optionen

=over 4

=item C<-d I<Host>>

Sendet an diesen Host. Default: loghost@@MAILDOM@.

=item C<-p I<Port>>

Sendet an diesen Port. Default: logstore.

=item C<-m I<Mailaddr>>

Fehlermails gehen an I<Mailaddr>.

Default: autolog-failed@@MAILDOM@.

=item C<-l I<Lock>>

Sperrt den Logclient mit I<Lock> gegen Mehrfachausführung,
schickt Mail wenn gesperrt.

=item C<-o I<Option=Name>,...>

Sendet die angegebenen Optionen an den Logserver.

=item C<-f>

Sendet den Dateinamen (ohne Pfad) an den Logserver.

=item C<-F>

Sendet den Dateinamen (mit Pfad) an den Logserver.

=item C<-t>

Sendet den Zeitpunkt der lezten Änderung der Datei an den Logserver.

=item C<-T yyyy-mm-dd>

Sendet den angegebenen Zeitpunkt an den Logserver.

=item C<-s>

Sendet die aktuelle Dateigröße an den Logserver.

=item C<-n>

Normalerweise wird die Logdatei nach einer erfolgreichen Übertragung
gelöscht. Diese Option verhindert das.

=item C<-z>

Alternativ bewirkt diese Option das Zurücksetzen der Datei auf Größe Null.

Diese Option ist mit C<-n> und C<-s> inkompatibel.

=item -b N

generiere N Backupkopien, benannt I<Name>.1 bis I<Name>.N.

=item -b N

generiere N mit gzip komprimierte Backupkopien, benannt I<Name>.1 bis
I<Name>.N.

=item C<Datei> ...

Sendet die angegebenen Datei.

=back

=head1 Daten

Der Logclient greift auf folgende Datenbestände zu:

=head2 I</etc/pop.conf>

Konfigurationsvariablen C<LOGHOST> und C<MAILDOM>.
werden überschrieben.

=head1 ToDo

Das Ganze ist noch ziemlich nervig.

=cut

