#!/usr/ug/bin/perl5 # vim:fo=croql:cin:com=\:# # # killfiling gsubrc, mark II # jtr@ugcs.caltech.edu use strict; use POSIX qw(strftime setpgid); # is this really something I want to do? print "cannot become process group leader\n" if (!defined(setpgid(0,0))); # if this ain't a sign of good programming, then shit... # gale info use vars qw($CONTENT $PING $TO $FROM $ENC $CAT $SIGN $FTIME $TIME @MESSAGE $AGENT); # directories use vars qw($GALE $HOME $GALESTUN $GALELAST); # formatting use vars qw($BON $BOFF $CEOL $STOMP $BEEP $COLUMNS); # killinfo use vars qw(%score @nukes %gvars); if (-t 1) { $STOMP= "\r"; $BEEP= "\a"; $BON=`tput bold`; $BOFF=`tput sgr0`; $CEOL= `tput el`; $STOMP .= $CEOL; } $FROM= &envSet('GALE_TEXT_MESSAGE_SENDER', '*anonymous*'); $TO= &envSet('GALE_TEXT_MESSAGE_RECIPIENT', '*everyone*'); $TIME= &envSet('GALE_TIME_ID_TIME', 'never, never, no place, no time'); $FTIME= substr($TIME, 5); $FTIME= $TIME if (!defined($ENV{'GALE_TIME_ID_TIME'})); $AGENT= $ENV{'HEADER_AGENT'}; $PING= $ENV{'HEADER_RECEIPT_TO'}; $CAT= $ENV{'GALE_CATEGORY'}; $CAT =~ s-zephyr/message-zephyr/MESSAGE-gi; $ENC= $ENV{'GALE_ENCRYPTED'}; $SIGN= $ENV{'GALE_SIGNED'}; $CONTENT= $ENV{'HEADER_CONTENT_TYPE'}; $HOME= $ENV{'HOME'}; $GALE= $HOME . "/.gale/"; $GALESTUN= $HOME . "/.gale/stun"; $GALELAST= "$GALE/glast"; $COLUMNS= 80; $COLUMNS= $ENV{'COLUMNS'} if defined($ENV{'COLUMNS'}); # you did not see this. exit 0 if crypt("$ENC", "CL") eq "CLlLLBYXYwT/Y" && ($ENC ne $SIGN); @MESSAGE= <>; sub envSet { my($evar, $dflt)= @_; return $ENV{$evar} if defined($ENV{$evar}); return $dflt; } # # main handler # &logit; if ($CAT =~ m-^notice/-) { &printNotice(@MESSAGE); } elsif ($CAT =~ m-receipt$-) { &printReceipt(@MESSAGE); } else { &mkKillfile; my $res= &chkKill; if (!defined($ENC) && defined($gvars{'shutup'})) { exit 0; } if (defined($ENC) && defined($SIGN)) { &acquire("$GALE/lock-glast"); if (open(G, ">$GALELAST")) { print G $SIGN; } &release("$GALE/lock-glast"); } if ($res >= 0) { &printMessage(@MESSAGE); } else { &printKilledHeader($res); $gvars{'numkilled'}++; } &sweepKillfiles; } # # log information about recent messages # sub logit { } # # formatting # sub center { my($str, $bold)= @_; print "${STOMP}", ' ' x (40 - length($str) / 2); print $BON if ($bold); print $str; print $BOFF if ($bold); print "$CEOL\n"; } sub printKilledHeader { my($res)= @_; if ($gvars{'showkillshit'}) { my $name= $FROM; $name =~ s/ <.*>//; print "${STOMP}$res KILLED: [$BON$CAT$BOFF] from $BON$name$BOFF$CEOL\n"; print "${STOMP}\tencrypted: $BON$ENC$BOFF$CEOL\n" if defined($ENC); print "${STOMP}"; } } sub printNotice { print "${STOMP}$BON"; print "* $SIGN " if defined($SIGN); my $C= $CAT; $C =~ s-notice/[^/]*/[^/]*/([^/]*)-$1-; print "$C: "; print "$AGENT on "; print "$TIME$BOFF$CEOL\n${STOMP}"; } sub printReceipt { print "${STOMP}$BON"; print "* " if defined($SIGN); print "receipt: "; print "$AGENT at "; print "$TIME$BOFF$CEOL\n${STOMP}"; } sub printMessageFought { my($logf, @MESSAGE)= @_; print $logf $STOMP, "-" x ($COLUMNS-1), "\n"; &printHeaderFought($logf); &wrapBody($logf, @MESSAGE); &printFooterFought($logf); } sub wrapBody { my($logf, @MESSAGE)= @_; my $line; foreach $line (@MESSAGE) { if (length($line) > ($COLUMNS-1)) { my($word, $l)= ('', ''); ($l,$line)= ($line =~ /^(\s*)(.*)$/); foreach $word (split(/\s/, $line)) { if (length($word . ' ' . $l) > ($COLUMNS-1) || (length($word) > ($COLUMNS-1) && length($l) > 0)) { print $logf "$STOMP$l", "\n"; $l= $word; } else { $l .= ' ' if ($l !~ /^\s*$/); $l .= $word; } } print($logf "$STOMP$l\n") if length($l) > 0; } else { print $logf $STOMP, $line; } } } sub printMessage { my @MESSAGE= @_; if (defined($gvars{'foughtdisplay'})) { &printMessageFought(*STDOUT, @MESSAGE); } else { &printMessageMe(@MESSAGE); } } sub printMessageMe { my @MESSAGE= @_; &printHeaderMarkII(*STDOUT); &wrapBody(*STDOUT, @MESSAGE); if (defined($SIGN) || defined($ENC)) { my $enc= '-- '; $enc .= "signed: $SIGN" if defined($SIGN); $enc .= " / " if (defined($SIGN) && defined($ENC)); $enc .= "encrypted: $ENC" if defined($ENC); $enc .= ' --'; ¢er($enc, 1); } print "${BEEP}" if defined($ENC); print "${STOMP}$CEOL\n$CEOL${STOMP}"; } sub printHeader { my $name= $FROM; $name =~ s/ <.*>//; print "${STOMP}"; print "+" if defined($PING); print "[$BON$CAT$BOFF] from $BON$name$BOFF"; print "$TIME$CEOL\n"; } sub printHeaderFought { my($logf)= @_; my $name= $FROM; print $STOMP; print $logf "+" if defined($ENV{'HEADER_RECEIPT_TO'}); print $logf "[$BON$CAT$BOFF] from $BON$name$BOFF to $BON$TO$BOFF\n"; } sub printHeaderMarkII { my($logf)= @_; my $name= $FROM; $name =~ s/ <.*>//; print "${STOMP}"; print $logf "+" if defined($ENV{'HEADER_RECEIPT_TO'}); print $logf "[$BON$CAT$BOFF] from $BON$name$BOFF"; print $logf (" $FTIME$CEOL\n"); } sub printFooterFought { my ($logf)= @_; my $foot= "-- "; if (defined($SIGN)) { $foot .= "<$BON$SIGN$BOFF>"; } else { $foot .= "$BON*anonymous*$BOFF"; } $foot .= " for "; if (defined($ENC)) { $foot .= "<$BON$ENC$BOFF>"; } else { $foot .= "$BON*everyone*$BOFF"; } $foot .= " at $FTIME --\n"; print $logf ($STOMP . (" " x ($COLUMNS + length(($BON.$BOFF) x 2) - length($foot))) . $foot); } sub printFooterMarkII { my ($logf)= @_; if (defined($SIGN) || defined($ENC)) { my $enc= '-- '; $enc .= "signed: $SIGN" if defined($SIGN); $enc .= " / " if (defined($SIGN) && defined($ENC)); $enc .= "encrypted: $ENC" if defined($ENC); $enc .= ' --'; ¢er($logf, $enc); } } # Mark II killfile sub chkKill { my @catscore= (); my($f, $cat, $score); foreach $cat (split(/:/, $CAT)) { $gvars{'category'}= $cat; $score= 0; foreach $f (keys %score) { print "${STOMP}<<$f>>\n" if $gvars{'expandverbose'}; if (eval $f) { print "${STOMP}$f: " . $score{$f} . "\n${STOMP}" if $gvars{'scoreverbose'}; $score += $score{$f}; } } push @catscore, $score; } $score= &pickScore(@catscore); &nuke($score); return $score; } sub pickScore { my @catscore= @_; my($score, $f); if ($gvars{'xpost'} =~ /sum|avg/) { $score= 0; foreach $f (@catscore) { $score += $f; } $score /= ($#catscore + 1) if $gvars{'xpost'} =~ /avg/; } elsif ($gvars{'xpost'} =~ /max/) { $score= $catscore[0]; foreach $f (@catscore) { $score= $f if $f > $score; } } else { # minimum $score= $catscore[0]; foreach $f (@catscore) { $score= $f if $f < $score; } } return $score; } sub nuke { my($score)= @_; my($nk); foreach $nk (@nukes) { my($s, $e)= split(/\.\./, $nk->[0]); if ($s eq '' || $score >= $s) { if ($e eq '' || $score < $e) { my $newrule= $nk->[2]; $newrule =~ s:\^([a-z]+):$gvars{$1}:g; $newrule =~ s:\^([A-Z]+):$ENV{$1}:g; open(TF, ">$GALESTUN/" . time . "-$$:" . $nk->[1]) || die "can't plonk"; print TF $newrule, "\n"; close(TF); } } } } sub mkKillfile { &readKillfile("$GALE/gkill"); if (-d "$GALESTUN") { &acquire("$GALE/lock-stundir"); my $f; foreach $f (<$GALESTUN/*>) { # */ grr &readKillfile($f); } &release("$GALE/lock-stundir"); } else { mkdir($GALESTUN, 0755); } } sub sweepKillfiles { &acquire("$GALE/lock-stundir"); my $f; foreach $f (<$GALESTUN/*>) { # */ stooopid editor my $mtime= (stat($f))[9]; my $len= (split(/:/, $f))[1]; unlink($f) if (time > $mtime + $len); } &release("$GALE/lock-stundir"); } sub readKillfile { my($f)= @_; open(GKILL, $f) || return; while () { s/#.*$//; if (/^[+-]/) { &readScore($_); } elsif (/^\d*\.\.d*/) { &readNuke($_); } elsif (/^(\w*)\s*=\s*(.*)$/) { $gvars{$1}= $2; } else { # compatibility with Mk I killfile if (/^dipshit\s*([^\s]*)\s*([^\s]*)/) { my $target= $1; if ($2 =~ /kill/) { $score{" \$ENV{'GALE_SIGNED'} =~ /$target/"}= -50; } else { $score{" \$ENV{'GALE_SIGNED'} =~ /$target/"}= -100; push @nukes, ['..-99', 3600, '-50:category(^category)']; } } elsif (/^category\s*(.*)$/) { $score{" \$ENV{'GALE_CATEGORY'} =~ /$1/"}= -50; } elsif (/^polluted\s*([^\s*])/) { $score{" \$ENV{'GALE_CATEGORY'} =~ /$1/"}= -50; } else { my @a= split(/\s*/); $gvars{$a[0]}= $a[1]; } } } } sub readScore { my($cmdl)= @_; /^(.*):(.*)$/; my($score, $condition)= ($1, $2); $condition =~ s/\@/\\\@/g; $condition =~ s:([A-Z_]+)\(\):defined (\$ENV{'$1'}):g; $condition =~ s:([a-z_]+)\(\):defined (\$gvars{'$1'}):g; $condition =~ s:([A-Z_]+)\(([^)]+)\):(\$ENV{'$1'} =~ m!$2!):g; $condition =~ s:([a-z_]+)\(([^)]+)\):(\$gvars{'$1'} =~ m!$2!):g; $score{$condition}= $score; } sub readNuke { my($cmdl)= @_; /^([^:]*):([^:]*):(.*)$/; my($l, @a)= ($3, $1, $2); $l =~ s:\$([A-Z_]+):^$1:g; $l =~ s:\$([a-z_]+):^$1:g; push @a, $l; push @nukes, \@a; } # # mutexery # sub acquire { my($lockf)= @_; my $retries= 0; while (!mkdir($lockf, 0)) { die "error acquiring lock on $lockf: $!" if ($! ne "File exists"); $retries++; print("${STOMP}sleeping on lock $lockf: $!\n") if ($gvars{'lockverbose'} == 1 || $retries % 20 == 0); sleep(4); } } sub release { my($lockf)= @_; rmdir($lockf); }