Initial revision
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
Данный скрипт предназначен для генерации статистики о работе мейлера
|
||||
binkleyforce путём анализа создаваемого им файла истории сессий (параметр
|
||||
`history_file' в bforce.conf). Статистика генерится за предыдущие сутки от
|
||||
момента запуска скрипта и постится в заданную ньюсгруппу. Доступны два типа
|
||||
статистики.
|
||||
|
||||
Перед первым запуском рекомендуется изменить значение конфигурационных
|
||||
переменных -- они находятся в начале скрипта.
|
||||
|
||||
Известные баги:
|
||||
|
||||
1. Hе учитывается случай, когда файл истории сессий повёрнут
|
||||
logrotate'ом (может потеряться часть статистики)
|
||||
2. Hеправильно считает cps (завышает), если трафик в обе стороны
|
||||
|
||||
Автор скрипта: Serge N. Pokhodyaev, 2:5020/1838, <snp@ru.ru>
|
||||
|
||||
Распространяется под GNU GPL.
|
||||
|
||||
@@ -0,0 +1,575 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
#
|
||||
# bfha -- binkleyforce history analyzer
|
||||
#
|
||||
# Copyright (C) 2000 Serge N. Pokhodyaev
|
||||
#
|
||||
# E-mail: snp@ru.ru
|
||||
# Fido: 2:5020/1838
|
||||
#
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
#
|
||||
# çÅÎÅÒÉÔ ÓÔÁÔÉÓÔÉËÕ ÚÁ ÐÒÅÄÙÄÕÝÉÊ ÄÅÎØ
|
||||
#
|
||||
|
||||
#
|
||||
# TODO:
|
||||
#
|
||||
# 1. õÞÅÓÔØ ÓÌÕÞÁÊ, ËÏÇÄÁ ÌÏÇ ÐÏ×£ÒÎÕÔ logrotate'ÏÍ
|
||||
#
|
||||
# Known bugs:
|
||||
#
|
||||
# 1. HÅÐÒÁ×ÉÌØÎÏ ÓÞÉÔÁÅÔ cps (ÚÁ×ÙÛÁÅÔ) ÅÓÌÉ ÔÒÁÆÉË × ÏÂÅ ÓÔÏÒÏÎÙ
|
||||
#
|
||||
|
||||
use strict;
|
||||
use Time::Local;
|
||||
use POSIX qw(strftime);
|
||||
|
||||
my $PROGNAME = 'bfha';
|
||||
my $VERSION = '$Revision$ ';
|
||||
|
||||
######## Configurable part ###################################################
|
||||
|
||||
my $inews = "/usr/bin/inews -h -O -S";
|
||||
|
||||
my $log = "/var/spool/fido/history";
|
||||
|
||||
my $rep_newsgroups = "ftn.1838.stat";
|
||||
my $rep_from = "\"Statistics generator\" <snp\@gloom.intra.eu.org>";
|
||||
my $rep1_subj = "Sessions history";
|
||||
my $rep2_subj = "Sessions history";
|
||||
my $rep3_subj = "Links statistics";
|
||||
|
||||
my $count_failed = 1;
|
||||
|
||||
#my %line_names = (
|
||||
# "ttyS1" => "Modem",
|
||||
# "tcpip" => "IP"
|
||||
#);
|
||||
|
||||
##############################################################################
|
||||
|
||||
my $devel = 0;
|
||||
|
||||
my (%st, %lines, %nodes, @nodes_sorted);
|
||||
my @tm;
|
||||
my $time;
|
||||
|
||||
die "Usage: $PROGNAME [-d]\n" if (!((0 == $#ARGV) && ($ARGV[0] eq '-d')) && !(-1 == $#ARGV));
|
||||
$devel = 1 if ((0 == $#ARGV) && ($ARGV[0] eq '-d'));
|
||||
|
||||
$log = "./history" if ($devel);
|
||||
|
||||
# Make version string
|
||||
#
|
||||
$VERSION =~ s/(\$Rev)ision:\s([\d.]+).*/$PROGNAME\/$2/;
|
||||
|
||||
# Get time of 0:00:00 of yesterday
|
||||
#
|
||||
@tm = localtime(time - 86400);
|
||||
$tm[0] = 0; # sec
|
||||
$tm[1] = 0; # min
|
||||
$tm[2] = 0; # hours
|
||||
$time = timelocal(@tm);
|
||||
|
||||
# At first read logs
|
||||
#
|
||||
undef %st;
|
||||
undef %lines;
|
||||
undef %nodes;
|
||||
die "Log reading error\n" if (0 != log_read($time));
|
||||
|
||||
@nodes_sorted = sort(node_cmp keys(%nodes));
|
||||
|
||||
# Now generate statistics
|
||||
#
|
||||
out_close();
|
||||
#rep1();
|
||||
rep2();
|
||||
rep3();
|
||||
|
||||
|
||||
sub log_read
|
||||
{
|
||||
my $i;
|
||||
my $t;
|
||||
my @l;
|
||||
|
||||
die if (0 != $#_);
|
||||
|
||||
$t = $_[0];
|
||||
|
||||
open(LOG, "< $log") || die("Can't open $log: $!\n");
|
||||
while (<LOG>)
|
||||
{
|
||||
chomp;
|
||||
@l = split(/,/);
|
||||
return 1 if ($#l != 11);
|
||||
return 1 if (! ($l[4] =~ /[IO]/));
|
||||
|
||||
# Check date
|
||||
#
|
||||
next if ($l[2] < $t);
|
||||
last if ($l[2] >= ($t + 86400));
|
||||
|
||||
# Entries without address
|
||||
#
|
||||
if ($l[1] eq '')
|
||||
{
|
||||
next if (0 == $count_failed);
|
||||
$l[1] = 'failed' if (0 != $count_failed);
|
||||
}
|
||||
|
||||
# Remove domain
|
||||
#
|
||||
$l[1] =~ s/@.*$//;
|
||||
|
||||
# Add statistics
|
||||
#
|
||||
$i = $#{$st{beg}} + 1;
|
||||
|
||||
$lines{$l[0]}[$#{$lines{$l[0]}} + 1] = $i;
|
||||
$nodes{$l[1]}[$#{$nodes{$l[1]}} + 1] = $i;
|
||||
|
||||
$st{beg}[$i] = $l[2];
|
||||
$st{len}[$i] = $l[3];
|
||||
$st{addr}[$i] = $l[1];
|
||||
$st{line}[$i] = $l[0];
|
||||
$st{rc}[$i] = $l[5];
|
||||
$st{snt_nm}[$i] = $l[6];
|
||||
$st{snt_am}[$i] = $l[7];
|
||||
$st{snt_f}[$i] = $l[8];
|
||||
$st{rcv_nm}[$i] = $l[9];
|
||||
$st{rcv_am}[$i] = $l[10];
|
||||
$st{rcv_f}[$i] = $l[11];
|
||||
$st{islst}[$i] = 0;
|
||||
$st{islst}[$i] = 1 if ($l[4] =~ /L/);
|
||||
$st{isprot}[$i] = 0;
|
||||
$st{isprot}[$i] = 1 if ($l[4] =~ /P/);
|
||||
$st{type}[$i] = 'I' if ($l[4] =~ /I/);
|
||||
$st{type}[$i] = 'O' if ($l[4] =~ /O/);
|
||||
}
|
||||
}
|
||||
|
||||
######## rep1 ################################################################
|
||||
|
||||
sub rep1
|
||||
{
|
||||
my ($i, $j);
|
||||
my (%se, %se_t);
|
||||
my $node;
|
||||
|
||||
out_open($rep1_subj);
|
||||
printf "Date: %s\n\n", strftime("%a, %e %b %Y", localtime($time));
|
||||
|
||||
$~ = "rep1_header";
|
||||
write;
|
||||
|
||||
$~ = "rep1_body";
|
||||
$se_t{num_in} = 0;
|
||||
$se_t{num_out} = 0;
|
||||
$se_t{snt} = 0;
|
||||
$se_t{rcv} = 0;
|
||||
$se_t{len} = 0;
|
||||
foreach $node (@nodes_sorted)
|
||||
{
|
||||
$se{num_in} = 0;
|
||||
$se{num_out} = 0;
|
||||
$se{snt} = 0;
|
||||
$se{rcv} = 0;
|
||||
$se{len} = 0;
|
||||
for ($i = 0; $i <= $#{$nodes{$node}}; ++$i)
|
||||
{
|
||||
$j = $nodes{$node}[$i];
|
||||
++$se{num_in} if ($st{type}[$j] eq 'I');
|
||||
++$se{num_out} if ($st{type}[$j] eq 'O');
|
||||
$se{snt} += $st{snt_am}[$j] + $st{snt_nm}[$j] + $st{snt_f}[$j];
|
||||
$se{rcv} += $st{rcv_am}[$j] + $st{rcv_nm}[$j] + $st{rcv_f}[$j];
|
||||
$se{len} += $st{len}[$j];
|
||||
}
|
||||
$se{time} = time_int2str($se{len});
|
||||
# FIXME (cps)
|
||||
$se{cps} = div_int(($se{snt} + $se{rcv}), $se{len});
|
||||
write;
|
||||
|
||||
$se_t{num_in} += $se{num_in};
|
||||
$se_t{num_out} += $se{num_out};
|
||||
$se_t{snt} += $se{snt};
|
||||
$se_t{rcv} += $se{rcv};
|
||||
$se_t{len} += $se{len};
|
||||
}
|
||||
|
||||
$~ = "rep1_footer";
|
||||
$se_t{time} = time_int2str($se_t{len});
|
||||
# FIXME (cps)
|
||||
$se_t{cps} = div_int(($se_t{snt} + $se_t{rcv}), $se_t{len});
|
||||
write;
|
||||
|
||||
print "\n";
|
||||
out_close();
|
||||
|
||||
|
||||
format rep1_header =
|
||||
¥ ¶ ¶ ¶ ¶ ¶ ¨
|
||||
¡ System � Sessions � Sent � Received � Time � CPS ¡
|
||||
¡ address � in out � bytes � bytes � online � ¡
|
||||
± ¼ ¼ ¼ ¼ ¼ µ
|
||||
.
|
||||
|
||||
format rep1_body =
|
||||
¡ @<<<<<<<<<<<<<< � @>> @>> � @>>>>>>>> � @>>>>>>>>> � @>>>>>>>> � @>>>> ¡
|
||||
$node, $se{num_in}, $se{num_out}, $se{snt}, $se{rcv}, $se{time}, $se{cps}
|
||||
.
|
||||
|
||||
format rep1_footer =
|
||||
°€€€€€€€€€€€€€€€€€Š€€€€€€€€€€Š€€€€€€€€€€€Š€€€€€€€€€€€€Š€€€€€€€€€€€Š€€€€€€€´
|
||||
¡ TOTAL � @>> @>> � @>>>>>>>> � @>>>>>>>>> � @>>>>>>>> � @>>>> ¡
|
||||
$se_t{num_in}, $se_t{num_out}, $se_t{snt}, $se_t{rcv}, $se_t{time}, $se_t{cps}
|
||||
« ¹ ¹ ¹ ¹ ¹ ®
|
||||
.
|
||||
}
|
||||
|
||||
######## rep2 ################################################################
|
||||
|
||||
sub rep2
|
||||
{
|
||||
my ($i, $j);
|
||||
my @t;
|
||||
my ($t1, $t2, $str, $lv);
|
||||
my $node;
|
||||
my %se;
|
||||
|
||||
out_open($rep2_subj);
|
||||
printf "Date: %s\n\n", strftime("%a, %e %b %Y", localtime($time));
|
||||
|
||||
$~ = "rep2_header";
|
||||
write;
|
||||
|
||||
$~ = "rep2_body";
|
||||
foreach $node (@nodes_sorted)
|
||||
{
|
||||
$se{snt} = 0;
|
||||
$se{rcv} = 0;
|
||||
$se{len} = 0;
|
||||
for ($i = 0; $i <= 95; ++$i)
|
||||
{
|
||||
$t[$i] = 0;
|
||||
}
|
||||
for ($i = 0; $i <= $#{$nodes{$node}}; ++$i)
|
||||
{
|
||||
$j = $nodes{$node}[$i];
|
||||
|
||||
# Fill array
|
||||
#
|
||||
$t1 = $st{beg}[$j] - $time;
|
||||
$t2 = $t1 + $st{len}[$j];
|
||||
$t2 = 86399 if ($t2 > 86399);
|
||||
$t1 = div_int($t1, 900);
|
||||
$t2 = div_int($t2, 900);
|
||||
while ($t1 <= $t2)
|
||||
{
|
||||
$t[$t1++] = 1;
|
||||
}
|
||||
|
||||
$se{snt} += $st{snt_am}[$j] + $st{snt_nm}[$j] + $st{snt_f}[$j];
|
||||
$se{rcv} += $st{rcv_am}[$j] + $st{rcv_nm}[$j] + $st{rcv_f}[$j];
|
||||
$se{len} += $st{len}[$j];
|
||||
}
|
||||
$se{time} = time_int2str($se{len});
|
||||
# FIXME (cps)
|
||||
$se{cps} = div_int(($se{snt} + $se{rcv}), $se{len});
|
||||
|
||||
# Visualize
|
||||
#
|
||||
$i = 0;
|
||||
$str = "";
|
||||
if ($t[$i++])
|
||||
{
|
||||
$str = $str . "�";
|
||||
}
|
||||
else
|
||||
{
|
||||
$str = $str . "�";
|
||||
}
|
||||
while ($i < $#t)
|
||||
{
|
||||
$lv = 0;
|
||||
$lv += 1 if ($t[$i++]);
|
||||
$lv += 2 if ($t[$i++]);
|
||||
|
||||
if (0 == $lv)
|
||||
{
|
||||
if (div_rest(($i - 1), 8) == 0)
|
||||
{
|
||||
$str = $str . "�";
|
||||
}
|
||||
else
|
||||
{
|
||||
$str = $str . " ";
|
||||
}
|
||||
}
|
||||
elsif (1 == $lv)
|
||||
{
|
||||
$str = $str . "Ž";
|
||||
}
|
||||
elsif (2 == $lv)
|
||||
{
|
||||
$str = $str . "�";
|
||||
}
|
||||
elsif (3 == $lv)
|
||||
{
|
||||
$str = $str . "�";
|
||||
}
|
||||
}
|
||||
if ($t[$i])
|
||||
{
|
||||
$str = $str . "Ž";
|
||||
}
|
||||
else
|
||||
{
|
||||
$str = $str . "�";
|
||||
}
|
||||
|
||||
write;
|
||||
}
|
||||
|
||||
$~ = "rep2_footer";
|
||||
write;
|
||||
|
||||
out_close();
|
||||
|
||||
|
||||
format rep2_header =
|
||||
0 2 4 6 8 10 12 14 16 18 20 22 24
|
||||
†€‰€Š€‰€Š€‰€Š€‰€Š€‰€Š€‰€Š€‰€Š€‰€Š€‰€Š€‰€Š€‰€Š€‰€‡
|
||||
.
|
||||
|
||||
format rep2_body =
|
||||
@<<<<<<<<<<<<<<@||||||||||||||||||||||||||||||||||||||||||||||||
|
||||
$node, $str
|
||||
.
|
||||
|
||||
format rep2_footer =
|
||||
†€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€‡
|
||||
0 2 4 6 8 10 12 14 16 18 20 22 24
|
||||
.
|
||||
}
|
||||
|
||||
######## rep3 ################################################################
|
||||
|
||||
sub rep3
|
||||
{
|
||||
my $node;
|
||||
my (%se, %se_t);
|
||||
my ($i, $j);
|
||||
|
||||
out_open($rep3_subj);
|
||||
printf "Date: %s\n\n", strftime("%a, %e %b %Y", localtime($time));
|
||||
|
||||
$~ = "rep3_header";
|
||||
write;
|
||||
|
||||
$~ = "rep3_body";
|
||||
$se_t{num_in} = 0;
|
||||
$se_t{num_out} = 0;
|
||||
$se_t{time_in} = 0;
|
||||
$se_t{time_out} = 0;
|
||||
$se_t{snt} = 0;
|
||||
$se_t{rcv} = 0;
|
||||
$se_t{time} = 0;
|
||||
foreach $node (@nodes_sorted)
|
||||
{
|
||||
$se{num_in} = 0;
|
||||
$se{num_out} = 0;
|
||||
$se{time_in} = 0;
|
||||
$se{time_out} = 0;
|
||||
$se{snt} = 0;
|
||||
$se{rcv} = 0;
|
||||
$se{time} = 0;
|
||||
for ($i = 0; $i <= $#{$nodes{$node}}; ++$i)
|
||||
{
|
||||
$j = $nodes{$node}[$i];
|
||||
++$se{num_in} if ($st{type}[$j] eq 'I');
|
||||
++$se{num_out} if ($st{type}[$j] eq 'O');
|
||||
$se{time_in} += $st{len}[$j] if ($st{type}[$j] eq 'I');
|
||||
$se{time_out} += $st{len}[$j] if ($st{type}[$j] eq 'O');
|
||||
$se{snt} += $st{snt_am}[$j] + $st{snt_nm}[$j] + $st{snt_f}[$j];
|
||||
$se{rcv} += $st{rcv_am}[$j] + $st{rcv_nm}[$j] + $st{rcv_f}[$j];
|
||||
$se{time} += $st{len}[$j];
|
||||
}
|
||||
|
||||
# Total counters
|
||||
#
|
||||
$se_t{num_in} += $se{num_in};
|
||||
$se_t{num_out} += $se{num_out};
|
||||
$se_t{snt} += $se{snt};
|
||||
$se_t{rcv} += $se{rcv};
|
||||
$se_t{time} += $se{time};
|
||||
$se_t{time_out} += $se{time_out};
|
||||
$se_t{time_in} += $se{time_in};
|
||||
|
||||
# Output string
|
||||
#
|
||||
# FIXME (cps)
|
||||
$se{cps} = dash_if_zero(div_int(($se{snt} + $se{rcv}), $se{time}));
|
||||
$se{time} = time_int2str($se{time});
|
||||
$se{time_in} = time_int2str($se{time_in});
|
||||
$se{time_out} = time_int2str($se{time_out});
|
||||
$se{num_in} = dash_if_zero($se{num_in});
|
||||
$se{num_out} = dash_if_zero($se{num_out});
|
||||
$se{rcv} = shrink_size(dash_if_zero($se{rcv}));
|
||||
$se{snt} = shrink_size(dash_if_zero($se{snt}));
|
||||
write;
|
||||
}
|
||||
|
||||
$~ = "rep3_footer";
|
||||
# FIXME (cps)
|
||||
$se_t{cps} = dash_if_zero(div_int(($se_t{snt} + $se_t{rcv}), $se_t{time}));
|
||||
$se_t{time} = time_int2str($se_t{time});
|
||||
$se_t{time_in} = time_int2str($se_t{time_in});
|
||||
$se_t{time_out} = time_int2str($se_t{time_out});
|
||||
$se_t{num_in} = dash_if_zero($se_t{num_in});
|
||||
$se_t{num_out} = dash_if_zero($se_t{num_out});
|
||||
$se_t{rcv} = shrink_size(dash_if_zero($se_t{rcv}));
|
||||
$se_t{snt} = shrink_size(dash_if_zero($se_t{snt}));
|
||||
$~ = "rep3_footer";
|
||||
write;
|
||||
|
||||
print "\n";
|
||||
out_close();
|
||||
|
||||
|
||||
format rep3_header =
|
||||
¥ ¸ ¸ ¸ ¸ ¨
|
||||
¡ ¡ Sessions/Online ¡ Time ¡ Traffic ¡ ¡
|
||||
¡ Address ± ¸ µ online ± ¸ µ CPS ¡
|
||||
¡ ¡ Incoming ¡ Outgoing ¡ ¡ Rcvd ¡ Sent ¡ ¡
|
||||
± ¾ ¶ ¾ ¶ ¾ ¾ ¾ ¾ µ
|
||||
.
|
||||
|
||||
format rep3_body =
|
||||
¡ @<<<<<<<<<<<<<<¡@>>�@>>>>>>> ¡@>>�@>>>>>>> ¡@>>>>>>>> ¡@>>>>>¡@>>>>>¡@>>>>> ¡
|
||||
$node, $se{num_in}, $se{time_in}, $se{num_out}, $se{time_out}, $se{time}, $se{rcv}, $se{snt}, $se{cps}
|
||||
.
|
||||
|
||||
format rep3_footer =
|
||||
°€€€€€€€€€€€€€€€€½€€€Š€€€€€€€€€½€€€Š€€€€€€€€€½€€€€€€€€€€½€€€€€€½€€€€€€½€€€€€€€´
|
||||
¡ TOTAL ¡@>>�@>>>>>>> ¡@>>�@>>>>>>> ¡@>>>>>>>> ¡@>>>>>¡@>>>>>¡@>>>>> ¡
|
||||
$se_t{num_in}, $se_t{time_in}, $se_t{num_out}, $se_t{time_out}, $se_t{time}, $se_t{rcv}, $se_t{snt}, $se_t{cps}
|
||||
« » ¹ » ¹ » » » » ®
|
||||
.
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
|
||||
sub shrink_size
|
||||
{
|
||||
die if (0 != $#_);
|
||||
|
||||
return $_[0] if ($_[0] < 1024);
|
||||
return sprintf("%.1fk", $_[0] / 1024) if ($_[0] < 1048576);
|
||||
return sprintf("%.1fM", $_[0] / 1048576);
|
||||
}
|
||||
|
||||
sub dash_if_zero
|
||||
{
|
||||
die if (0 != $#_);
|
||||
|
||||
return "-" if (0 == $_[0]);
|
||||
return $_[0];
|
||||
}
|
||||
|
||||
sub time_int2str
|
||||
{
|
||||
my $time;
|
||||
my $h;
|
||||
my $m;
|
||||
my $s;
|
||||
|
||||
die if (0 != $#_);
|
||||
die if (86399 < $time);
|
||||
|
||||
return "-:--:--" if (0 == $_[0]);
|
||||
|
||||
$time = $_[0];
|
||||
$h = div_int($time, 3600);
|
||||
$time = div_rest($time, 3600);
|
||||
$m = div_int($time, 60);
|
||||
$s = div_rest($time, 60);
|
||||
|
||||
return sprintf("%d:%2.2d:%2.2d", $h, $m, $s);
|
||||
}
|
||||
|
||||
# ãÅÌÏÞÉÓÌÅÎÎÏÅ ÄÅÌÅÎÉÅ
|
||||
sub div_int
|
||||
{
|
||||
use integer;
|
||||
|
||||
die if (1 != $#_);
|
||||
|
||||
return 0 if ($_[1] == 0);
|
||||
return $_[0] / $_[1];
|
||||
}
|
||||
|
||||
|
||||
# ïÓÔÁÔÏË ÏÔ ÃÅÌÏÞÉÓÌÅÎÎÏÇÏ ÄÅÌÅÎÉÑ
|
||||
sub div_rest
|
||||
{
|
||||
die if (1 != $#_);
|
||||
|
||||
return 0 if ($_[1] == 0);
|
||||
return $_[0] - (div_int($_[0], $_[1]) * $_[1]);
|
||||
}
|
||||
|
||||
sub out_open
|
||||
{
|
||||
die if (0 != $#_);
|
||||
|
||||
open(STDOUT, "| $inews") || die("Can't pipe to inews: $!\n") if (! $devel);
|
||||
printf "Newsgroups: %s\n", $rep_newsgroups;
|
||||
printf "From: %s\n", $rep_from;
|
||||
printf "Subject: %s\n", $_[0];
|
||||
printf "X-FTN-Tearline: %s\n\n", $VERSION;
|
||||
}
|
||||
|
||||
sub out_close
|
||||
{
|
||||
close(STDOUT) if (! $devel);
|
||||
}
|
||||
|
||||
sub node_cmp
|
||||
{
|
||||
my (@na, @nb);
|
||||
|
||||
@na = split('[:/.]', $::a);
|
||||
@nb = split('[:/.]', $::b);
|
||||
|
||||
# zone
|
||||
return -1 if ($na[0] < $nb[0]);
|
||||
return 1 if ($na[0] > $nb[0]);
|
||||
|
||||
# net
|
||||
return -1 if ($na[1] < $nb[1]);
|
||||
return 1 if ($na[1] > $nb[1]);
|
||||
|
||||
# node
|
||||
return -1 if ($na[2] < $nb[2]);
|
||||
return 1 if ($na[2] > $nb[2]);
|
||||
|
||||
#point
|
||||
return -1 if ($na[3] < $nb[3]);
|
||||
return 1 if ($na[3] > $nb[3]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+384
@@ -0,0 +1,384 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# It is a log file analyser for 'binkleyforce' mailer.
|
||||
#
|
||||
# Copyright (c) 1998-99 by Alexander Belkin
|
||||
#
|
||||
# $Id$:
|
||||
#
|
||||
# If you have any questions, suggestions or wishes, feel free to contact
|
||||
# with me. My address: 2:5020/1398.11@fidonet
|
||||
#
|
||||
# To post into news, use bflan |inews -h -O -S
|
||||
$program_name = "bforce-lan v1.0/Perl/Linux";
|
||||
$station_name = "My Station";
|
||||
$log_file = "/var/log/bforce/bf-log.ttyS0";
|
||||
$news_header = "From: Statistic Robot <postmaster\@fido.xxx.local>\n".
|
||||
"Newsgroups: junk\n".
|
||||
"Subject: Sessions statistic.\n";
|
||||
|
||||
#main
|
||||
#{
|
||||
if( &ReadLog($log_file) == 0 )
|
||||
{
|
||||
print $news_header;
|
||||
print "\n";
|
||||
print "\"$system_name\" statistic from <$TimeFirst> to <$TimeLast>\n";
|
||||
print "\n";
|
||||
&TotalStatistic();
|
||||
print "\n";
|
||||
&SessionsStatistic();
|
||||
}
|
||||
exit(0);
|
||||
#}
|
||||
|
||||
sub ReadLog
|
||||
{
|
||||
my($start);
|
||||
|
||||
if( open( FLOG, $_[0] ) == 0 )
|
||||
{
|
||||
print "Can't open log \"$_[0]\": $!\n";
|
||||
return 1;
|
||||
}
|
||||
$start = 0;
|
||||
$cnt = 0;
|
||||
$TimeFirst = "";
|
||||
$TimeLast = "";
|
||||
|
||||
# Read in information from logfile
|
||||
|
||||
while( <FLOG> )
|
||||
{
|
||||
chomp;
|
||||
|
||||
( $Mon, $Day, $Time, $Pid, $Text ) = split( /[ \t]+/, $_, 5 );
|
||||
|
||||
if( $TimeFirst eq "" )
|
||||
{
|
||||
$TimeFirst = "$Mon $Day $Time";
|
||||
}
|
||||
|
||||
if( $start == 0 )
|
||||
{
|
||||
if( !defined($Connect[$cnt]) )
|
||||
{
|
||||
$Address[$cnt] = "";
|
||||
$Connect[$cnt] = "?????";
|
||||
$InFiles[$cnt] = 0;
|
||||
$OutFiles[$cnt] = 0;
|
||||
$InBytes[$cnt] = 0;
|
||||
$OutBytes[$cnt] = 0;
|
||||
$Status[$cnt] = "U";
|
||||
$Success[$cnt] = " ";
|
||||
}
|
||||
if( $Text =~ /^calling/ )
|
||||
{
|
||||
$Text =~ /^calling ([\d:\/.]+)/;
|
||||
$PidsCall{$Pid} = $1;
|
||||
$Calls{$1} = 0 if (!defined( $Calls{$1} ));
|
||||
$Calls{$1}++;
|
||||
}
|
||||
elsif( $Text =~ /^connect/ )
|
||||
{
|
||||
$Text =~ /^connect "\D*(\d+).*$/;
|
||||
$Connect[$cnt] = $1;
|
||||
}
|
||||
elsif( $Text =~ /^TCP\/IP connect/ )
|
||||
{
|
||||
$Connect[$cnt] = "TCPIP";
|
||||
}
|
||||
elsif( $Text =~ /^outbound (\S+) session/ )
|
||||
{
|
||||
$start = 1;
|
||||
$Time =~ /^(..):(..):(..)$/;
|
||||
$Start[$cnt] = ( $1 * 60 + $2 ) * 60 + $3;
|
||||
$Direction[$cnt] = "O";
|
||||
$Address[$cnt] = $PidsCall{$Pid};
|
||||
$MySexyPid = $Pid;
|
||||
next;
|
||||
}
|
||||
elsif( $Text =~ /^inbound (\S+) session/ )
|
||||
{
|
||||
$start = 1;
|
||||
$Time =~ /^(..):(..):(..)$/;
|
||||
$Start[$cnt] = ( $1 * 60 + $2 ) * 60 + $3;
|
||||
$Direction[$cnt] = "I";
|
||||
# $kAddress[$cnt] = $PidsCall{$Pid} if( defined($PidsCall{$Pid}) );
|
||||
$MySexyPid = $Pid;
|
||||
next;
|
||||
}
|
||||
next;
|
||||
}
|
||||
|
||||
if( ($start == 1) && ($Pid eq $MySexyPid) )
|
||||
{
|
||||
if( $Text =~ /^remote is password protected system/ )
|
||||
{
|
||||
$Status[$cnt] = "P";
|
||||
}
|
||||
elsif( $Text =~ /^remote is listed system/ )
|
||||
{
|
||||
$Status[$cnt] = "L";
|
||||
}
|
||||
elsif( $Text =~ /^remote is unlisted system/ )
|
||||
{
|
||||
$Status[$cnt] = "U";
|
||||
}
|
||||
elsif( $Text =~ /^[ \t]*Address :/ )
|
||||
{
|
||||
next if( $Address[$cnt] ne "" );
|
||||
$Text =~ /^.+:[ \t]+([\d:.\/]+).*$/;
|
||||
$Address[$cnt] = $1;
|
||||
}
|
||||
elsif( $Text =~ /^rcvd: \".+\" \d+/ )
|
||||
{
|
||||
$Text =~ /^rcvd: \".+\" (\d+)/;
|
||||
$InBytes[$cnt] += $1;
|
||||
$InFiles[$cnt] ++;
|
||||
}
|
||||
elsif( $Text =~ /^sent: \".+\" \d+/ )
|
||||
{
|
||||
$Text =~ /^sent: \".+\" (\d+)/;
|
||||
$OutBytes[$cnt] += $1;
|
||||
$OutFiles[$cnt] ++;
|
||||
}
|
||||
elsif( $Text =~ /^session rc = \d+/ )
|
||||
{
|
||||
$Text =~ /^session rc = (\d+)/;
|
||||
if( $1 != 0 )
|
||||
{
|
||||
$Success[$cnt] = "A";
|
||||
}
|
||||
$Time =~ /^(..):(..):(..)$/;
|
||||
$Finish[$cnt] = ( $1 * 60 + $2 ) * 60 + $3;
|
||||
$OnLine[$cnt] = $Finish[$cnt] - $Start[$cnt];
|
||||
$OnLine[$cnt] += 86400 if(( $Finish[$cnt] - $Start[$cnt] ) < 0 );
|
||||
$start = 0;
|
||||
$cnt++;
|
||||
}
|
||||
}
|
||||
# got another PID!
|
||||
elsif( $Text =~ /^connect \".+\"/
|
||||
|| $Text =~ /^inbound (\S+) session/
|
||||
|| $Text =~ /^outbound (\S+) session/ )
|
||||
{
|
||||
# Possible there was incorrectly terminated session
|
||||
# due to mailer crash or killing, so getting this string
|
||||
# can mean that we need to break reading session statistic?
|
||||
# But we can also get it if log file used not only by one
|
||||
# mailer at the same time, so.. ignore :)
|
||||
}
|
||||
} # end of while( <FLOG> )
|
||||
|
||||
close(FLOG);
|
||||
|
||||
$TimeLast = "$Mon $Day $Time" if( $Mon && $Day && $Time );
|
||||
}
|
||||
|
||||
sub SessionsStatistic
|
||||
{
|
||||
local ($addr, $start, $finish, $online, $ibyte, $obyte, $cps, $speed);
|
||||
my ($i);
|
||||
|
||||
$~ = HEADER;
|
||||
write;
|
||||
$~ = EACH;
|
||||
|
||||
for ($i = 0; $i < $cnt; $i++)
|
||||
{
|
||||
$addr = $Address[$i];
|
||||
$stat = "$Direction[$i]$Status[$i]$Success[$i]";
|
||||
$start = sec2str($Start[$i], "short");
|
||||
$finish = sec2str($Finish[$i], "short");
|
||||
$online = sec2str($OnLine[$i], "long");
|
||||
$ibyte = $InBytes[$i];
|
||||
$in = $InFiles[$i];
|
||||
$obyte = $OutBytes[$i];
|
||||
$on = $OutFiles[$i];
|
||||
$cps = int( ($ibyte + $obyte) / $OnLine[$i] ) if ($OnLine[$i] > 0);
|
||||
$speed = $Connect[$i];
|
||||
$ibyte = num2siz( $ibyte );
|
||||
$obyte = num2siz( $obyte );
|
||||
write;
|
||||
}
|
||||
|
||||
$~ = FOOTER;
|
||||
write;
|
||||
}
|
||||
|
||||
sub TotalStatistic
|
||||
{
|
||||
undef( %hSystems );
|
||||
undef( %hCalls );
|
||||
undef( %hTimes );
|
||||
undef( %hSessions );
|
||||
undef( %hInBytes );
|
||||
undef( %hOutBytes );
|
||||
undef( %hInFiles );
|
||||
undef( %hOutFiles );
|
||||
local($cal, $ses, $time, $ibyte, $obyte, $inum, $onum, $icps, $ocps);
|
||||
local($acal, $ases, $atime, $aibyte, $aobyte, $ainum, $aonum, $aicps, $aocps);
|
||||
local($sys);
|
||||
my($i);
|
||||
|
||||
$acal = 0;
|
||||
$ases = 0;
|
||||
$atime = 0;
|
||||
$aibyte = 0;
|
||||
$aobyte = 0;
|
||||
$ainum = 0;
|
||||
$aonum = 0;
|
||||
$aicps = 0;
|
||||
$aocps = 0;
|
||||
|
||||
for( $i = 0; $i < $cnt; $i++ )
|
||||
{
|
||||
$sys = $Address[$i];
|
||||
if( !defined($hSystems{$sys}) )
|
||||
{
|
||||
$hSystems{$sys} = 1;
|
||||
$hCalls{$sys} = $Calls{$sys}; $Calls{$sys} = 0;
|
||||
$hTimes{$sys} = 0;
|
||||
$hSessions{$sys} = 0;
|
||||
$hInBytes{$sys} = 0;
|
||||
$hOutBytes{$sys} = 0;
|
||||
$hInFiles{$sys} = 0;
|
||||
$hOutFiles{$sys} = 0;
|
||||
}
|
||||
$hTimes{$sys} += $OnLine[$i];
|
||||
$hSessions{$sys} += 1;
|
||||
$hInBytes{$sys} += $InBytes[$i];
|
||||
$hOutBytes{$sys} += $OutBytes[$i];
|
||||
$hInFiles{$sys} += $InFiles[$i];
|
||||
$hOutFiles{$sys} += $OutFiles[$i];
|
||||
}
|
||||
@Syst = sort( keys( %hSystems ));
|
||||
|
||||
$~ = hHEADER;
|
||||
write;
|
||||
|
||||
$~ = hEACH;
|
||||
for( $i = 0; $i <= $#Syst; $i++ )
|
||||
{
|
||||
$sys = $Syst[$i];
|
||||
$cal = ( $hCalls{$sys} || 0 ); $acal += $cal;
|
||||
$ses = $hSessions{$sys}; $ases += $ses;
|
||||
$time = sec2str($hTimes{$sys}, "long"); $atime += $hTimes{$sys};
|
||||
$ibyte = $hInBytes{$sys}; $aibyte += $ibyte;
|
||||
$obyte = $hOutBytes{$sys}; $aobyte += $obyte;
|
||||
$inum = $hInFiles{$sys}; $ainum += $inum;
|
||||
$onum = $hOutFiles{$sys}; $aonum += $onum;
|
||||
|
||||
if( $hInFiles{$sys} > 0 || $hOutFiles{$sys} > 0 )
|
||||
{
|
||||
$cps = int( ($hInBytes{$sys} + $hOutBytes{$sys}) / $hTimes{$sys} );
|
||||
$acps += $cps;
|
||||
$sess++;
|
||||
}
|
||||
else
|
||||
{
|
||||
$cps = 0;
|
||||
}
|
||||
write;
|
||||
}
|
||||
|
||||
# Now, draw systems without sessions ..
|
||||
@Syst = sort( keys( %Calls ));
|
||||
$ses = "-";
|
||||
$time = "-";
|
||||
$ibyte = "-";
|
||||
$obyte = "-";
|
||||
$inum = "-";
|
||||
$onum = "-";
|
||||
$cps = "-";
|
||||
for( $i = 0; $i <= $#Syst; $i++ )
|
||||
{
|
||||
$sys = $Syst[$i];
|
||||
if( $Calls{$sys} )
|
||||
{
|
||||
$sys = $Syst[$i];
|
||||
$cal = $Calls{$sys}; $acal += $cal;
|
||||
write;
|
||||
}
|
||||
}
|
||||
$atime = sec2str($atime, "long");
|
||||
if( $sess > 0 )
|
||||
{
|
||||
$acps = int( $acps / $sess );
|
||||
}
|
||||
else
|
||||
{
|
||||
$acps = 0;
|
||||
}
|
||||
|
||||
$~ = hFOOTER;
|
||||
write;
|
||||
}
|
||||
|
||||
sub num2siz
|
||||
{
|
||||
my($num) = $_[0];
|
||||
my($siz);
|
||||
if($num < 1000) {
|
||||
$siz = $num.' ';
|
||||
} elsif($num < 10000000) {
|
||||
$siz = int($num/1024).'k';
|
||||
} else {
|
||||
$siz = int($num/(1024*1024)).'M';
|
||||
}
|
||||
return $siz;
|
||||
}
|
||||
|
||||
sub sec2str
|
||||
{
|
||||
my($sec) = $_[0];
|
||||
my($tip) = $_[1];
|
||||
my ($h, $m, $s);
|
||||
$h = int( $sec / 3600 );
|
||||
$m = int( ($sec - $h*3600) / 60);
|
||||
$s = int( $sec % 60 );
|
||||
if( $tip =~ /short/ ) {
|
||||
return sprintf("%02d:%02d", $h, $m);
|
||||
} elsif( $tip =~ /long/ ) {
|
||||
return sprintf("%03d:%02d:%02d", $h, $m, $s);
|
||||
}
|
||||
}
|
||||
|
||||
format HEADER =
|
||||
ª”” Call : 'I' - Incoming, 'O' - Outgoing
|
||||
ƒª” Status : 'U' - Unlisted, 'L' - Listed, 'P' - Protected
|
||||
ƒƒª Session : ' ' - Success, 'A' - Aborted
|
||||
¥�����������¡���¡���������������¡���������¡����������¡����������¡�����¡�����ˆ
|
||||
ƒ Time ƒStaƒ FTN ƒ On-Line ƒ Incoming ƒ Outgoing ƒ Avg.ƒSpeedƒ
|
||||
ƒhh:mm-hh:mmƒtusƒ Address ƒhhh:mm:ssƒ Bytesƒ N ƒ Bytesƒ N ƒ CPS ƒ ƒ
|
||||
–�����������¨���¨���������������¨���������¨������¨���¨������¨���¨�����¨�����…
|
||||
.
|
||||
format EACH =
|
||||
ƒ@<<<<-@<<<<ƒ@<<ƒ@<<<<<<<<<<<<<<ƒ@>>>>>>>>ƒ@>>>>>ƒ@>>ƒ@>>>>>ƒ@>>ƒ@>>>>ƒ@>>>>ƒ
|
||||
$start,$finish,$stat,$addr, $online, $ibyte, $in,$obyte, $on,$cps, $speed
|
||||
.
|
||||
format FOOTER =
|
||||
¤�����������Ÿ���Ÿ���������������Ÿ���������Ÿ������Ÿ���Ÿ������Ÿ���Ÿ�����Ÿ�����Ž
|
||||
@>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
$Version
|
||||
.
|
||||
|
||||
format hHEADER =
|
||||
¥���������������¡���������¡���������¡��������������¡��������������¡�����ˆ
|
||||
ƒ FTN ƒ Total ƒ Time ƒ Incoming ƒ Outgoing ƒ CPS ƒ
|
||||
ƒ Address ƒCal.ƒSes.ƒ On-Line ƒ Bytes ƒ NN ƒ Bytes ƒ NN ƒ ƒ
|
||||
–���������������¨����¨����¨���������¨���������¨����¨���������¨����¨�����…
|
||||
.
|
||||
format hEACH =
|
||||
ƒ@<<<<<<<<<<<<<<ƒ@>>>ƒ@>>>ƒ@||||||||ƒ@>>>>>>>>ƒ@>>>ƒ@>>>>>>>>ƒ@>>>ƒ@>>>>ƒ
|
||||
$sys, $cal,$ses,$time, $ibyte, $inum,$obyte, $onum,$cps
|
||||
.
|
||||
format hFOOTER =
|
||||
“”””””””””””””””•””””•””””•”””””””””•”””””””””•””””•”””””””””•””””•”””””„
|
||||
ƒ TOTAL ƒ@>>>ƒ@>>>ƒ@||||||||ƒ@>>>>>>>>ƒ@>>>ƒ@>>>>>>>>ƒ@>>>ƒ@>>>>ƒ
|
||||
$acal,$ases,$atime, $aibyte, $ainum,$aobyte,$aonum,$acps
|
||||
¤���������������Ÿ����Ÿ����Ÿ���������Ÿ���������Ÿ����Ÿ���������Ÿ����Ÿ�����Ž
|
||||
@>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
$Version
|
||||
.
|
||||
@@ -0,0 +1,229 @@
|
||||
#!/bin/sh
|
||||
|
||||
Ver=1.1h
|
||||
|
||||
# óËÒÉÐÔ ÄÌÑ ÐÒÏÚ×ÏÎËÉ ÎÁ ÁÐÌÉÎËÏ×
|
||||
# ðÒÏ ×ÒÅÍÑ ÉÈ ÒÁÂÏÔÙ (É ÔÅÌÅÆÏÎÙ ÈÉÄÄÅÎÏ×) ÄÏÌÖÅÎ ÚÎÁÔØ ÍÅÊÌÅÒ
|
||||
#
|
||||
# úÁÔÏÞÅÎ ÄÌÑ ÍÅÊÌÅÒÁ BinkleyForce
|
||||
# äÌÑ ÄÒÕÇÉÈ ÐÒÁ×ÉÔØ ÆÕÎËÃÉÀ docallout
|
||||
|
||||
#
|
||||
# Copyright (c) 2000 by Georgi Fofanov, 2:5050/29@fidonet
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
|
||||
# ðÕÔØ Ë outbound'Õ ÎÕÖÎÏÊ ÚÏÎÙ (ÐÏËÁ ÚÎÁÅÍ ÔÏÌØËÏ ÐÒÏ ÏÄÎÕ ÚÏÎÕ)
|
||||
outb=/var/spool/ifmail/outb/
|
||||
|
||||
# ðÕÔØ Ë ËÁÔÁÌÏÇÕ Ó lock-ÆÁÊÌÁÍÉ (ÐÏÓÌÅÄÎÉÊ ÓÌÜÛ ÎÕÖÅÎ!)
|
||||
lock=/var/lock/
|
||||
|
||||
# ðÁÕÚÁ ÍÅÖÄÕ Ú×ÏÎËÁÍÉ
|
||||
# ÷ ÓÅËÕÎÄÁÈ
|
||||
dialdelay=120
|
||||
|
||||
# ðÅÒÉÏÄ ÓËÁÎÉÒÏ×ÁÎÉÑ outbound'Á
|
||||
# ðÏËÁ ÐÏÓÌÅ ÚÁ×ÅÒÛÅÎÉÑ ËÒÕÇÁ ÐÒÏÚ×ÏÎËÉ ÂÕÄÅÔ 2 ÐÁÕÚÙ - dialdelay É scan
|
||||
# ÷ ÓÅËÕÎÄÁÈ
|
||||
scan=60
|
||||
|
||||
# ðÁÕÚÁ ÍÅÖÄÕ ÐÒÏ×ÅÒËÁÍÉ lock-ÆÁÊÌÁ
|
||||
# ÷ ÓÅËÕÎÄÁÈ
|
||||
lockdelay=10
|
||||
|
||||
# òÁÓÐÏÌÏÖÅÎÉÅ ÍÅÊÌÅÒÁ
|
||||
mailer=/usr/local/bin/bforce
|
||||
|
||||
# ëÏÍÁÎÄÁ, ×ÙÐÏÌÎÑÅÍÁÑ ÐÏÓÌÅ ÕÓÐÅÛÎÏÊ ÓÅÓÓÉÉ
|
||||
after=/usr/local/bin/after_session
|
||||
|
||||
# õÓÔÒÏÊÓÔ×Ï, ÎÁ ËÏÔÏÒÏÍ ÓÉÄÉÔ ÍÏÄÅÍ
|
||||
TTY="ttyS1"
|
||||
|
||||
# úÄÅÓØ ÐÅÒÅÞÉÓÌÅÎÙ ÓÉÓÔÅÍÙ, ÎÁ ËÏÔÏÒÙÅ ÍÏÖÎÏ Ú×ÏÎÉÔØ É (ÞÅÒÅÚ ÐÒÏÂÅÌ) ÞÉÓÌÏ
|
||||
# ÉÈ ÍÏÄÅÍÎÙÈ ÌÉÎÉÊ
|
||||
# îÁÐÒÉÍÅÒ:
|
||||
# 2:5050/13 3
|
||||
# 2:5050/9 2
|
||||
# 2:5050/33 1
|
||||
sys_poll=/etc/fido/poll.list
|
||||
|
||||
# ðÏÌØÚÏ×ÁÔÅÌØ, ÏÔ ÉÍÅÎÉ ËÏÔÏÒÏÇÏ ÎÁÄÏ ÚÁÐÕÓËÁÔØ
|
||||
mailer_owner=fido
|
||||
|
||||
# ÷ÒÅÍÅÎÎÙÊ ÆÁÊÌ, ËÕÄÁ ÚÁÐÉÓÙ×ÁÅÔÓÑ ÓÐÉÓÏË ?lo É ?ut
|
||||
list_file=/var/spool/ifmail/list.lst
|
||||
|
||||
# ÷ÒÅÍÅÎÎÙÊ ÆÁÊÌ
|
||||
tmp_file=/var/spool/ifmail/list.tmp
|
||||
|
||||
# ÷ÒÅÍÅÎÎÙÊ ÆÁÊÌ, × ËÏÔÏÒÏÍ ÐÅÒÅÞÉÓÌÅÎÙ ÓÉÓÔÅÍÙ, ÎÁ ËÏÔÏÒÙÅ ÂÕÄÅÍ Ú×ÏÎÉÔØ
|
||||
poll_file=/var/spool/ifmail/polling.list
|
||||
|
||||
# íÁËÓÉÍÁÌØÎÏÅ ÞÉÓÌÏ ÐÏÐÙÔÏË ÄÏÚ×ÏÎÉÔØÓÑ ÎÁ ÓÉÓÔÅÍÕ
|
||||
MAXTRY=25
|
||||
|
||||
# óËÏÌØËÏ ×ÒÅÍÅÎÉ ÎÅ Ú×ÏÎÉÔØ ÎÁ ÓÉÓÔÅÍÕ, ÅÓÌÉ ÉÓÞÅÒÐÁÎÏ ÞÉÓÌÏ ÐÏÐÙÔÏË ÄÏÚ×ÏÎÁ
|
||||
# ÷ ÍÉÎÕÔÁÈ
|
||||
MAXTIME=60
|
||||
|
||||
# ðÒÏÉÚ×ÏÄÉÍ Ú×ÏÎÏË
|
||||
function docallout ()
|
||||
{
|
||||
local zone=$1 net=$2 node=$3 point=$4 curtry=$5 numline=$6 line
|
||||
|
||||
let line=${curtry}%${numline}
|
||||
|
||||
if [ $point = 0 ] ; then
|
||||
echo -n `date +%b\ %m\ %T` callout[$$] ú×ÏÎÉÍ ÎÁ ${zone}:${net}/${node} \(try \#${curtry}\)
|
||||
$mailer ${zone}:${net}/${node} -l $line
|
||||
let result=$?
|
||||
else
|
||||
echo -n `date +%b\ %m.%Y\ %T` callout[$$] ú×ÏÎÉÍ ÎÁ ${zone}:${net}/${node}.${point} \(try \#${curtry}\)
|
||||
$mailer ${zone}:${net}/${node}.${point} -l $line
|
||||
let result=$?
|
||||
fi
|
||||
|
||||
case $result in
|
||||
0 ) echo " ÕÓÐÅÛÎÏ" ;;
|
||||
* ) echo " ÏÛÉÂËÁ" \#$result ;;
|
||||
esac
|
||||
|
||||
if [ $result = 0 ] ; then
|
||||
echo `date +%s` 0 0 >$sts
|
||||
`$after`
|
||||
else
|
||||
echo `date +%s` $curtry $result >$sts
|
||||
fi
|
||||
}
|
||||
|
||||
# ðÒÏ×ÅÒÑÅÍ, ÍÏÖÎÏ ÌÉ Ú×ÏÎÉÔØ ÎÁ ÜÔÕ ÓÉÓÔÅÍÕ
|
||||
function checkcallout ()
|
||||
{
|
||||
local curtry=$1 zone=$2 net=$3 node=$4 point=$5 numline=0
|
||||
|
||||
if [ $point = 0 ] ; then
|
||||
`fgrep "${zone}:${net}/${node}" $sys_poll | awk '{ print "let numline=" $2 }'`
|
||||
else
|
||||
`fgrep "${zone}:${net}/${node}.${point}" $sys_poll | awk '{ print "let numline=" $2 }'`
|
||||
fi
|
||||
if [ $numline == 0 ] ; then return ; fi
|
||||
|
||||
docallout $zone $net $node $point $curtry $numline
|
||||
}
|
||||
|
||||
# óËÁÎÉÒÕÅÍ outbound
|
||||
function scandir ()
|
||||
{
|
||||
find -type f -and \( -name "*.?lo" -o -name "*.?ut" \) > $list_file
|
||||
for file in `cat $list_file` ; do
|
||||
eval `echo $file | awk '{ sub(/\.\//, "")
|
||||
if (substr($0, 9, 4) == ".pnt") {
|
||||
point = substr($0, 18, 4)
|
||||
} else {
|
||||
point = 0
|
||||
}
|
||||
printf "zonehex=%s nethex=%s nodehex=%s pointhex=%s let zone=0x%s net=0x%s node=0x%s point=0x%s",
|
||||
"2", substr($0, 1, 4), substr($0, 5, 4), point,
|
||||
"2", substr($0, 1, 4), substr($0, 5, 4), point
|
||||
}'`
|
||||
ext=${file:${#file}-3}
|
||||
sts=${file%%?ut}
|
||||
sts=${sts%%?lo}
|
||||
bsy=${sts}bsy
|
||||
sts=${sts}sts
|
||||
if [ $ext != hlo -a $ext != hut ] ; then
|
||||
echo ${zone} ${net} ${node} ${point} $sts $bsy >> $tmp_file
|
||||
fi
|
||||
done
|
||||
|
||||
rm $list_file
|
||||
|
||||
if [ -f $tmp_file ] ; then
|
||||
`cat $tmp_file | sort | uniq > $poll_file`
|
||||
rm $tmp_file
|
||||
n=0
|
||||
for sys in `cat $poll_file` ; do
|
||||
let n=${n}+1
|
||||
let tmp=${n}%6
|
||||
case $tmp in
|
||||
1 ) let zone=$sys ;;
|
||||
2 ) let net=$sys ;;
|
||||
3 ) let node=$sys ;;
|
||||
4 ) let point=$sys ;;
|
||||
5 ) sts=$sys ;;
|
||||
0 ) bsy=$sys ;;
|
||||
esac
|
||||
if [ $tmp == 0 ] ; then
|
||||
while [ -e ${lock}LCK..$TTY ]
|
||||
do
|
||||
sleep $lockdelay
|
||||
done
|
||||
if [ ! -f $bsy ] ; then
|
||||
if [ ! -f $sts ] ; then
|
||||
let lasttime=0 retries=0 errcode=0
|
||||
else
|
||||
`cat $sts|awk '{ print "let lasttime=" $1 " retries=" $2 " errcode=" $3 }'`
|
||||
fi
|
||||
let curtime=`date +%s`
|
||||
let timediff=${curtime}-${lasttime}
|
||||
let curtry=${retries}+1
|
||||
if [ $curtry -gt $MAXTRY ] ; then
|
||||
if [ $timediff -gt $MAXTIME ] ; then
|
||||
let curtry=1
|
||||
checkcallout $curtry $zone $net $node $point
|
||||
sleep $dialdelay
|
||||
fi
|
||||
else
|
||||
checkcallout $curtry $zone $net $node $point
|
||||
sleep $dialdelay
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
rm $poll_file
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
function main ()
|
||||
{
|
||||
|
||||
cd $outb
|
||||
|
||||
while [ ! -f /tmp/callout.exit ] ; do
|
||||
if [ ! -e ${lock}LCK..$TTY ]; then
|
||||
scandir
|
||||
sleep $scan
|
||||
else
|
||||
sleep $lockdelay
|
||||
fi
|
||||
done
|
||||
rm /tmp/callout.exit
|
||||
}
|
||||
|
||||
if [ `whoami` != "$mailer_owner" ]; then
|
||||
echo "wrong uid, run as user $mailer_owner (rc=2)"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
. /etc/profile > /dev/null 2>&1
|
||||
let MAXTIME=${MAXTIME}*60
|
||||
main >> /var/log/ifmail/callout.log 2>&1
|
||||
|
||||
## éÚÍÅÎÅÎÉÑ
|
||||
|
||||
# Ver 1.1, 09 Jul 2000:
|
||||
#
|
||||
# ïÂÎÕÌÅÎÉÅ ÞÉÓÌÁ ÐÏÐÙÔÏË ÐÏÓÌÅ ÕÓÐÅÛÎÏÊ ÓÅÓÓÉÉ
|
||||
#
|
||||
# îÅ ÒÁÂÏÔÁÌ MAXTIME
|
||||
|
||||
# Ver 1.0, 08 Jul 2000:
|
||||
#
|
||||
# ðÅÒ×ÁÑ ÓÔÁÂÉÌØÎÁÑ ×ÅÒÓÉÑ
|
||||
@@ -0,0 +1,51 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# bforce FTN mailer
|
||||
#
|
||||
# chkconfig: 345 94 14
|
||||
# description: Starts and stops the binkleyforce mailer daemon
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
OWNER=uucp
|
||||
BFORCE=/usr/local/fido/bin/bforce
|
||||
|
||||
# Source function library.
|
||||
. /etc/init.d/functions
|
||||
|
||||
[ -f $BFORCE ] || exit 0
|
||||
|
||||
# See how we were called.
|
||||
case "$1" in
|
||||
start)
|
||||
# Start daemon.
|
||||
echo -n "Starting bforce: "
|
||||
su $OWNER -c ". /etc/rc.d/init.d/functions; daemon $BFORCE -d"
|
||||
echo
|
||||
touch /var/lock/subsys/bforce
|
||||
;;
|
||||
stop)
|
||||
# Stop daemon.
|
||||
echo -n "Shutting down bforce: "
|
||||
killproc bforce
|
||||
rm -f /var/lock/subsys/bforce
|
||||
echo
|
||||
;;
|
||||
status)
|
||||
status bforce
|
||||
exit $?
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
$0 start
|
||||
exit $?
|
||||
;;
|
||||
*)
|
||||
echo "Usage: bforce {start|stop|status|restart}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# bforce FTN mailer
|
||||
#
|
||||
# chkconfig: 345 94 14
|
||||
# description: Starts and stops the binkleyforce mailer daemon
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
OWNER=uucp
|
||||
BFORCE=/usr/local/fido/bin/bforce
|
||||
|
||||
[ -f $BFORCE ] || exit 0
|
||||
|
||||
# See how we were called.
|
||||
case "$1" in
|
||||
start)
|
||||
# Start daemon.
|
||||
echo -n "Starting bforce. "
|
||||
su $OWNER -c "daemon $BFORCE -d"
|
||||
echo
|
||||
touch /var/lock/subsys/bforce
|
||||
;;
|
||||
stop)
|
||||
# Stop daemon.
|
||||
echo -n "Shutting down bforce. "
|
||||
$BFORCE -q
|
||||
rm -f /var/lock/subsys/bforce
|
||||
echo
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
$0 start
|
||||
exit $?
|
||||
;;
|
||||
*)
|
||||
echo "Usage: bforce {start|stop|restart}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit 0
|
||||
+366
@@ -0,0 +1,366 @@
|
||||
#!/usr/bin/tclsh
|
||||
#
|
||||
# Copyright (c) 2000 by Alexander Belkin <adb@newmail.ru>
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# Tcl script for creating polls, file requests and file attaches
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
##################
|
||||
# Program settings
|
||||
|
||||
# Defaults for address completion
|
||||
set def_zone 2
|
||||
set def_net 5020
|
||||
set def_node 1398
|
||||
|
||||
# Path to your main BSO directory (not implemented)
|
||||
#set bso_dir "/var/spool/ftn/out"
|
||||
|
||||
# Path to your ASO directory
|
||||
set aso_dir "/var/spool/fido/amiga.out"
|
||||
|
||||
# Log file name
|
||||
set logfile "/var/log/bforce/outman.log"
|
||||
|
||||
# Uncomment this if you not need logging
|
||||
#set logfile {}
|
||||
|
||||
################################
|
||||
# The program's body starts here
|
||||
|
||||
set LOG {}
|
||||
|
||||
proc stupid_user {} {
|
||||
|
||||
puts "Usage: outman <\[poll|freq|send]> \[options] <address> \[files]\n"
|
||||
puts "options:"
|
||||
puts " -hold set hold flavor"
|
||||
puts " -normal set normal flavor (default)"
|
||||
puts " -crash set crash flavor"
|
||||
puts " -kill kill files after send"
|
||||
puts " -truncate truncate files after send"
|
||||
puts ""
|
||||
puts "Mail bug reports to <adb@newmail.ru>"
|
||||
exit 1
|
||||
}
|
||||
|
||||
proc log {str} {
|
||||
|
||||
global LOG
|
||||
global logfile
|
||||
|
||||
if { $logfile != {} } {
|
||||
|
||||
if { $LOG == {} } {
|
||||
set LOG [open $logfile "a"]
|
||||
}
|
||||
|
||||
set seconds [clock seconds]
|
||||
|
||||
puts $LOG "[clock format $seconds -format "%d/%m %H:%M:%S"] $str"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
proc parse_addr {str} {
|
||||
|
||||
global def_zone
|
||||
global def_net
|
||||
global def_node
|
||||
set zone $def_zone
|
||||
set net $def_net
|
||||
set node $def_node
|
||||
set point 0
|
||||
|
||||
if { [regexp "^\[0-9]+:\[0-9]+/\[0-9]+\\.?\[0-9]*$" $str] } {
|
||||
|
||||
regexp "(\[0-9]+):(\[0-9]+)/(\[0-9]+)\\.?(\[0-9]*)$" $str \
|
||||
{} zone net node point
|
||||
|
||||
} elseif { [regexp "^\[0-9]+/\[0-9]+\\.?\[0-9]*$" $str] } {
|
||||
|
||||
regexp "(\[0-9]+)/(\[0-9]+)\\.?(\[0-9]*)$" $str \
|
||||
{} net node point
|
||||
|
||||
} elseif { [regexp "^\[0-9]+\\.?\[0-9]*$" $str] } {
|
||||
|
||||
regexp "^(\[0-9]*)\\.?(\[0-9]*)$" $str \
|
||||
{} node point
|
||||
|
||||
} elseif { [regexp "^\.\[0-9]+$" $str] } {
|
||||
|
||||
regexp "^\.(\[0-9]+)$" $str \
|
||||
{} point
|
||||
|
||||
} else {
|
||||
|
||||
puts "invalid address $str"
|
||||
return {}
|
||||
|
||||
}
|
||||
|
||||
if { $zone == {} } { set zone [$def_zone] }
|
||||
if { $net == {} } { set net [$def_net] }
|
||||
if { $node == {} } { set node [$def_node] }
|
||||
if { $point == {} } { set point 0 }
|
||||
|
||||
# puts "debug: address parse '$str' -> '$zone,$net,$node,$point'"
|
||||
|
||||
return "$zone $net $node $point"
|
||||
}
|
||||
|
||||
proc addrstr {addr} {
|
||||
|
||||
return [lindex $addr 0]:[lindex $addr 1]/[lindex $addr 2].[lindex $addr 3]
|
||||
}
|
||||
|
||||
#
|
||||
# TODO: support for outbounds not in the default zone
|
||||
#
|
||||
proc filename_bso {addr flavor} {
|
||||
|
||||
global bso_dir
|
||||
|
||||
set zone [lindex $addr 0]
|
||||
set net [lindex $addr 1]
|
||||
set node [lindex $addr 2]
|
||||
set point [lindex $addr 3]
|
||||
|
||||
if { $point } {
|
||||
|
||||
set name [format "%04x%04x.pnt/%08x" $net $node $point]
|
||||
|
||||
} else {
|
||||
|
||||
set name [format "%04x%04x" $net $node]
|
||||
|
||||
}
|
||||
|
||||
switch $flavor {
|
||||
"bsy" {
|
||||
return "$bso_dir/$name.bsy"
|
||||
}
|
||||
"freq" {
|
||||
return "$bso_dir/$name.req"
|
||||
}
|
||||
"hold" {
|
||||
return "$bso_dir/$name.hlo"
|
||||
}
|
||||
"crash" {
|
||||
return "$bso_dir/$name.clo"
|
||||
}
|
||||
default {
|
||||
return "$bso_dir/$name.flo"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc filename_aso {addr flavor} {
|
||||
|
||||
global aso_dir
|
||||
|
||||
set name [lindex $addr 0].[lindex $addr 1].[lindex $addr 2].[lindex $addr 3]
|
||||
|
||||
switch $flavor {
|
||||
"bsy" {
|
||||
return "$aso_dir/$name.bsy"
|
||||
}
|
||||
"freq" {
|
||||
return "$aso_dir/$name.req"
|
||||
}
|
||||
"hold" {
|
||||
return "$aso_dir/$name.hlo"
|
||||
}
|
||||
"crash" {
|
||||
return "$aso_dir/$name.clo"
|
||||
}
|
||||
default {
|
||||
return "$aso_dir/$name.flo"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc bsy_exist {addr} {
|
||||
|
||||
set bsyname [filename_aso $addr "bsy"]
|
||||
|
||||
if { [file exists $bsyname] } {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
proc command_freq {addr files} {
|
||||
|
||||
set reqname [filename_aso $addr "freq"]
|
||||
set name {}
|
||||
|
||||
# puts "debug: file request name is '$reqname'"
|
||||
|
||||
set REQ [open $reqname "a"]
|
||||
|
||||
foreach name $files {
|
||||
puts $REQ $name
|
||||
log "request \"$name\" from [addrstr $addr]"
|
||||
}
|
||||
|
||||
close $REQ
|
||||
}
|
||||
|
||||
proc command_poll {addr flavor} {
|
||||
|
||||
set floname [filename_aso $addr $flavor]
|
||||
|
||||
if { ![file exists $floname] } {
|
||||
|
||||
set FLO [open $floname "a"]
|
||||
close $FLO
|
||||
log "poll [addrstr $addr] ($flavor)"
|
||||
|
||||
} else {
|
||||
|
||||
log "cannot create poll for [addrstr $addr]: allready polled"
|
||||
}
|
||||
}
|
||||
|
||||
proc command_send {addr files flavor action} {
|
||||
|
||||
set floname [filename_aso $addr $flavor]
|
||||
set name {}
|
||||
set curdir [exec pwd]
|
||||
|
||||
set FLO [open $floname "a"]
|
||||
|
||||
foreach name $files {
|
||||
if { [file exists $name] } {
|
||||
|
||||
if { [file pathtype $name] == "relative" } {
|
||||
if { [string match "./*" $name] } {
|
||||
set name [string range $name 2 end]
|
||||
}
|
||||
set name "$curdir/$name"
|
||||
}
|
||||
|
||||
log "send file \"$name\" ([file size $name] bytes) to [addrstr $addr] ($flavor)"
|
||||
|
||||
switch $action {
|
||||
"kill" {
|
||||
puts $FLO "^$name"
|
||||
}
|
||||
"truncate" {
|
||||
puts $FLO "#$name"
|
||||
}
|
||||
default {
|
||||
puts $FLO "@$name"
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
puts "skip file \"$name\" to [addrstr $addr]: file not exist"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
close $FLO
|
||||
}
|
||||
|
||||
##############################
|
||||
# The main program starts here
|
||||
|
||||
if { $argc < 2 } {
|
||||
stupid_user
|
||||
}
|
||||
|
||||
set command {}
|
||||
set address {}
|
||||
set addr {}
|
||||
set files {}
|
||||
set flavor "normal"
|
||||
set action "nothing"
|
||||
|
||||
for {set i 0} {$i < $argc} {incr i} {
|
||||
|
||||
set arg [lindex $argv $i]
|
||||
|
||||
if { [string index $arg 0] == "-" } {
|
||||
|
||||
switch [string range $arg 1 end] {
|
||||
"hold" {
|
||||
set flavor "hold"
|
||||
}
|
||||
"normal" {
|
||||
set flavor "normal"
|
||||
}
|
||||
"crash" {
|
||||
set flavor "crash"
|
||||
}
|
||||
"kill" {
|
||||
set action "kill"
|
||||
}
|
||||
"truncate" {
|
||||
set action "truncate"
|
||||
}
|
||||
default {
|
||||
puts "unknown command line option '$arg'"
|
||||
stupid_user
|
||||
}
|
||||
}
|
||||
|
||||
} elseif { $command == {} } {
|
||||
|
||||
set command $arg
|
||||
|
||||
} elseif { $address == {} } {
|
||||
|
||||
set address $arg
|
||||
set addr [parse_addr $address]
|
||||
if { $addr == {} } {
|
||||
stupid_user
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
lappend files $arg
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if { $command == {} || $address == {} } {
|
||||
stupid_user
|
||||
}
|
||||
|
||||
if { [bsy_exist $addr] } {
|
||||
puts "bsy file exist for address [addrstr $addr]"
|
||||
exit 2
|
||||
}
|
||||
|
||||
switch $command {
|
||||
"poll" {
|
||||
command_poll $addr $flavor
|
||||
}
|
||||
"freq" {
|
||||
command_freq $addr $files
|
||||
}
|
||||
"send" {
|
||||
command_send $addr $files $flavor $action
|
||||
}
|
||||
default {
|
||||
puts "unknown command $command"
|
||||
stupid_user
|
||||
}
|
||||
}
|
||||
|
||||
if { $LOG != {} } {
|
||||
close $LOG
|
||||
}
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/tclsh
|
||||
#
|
||||
# Copyright (c) 2000 by Alexander Belkin <adb@newmail.ru>
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# Time syncronization utility
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
##################
|
||||
# Program settings
|
||||
|
||||
set bforce_log_file "/var/log/bforce/bf-log.ttyS0"
|
||||
set sync_with_addr "2:450/102"
|
||||
set max_time_diff 1800
|
||||
set min_time_diff 20
|
||||
set news_groups "local.robots"
|
||||
set from_user "Time Robot <root@fido.xxx.local>"
|
||||
set inews_cmd "/usr/bin/inews"
|
||||
|
||||
################################
|
||||
# The program's body starts here
|
||||
|
||||
set sess_pid ""
|
||||
set remote_times ""
|
||||
set local_times ""
|
||||
set TEXT ""
|
||||
|
||||
set INP [open $bforce_log_file "r"]
|
||||
foreach line [split [read $INP] "\n"] {
|
||||
|
||||
set fields [split $line " "]
|
||||
set pid [lindex $fields 3]
|
||||
set time [join [lrange $fields 0 2]]
|
||||
set data [join [lrange $fields 4 end]]
|
||||
|
||||
if { [string match "*Address : $sync_with_addr" $data] } {
|
||||
set sess_pid $pid
|
||||
set sess_time ""
|
||||
} elseif { [string match "*Time :*" $data] } {
|
||||
if { $sess_pid == $pid } {
|
||||
regexp "Time : (.+)" $data {} timestr
|
||||
if { $timestr != "" } {
|
||||
set sess_time $timestr
|
||||
}
|
||||
}
|
||||
} elseif { [string match "remote is*,protected" $data] } {
|
||||
if { $sess_pid == $pid } {
|
||||
if { $sess_time != "" && $time != "" } {
|
||||
lappend remote_times $sess_time
|
||||
lappend local_times $time
|
||||
}
|
||||
set sess_pid ""
|
||||
set sess_time ""
|
||||
}
|
||||
} elseif { [string match "remote is*" $data] } {
|
||||
if { $sess_pid == $pid } {
|
||||
set sess_pid ""
|
||||
set sess_time ""
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
close $INP
|
||||
|
||||
set last_rem_time [lindex $remote_times end]
|
||||
set last_loc_time [lindex $local_times end]
|
||||
|
||||
if { $last_rem_time != "" && $last_loc_time != "" } {
|
||||
|
||||
regexp "(\[0-9]+):(\[0-9]+):(\[0-9]+)" $last_rem_time {} rh rm rs
|
||||
regexp "(\[0-9]+):(\[0-9]+):(\[0-9]+)" $last_loc_time {} lh lm ls
|
||||
set rem [expr "$rh*3600 + $rm*60 + $rs"]
|
||||
set loc [expr "$lh*3600 + $lm*60 + $ls"]
|
||||
set diff [expr "$rem - $loc"]
|
||||
|
||||
if { [expr abs($diff)] < $min_time_diff } {
|
||||
# Do nothing
|
||||
} elseif { [expr abs($diff)] <= $max_time_diff } {
|
||||
set old_sec [clock seconds]
|
||||
set new_sec [expr $old_sec + $diff]
|
||||
|
||||
exec /bin/date -s [clock format $new_sec -format "%d-%b-%Y %H:%M:%S"]
|
||||
exec /sbin/clock -wu
|
||||
|
||||
append TEXT "The System time was synchronized with the node $sync_with_addr\n\n"
|
||||
append TEXT "Old time : [clock format $old_sec]\n"
|
||||
append TEXT "New time : [clock format $new_sec]\n"
|
||||
append TEXT "Time difference : $diff second(s)\n"
|
||||
} else {
|
||||
set old_sec [clock seconds]
|
||||
set new_sec [expr $old_sec + $diff]
|
||||
|
||||
append TEXT "The System time WAS NOT synchronized with the node $sync_with_addr\n\n"
|
||||
append TEXT "Current time : [clock format $old_sec]\n"
|
||||
append TEXT "Want set time : [clock format $new_sec]\n"
|
||||
append TEXT "Time difference : $diff second(s) (must be lower $max_time_diff seconds)\n"
|
||||
}
|
||||
}
|
||||
|
||||
if { $TEXT != "" } {
|
||||
|
||||
set MSG "From: $from_user\n"
|
||||
append MSG "Subject: Time synchronization\n"
|
||||
append MSG "Newsgroups: $news_groups\n\n"
|
||||
append MSG $TEXT
|
||||
|
||||
exec $inews_cmd -h << $MSG
|
||||
}
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
License notice for u-srif-py
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
+-----------+----------------------+----------------------+
|
||||
| | Statistic | Limits |
|
||||
| Period +-------------+--------+-------------+--------+
|
||||
| | Size | Number | Size | Number |
|
||||
+-----------+-------------+--------+-------------+--------+
|
||||
| Day | @%-11d,sent_day_size@ | @%-6d,sent_day_num@ | @%-11s,limit_size_day@ | @%-6s,limit_num_day@ |
|
||||
+-----------+-------------+--------+-------------+--------+
|
||||
| Week | @%-11d,sent_week_size@ | @%-6d,sent_week_num@ | @%-11s,limit_size_week@ | @%-6s,limit_num_week@ |
|
||||
+-----------+-------------+--------+-------------+--------+
|
||||
| Month | @%-11d,sent_month_size@ | @%-6d,sent_month_num@ | @%-11s,limit_size_month@ | @%-6s,limit_num_month@ |
|
||||
+-----------+-------------+--------+-------------+--------+
|
||||
| Total | @%-11d,sent_total_size@ | @%-6d,sent_total_num@ |
|
||||
+-----------+-------------+--------+
|
||||
|
||||
******************************************************************************
|
||||
File requests policy
|
||||
******************************************************************************
|
||||
|
||||
File requests supported at 00:00-05:30 and at least 9600 speed
|
||||
|
||||
There are aliases for file requests:
|
||||
|
||||
FILES - Happy Station files list
|
||||
BFORCE - The latest version of the binkleyforce mailer
|
||||
|
||||
Bye, call again!
|
||||
@@ -0,0 +1,2 @@
|
||||
Hello, @%s,remote_sysop@!
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
files /home/ftp/pub/info/happy.zip
|
||||
filelist /home/ftp/pub/info/happy.lst
|
||||
test /home/ftp/pub/fileecho/PNT5020/pnt5020.zip
|
||||
bforce /home/ftp/pub/bforce/bforce-last.tar.gz
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
##############################################################################
|
||||
### u-srif FREQ processor configuration file #################################
|
||||
##############################################################################
|
||||
|
||||
# Spool directory for files index, links statistic, etc.
|
||||
spool-dir /var/spool/u-srif
|
||||
|
||||
# Log file name
|
||||
log-file /var/log/ftn/u-srif.log
|
||||
|
||||
# File with list of freqable directories
|
||||
dir-list-file /usr/local/etc/u-srif/u-srif.dirs
|
||||
|
||||
# File with list of freqable directories
|
||||
alias-list-file /usr/local/etc/u-srif/u-srif.aliases
|
||||
|
||||
freq-policy /usr/local/etc/u-srif/policy.text
|
||||
|
||||
freq-magic bforce-cvs /usr/local/etc/u-srif/magic/bforce-cvs
|
||||
freq-alias = files /home/ftp/pub password
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/home/ftp/pub/bforce/
|
||||
/home/ftp/pub/fileecho/ADV_FTNSOFT/
|
||||
/home/ftp/pub/fileecho/AFTNMISC/
|
||||
/home/ftp/pub/fileecho/AVP/
|
||||
/home/ftp/pub/fileecho/BOOK/
|
||||
/home/ftp/pub/fileecho/CRACKER/
|
||||
/home/ftp/pub/fileecho/CRACKS/
|
||||
/home/ftp/pub/fileecho/FAR/
|
||||
/home/ftp/pub/fileecho/FR_CO.FILES/
|
||||
/home/ftp/pub/fileecho/FWUTILS/
|
||||
/home/ftp/pub/fileecho/GSS_BETA/
|
||||
/home/ftp/pub/fileecho/GSS_SOFT/
|
||||
/home/ftp/pub/fileecho/G_CHEAT/
|
||||
/home/ftp/pub/fileecho/IT.FILES/
|
||||
/home/ftp/pub/fileecho/IT.MP3/
|
||||
/home/ftp/pub/fileecho/IT.MUSIC/
|
||||
/home/ftp/pub/fileecho/IT.NDL/
|
||||
/home/ftp/pub/fileecho/LARRY.FILES/
|
||||
/home/ftp/pub/fileecho/HAPPY.XCK/
|
||||
/home/ftp/pub/fileecho/MOBIL/
|
||||
/home/ftp/pub/fileecho/NET5020/
|
||||
/home/ftp/pub/fileecho/PNT5020/
|
||||
/home/ftp/pub/fileecho/RUFO/
|
||||
/home/ftp/pub/fileecho/STICK.FILES/
|
||||
/home/ftp/pub/fileecho/T-MAIL/
|
||||
/home/ftp/pub/fileecho/UNKNOWN/
|
||||
/home/ftp/pub/fileecho/XDOCREF/
|
||||
/home/ftp/pub/fileecho/XGAMSOL/
|
||||
/home/ftp/pub/fileecho/XHAMRADIO/
|
||||
/home/ftp/pub/fileecho/XHRDASUS/
|
||||
/home/ftp/pub/fileecho/XHRDDOCS/
|
||||
/home/ftp/pub/fileecho/XHRDIDC/
|
||||
/home/ftp/pub/fileecho/XHRDUSR/
|
||||
/home/ftp/pub/fileecho/XPICART/
|
||||
/home/ftp/pub/fileecho/XPICHUMOR/
|
||||
/home/ftp/pub/fileecho/XPICMUSIC/
|
||||
/home/ftp/pub/fileecho/XPICSHIP/
|
||||
/home/ftp/pub/fileecho/XPICSYSOP/
|
||||
/home/ftp/pub/fileecho/XPICWEAPON/
|
||||
/home/ftp/pub/files/uue_files/
|
||||
/home/ftp/pub/redhat-5.2/RedHat/RPMS/
|
||||
/home/ftp/pub/redhat-6.1/RedHat/RPMS/
|
||||
@@ -0,0 +1,163 @@
|
||||
|
||||
import gdbm
|
||||
import string
|
||||
import os
|
||||
import ufido
|
||||
|
||||
ALIAS_TYPE_NORMAL = 1 # Traditional aliase
|
||||
ALIAS_TYPE_MAGIC = 2 # "Magic" alias
|
||||
|
||||
# TODO: These functions must generate an exception in case of errors
|
||||
def get_bool(str):
|
||||
str = string.lower(str)
|
||||
if str == 'yes' or str == 'true':
|
||||
return 1
|
||||
elif str == 'no' or str == 'false':
|
||||
return 0
|
||||
return None
|
||||
|
||||
def get_size(str):
|
||||
# TODO: support nice size formats like 64M, 10G
|
||||
return str
|
||||
|
||||
def get_alias(str, type):
|
||||
args = string.split(str)
|
||||
if len(args) < 2 or len(args) > 3:
|
||||
return None
|
||||
if len(args) == 3:
|
||||
passwd = args[2]
|
||||
else:
|
||||
passwd = None
|
||||
return Alias(args[0], args[1], passwd, type)
|
||||
|
||||
class Alias:
|
||||
""" Aliases implementation
|
||||
"""
|
||||
def __init__(self, name, filename, passwd, type):
|
||||
""" Alias initialisation
|
||||
"""
|
||||
self.name = name
|
||||
self.filename = filename
|
||||
self.type = type
|
||||
|
||||
def get(self, passwd):
|
||||
""" Get the list of files to send for this alias
|
||||
"""
|
||||
yield = []
|
||||
if self.type == ALIAS_TYPE_NORMAL:
|
||||
yield.append(self.filename)
|
||||
return yield
|
||||
elif self.type == ALIAS_TYPE_MAGIC:
|
||||
# Prepare the environment (TODO)
|
||||
putenv('PASSWORD', passwd)
|
||||
putenv('ADDRESS', None)
|
||||
putenv('PROTECTED', 'FALSE')
|
||||
putenv('LISTED', 'FALSE')
|
||||
# Execute magic program and process its output
|
||||
try:
|
||||
magic = popen(self.filename)
|
||||
line = magic.readline()
|
||||
while line:
|
||||
line = magic.readline()
|
||||
yield.append(string.strip(line))
|
||||
if magic.close():
|
||||
print "Magic return code is non-zero: ", self.filename
|
||||
return None
|
||||
return yield
|
||||
except IOError:
|
||||
print "Failed to run magic: ", self.filename
|
||||
return None
|
||||
|
||||
class Config:
|
||||
def read_dir_list(self):
|
||||
yield = []
|
||||
fp = open(self.dir_list_file, 'r')
|
||||
line = fp.readline()
|
||||
while line:
|
||||
line = string.strip(line)
|
||||
if line != '':
|
||||
yield.append(line)
|
||||
line = fp.readline()
|
||||
fp.close()
|
||||
return yield
|
||||
|
||||
def read_alias_list(self):
|
||||
yield = []
|
||||
fp = open(self.alias_list_file, 'r')
|
||||
line = fp.readline()
|
||||
while line:
|
||||
line = string.strip(line)
|
||||
if line != '':
|
||||
[name, filename] = string.split(line, None, 1)
|
||||
yield.append(alias(name, filename))
|
||||
line = fp.readline()
|
||||
fp.close()
|
||||
return yield
|
||||
|
||||
def read(self, name):
|
||||
fp = open(name, 'r')
|
||||
line = fp.readline()
|
||||
while line:
|
||||
line = string.strip(line)
|
||||
args = string.split(line, None, 1)
|
||||
if line[0:1] == '#' or len(line) == 0:
|
||||
pass
|
||||
elif len(args) != 2:
|
||||
print "Invalid string in config: ", line
|
||||
else:
|
||||
key = string.lower(args[0])
|
||||
val = args[1]
|
||||
if key == 'dir-list-file':
|
||||
self.dir_list_file = val
|
||||
elif key == 'send-report':
|
||||
self.send_report = get_bool(val)
|
||||
elif key == 'limit-size-day':
|
||||
self.limit_size_day = get_size(val)
|
||||
elif key == 'limit-size-week':
|
||||
self.limit_size_week = get_size(val)
|
||||
elif key == 'limit-size-month':
|
||||
self.limit_size_month = get_size(val)
|
||||
elif key == 'spool-dir':
|
||||
self.spool_dir = val
|
||||
elif key == 'freq-alias':
|
||||
self.freq_alias.append(get_alias(val, ALIAS_TYPE_NORMAL))
|
||||
elif key == 'freq-magic':
|
||||
self.freq_magic.append(get_alias(val, ALIAS_TYPE_MAGIC))
|
||||
elif key == 'log-file':
|
||||
self.log_file = val
|
||||
elif key == 'local-address':
|
||||
self.local_address.parse(var)
|
||||
elif key == 'report-header':
|
||||
self.report_header = val
|
||||
elif key == 'report-footer':
|
||||
self.report_footer = val
|
||||
elif key == 'report-from':
|
||||
self.report_from = val
|
||||
elif key == 'report-subj':
|
||||
self.report_subj = val
|
||||
elif key == 'stat-dbase':
|
||||
self.stat_dbase = val
|
||||
else:
|
||||
print "unknown config keyword:", key
|
||||
line = fp.readline()
|
||||
fp.close()
|
||||
|
||||
def __init__(self, name):
|
||||
self.dir_list_file = ''
|
||||
self.send_report = 0
|
||||
self.limit_size_day = 0
|
||||
self.limit_size_week = 0
|
||||
self.limit_size_month = 0
|
||||
self.spool_dir = ''
|
||||
self.freq_policy = ''
|
||||
self.freq_alias = []
|
||||
self.freq_magic = []
|
||||
self.log_file = ''
|
||||
self.local_address = ufido.address()
|
||||
self.report_header = ''
|
||||
self.report_footer = ''
|
||||
self.report_from = 'FREQ manager'
|
||||
self.report_subj = 'FREQ report'
|
||||
self.stat_dbase = None
|
||||
self.read(name)
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
|
||||
import os
|
||||
import gdbm
|
||||
import string
|
||||
|
||||
def get_file_desc(filename):
|
||||
path, name = os.path.split(filename)
|
||||
descname = os.path.join(path, '.desc', name + '.desc')
|
||||
if not os.path.isfile(descname):
|
||||
return None
|
||||
try:
|
||||
fp = open(descname, 'r')
|
||||
except IOError:
|
||||
print 'Cannot open', descname
|
||||
return None
|
||||
line = fp.readline()
|
||||
yield = ''
|
||||
while line:
|
||||
yield = yield + line
|
||||
line = fp.readline()
|
||||
fp.close()
|
||||
return string.strip(yield)
|
||||
|
||||
def get_area_desc(areapath):
|
||||
descname = os.path.join(areapath, '.desc', '.desc')
|
||||
if not os.path.isfile(descname):
|
||||
return None
|
||||
try:
|
||||
fp = open(descname, 'r')
|
||||
except IOError:
|
||||
print 'Cannot open', descname
|
||||
return None
|
||||
line = fp.readline()
|
||||
yield = ''
|
||||
while line:
|
||||
yield = yield + line
|
||||
line = fp.readline()
|
||||
fp.close()
|
||||
return string.strip(yield)
|
||||
|
||||
class file:
|
||||
def stat(self):
|
||||
if self.fake:
|
||||
return
|
||||
try:
|
||||
statinfo = os.stat(self.fullname)
|
||||
self.size = statinfo[6]
|
||||
self.time = statinfo[8]
|
||||
except OSError:
|
||||
self.size = -1
|
||||
self.time = -1
|
||||
self.desc = 'File is not accessable'
|
||||
|
||||
def set(self, fullname, name = None, area = '', dlcnt = 0,\
|
||||
mode = '', desc = '', fake = 0):
|
||||
if name == None:
|
||||
self.name = os.path.split(fullname)[1]
|
||||
else:
|
||||
self.name = name
|
||||
self.fullname = fullname
|
||||
self.dlcnt = dlcnt
|
||||
self.size = -1
|
||||
self.time = -1
|
||||
self.area = area
|
||||
self.mode = mode
|
||||
self.desc = desc
|
||||
self.fake = fake
|
||||
|
||||
def reset(self):
|
||||
self.name = ''
|
||||
self.fullname = ''
|
||||
self.area = ''
|
||||
self.dlcnt = 0
|
||||
self.mode = ''
|
||||
self.desc = ''
|
||||
self.size = -1
|
||||
self.time = -1
|
||||
self.fake = 0
|
||||
|
||||
def __init__(self):
|
||||
self.reset()
|
||||
|
||||
class filebase:
|
||||
""" Index entry format: [fullname, area, dlcnt, accessmode, desc]
|
||||
"""
|
||||
def open(self, mode):
|
||||
self.db = gdbm.open(self.dbfile, mode)
|
||||
|
||||
def close(self):
|
||||
self.db.close()
|
||||
|
||||
def sync(self):
|
||||
self.db.sync()
|
||||
|
||||
def clean(self):
|
||||
for filename in self.db.keys():
|
||||
file = self.get(filename)
|
||||
if not os.path.isfile(file.fullname):
|
||||
print 'Remove file "%s" from index' % file.fullname
|
||||
del self.db[filename]
|
||||
|
||||
def get_all(self, filenames):
|
||||
""" Lookup files in the database and return list
|
||||
of file objects
|
||||
"""
|
||||
yield = []
|
||||
for name in filenames:
|
||||
files = self.get(name)
|
||||
if files and len(files) > 0:
|
||||
yield.extend(files)
|
||||
return yield
|
||||
|
||||
def get(self, filename):
|
||||
""" Lookup file by its name in the database and
|
||||
return list of file objects for this name
|
||||
"""
|
||||
yield = []
|
||||
if not self.db.has_key(filename):
|
||||
return None
|
||||
files_info = eval(self.db[filename])
|
||||
if files_info == None:
|
||||
newfile = file()
|
||||
newfile.set(filename, desc='File not found', fake=1)
|
||||
yield.append(newfile)
|
||||
else:
|
||||
for finfo in files_info:
|
||||
newfile = file()
|
||||
finfo = eval(finfo)
|
||||
newfile.set(finfo[0], area = finfo[1],\
|
||||
dlcnt = finfo[2], mode = finfo[3],\
|
||||
desc = finfo[4])
|
||||
yield.append(newfile)
|
||||
return yield
|
||||
|
||||
def put(self, file):
|
||||
finfo = []
|
||||
finfo.append(file.fullname)
|
||||
finfo.append(file.area)
|
||||
finfo.append(file.dlcnt)
|
||||
finfo.append(file.mode)
|
||||
finfo.append(file.desc)
|
||||
if self.db.has_key(file.name):
|
||||
files_info = eval(self.db[file.name])
|
||||
else:
|
||||
files_info = []
|
||||
files_info.append(repr(finfo))
|
||||
self.db[file.name] = repr(files_info)
|
||||
|
||||
def __init__(self, spooldir):
|
||||
self.dbfile = os.path.join(spooldir, 'filebase.db')
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
|
||||
import string
|
||||
import re
|
||||
import struct
|
||||
import time
|
||||
|
||||
#address_1 = re.compile('^\([0-9]+\):\([0-9]+\)/\([0-9]+\)\.?\([0-9]+\)?$')
|
||||
address_1 = re.compile('^(\d+):(\d+)/(\d+)\.?(\d+)?$')
|
||||
|
||||
months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',\
|
||||
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Jan')
|
||||
|
||||
class address:
|
||||
def is_set(self):
|
||||
if self.zone > 0 and self.net > 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def string(self):
|
||||
if self.invalid:
|
||||
yield = 'Invalid address'
|
||||
elif self.point > 0:
|
||||
yield = '%d:%d/%d.%d' % (self.zone, self.net, self.node, self.point)
|
||||
else:
|
||||
yield = '%d:%d/%d' % (self.zone, self.net, self.node)
|
||||
return yield
|
||||
|
||||
def parse(self, str):
|
||||
match = address_1.match(str)
|
||||
if match:
|
||||
try:
|
||||
self.zone = string.atoi(match.group(1))
|
||||
self.net = string.atoi(match.group(2))
|
||||
self.node = string.atoi(match.group(3))
|
||||
tmp = match.group(4)
|
||||
if tmp and tmp != '-1':
|
||||
self.point = string.atoi(tmp)
|
||||
else:
|
||||
self.point = 0
|
||||
self.invalid = 0
|
||||
except IndexError:
|
||||
self.__init__()
|
||||
return -1
|
||||
else:
|
||||
print "Regexp doesnt match!"
|
||||
return -1
|
||||
return 0
|
||||
|
||||
def __init__(self):
|
||||
self.zone = 0
|
||||
self.net = 0
|
||||
self.node = 0
|
||||
self.point = 0
|
||||
self.invalid = 1
|
||||
|
||||
class message:
|
||||
def newmsg(self, addr_from, user_from, addr_to, user_to, subject):
|
||||
self.unix_time = time.time()
|
||||
self.addr_orig = addr_from
|
||||
self.addr_dest = addr_to
|
||||
self.user_orig = user_from
|
||||
self.user_dest = user_to
|
||||
self.subject = subject
|
||||
self.msgbody = ''
|
||||
self.append_line('\001FMPT %d' % self.addr_orig.point)
|
||||
self.append_line('\001TOPT %d' % self.addr_dest.point)
|
||||
|
||||
def append_line(self, string):
|
||||
self.msgbody = self.msgbody + string + '\r'
|
||||
|
||||
def append_text(self, text):
|
||||
for line in string.split(text, '\n'):
|
||||
self.append_line(line)
|
||||
|
||||
def append_file(self, filename):
|
||||
try:
|
||||
fp = open(filename, 'r')
|
||||
except IOError:
|
||||
print 'Cannot append file', filename
|
||||
return
|
||||
line = fp.readline()
|
||||
while line:
|
||||
self.append_line(string.rstrip(line))
|
||||
line = fp.readline()
|
||||
fp.close()
|
||||
|
||||
def __init__(self):
|
||||
self.unix_time = 0
|
||||
self.addr_orig = address()
|
||||
self.addr_dest = address()
|
||||
self.user_orig = ''
|
||||
self.user_dest = ''
|
||||
self.subject = ''
|
||||
self.msgbody = ''
|
||||
self.origin = ''
|
||||
|
||||
class packet:
|
||||
def reset(self):
|
||||
self.addr_orig = address()
|
||||
self.addr_dest = address()
|
||||
self.password = ''
|
||||
self.messages = []
|
||||
|
||||
# TODO
|
||||
def read(self, filename):
|
||||
self.reset()
|
||||
fp = open(filename, "w")
|
||||
fp.close()
|
||||
|
||||
def get_time_string(self, unix_time):
|
||||
msgtime = time.localtime(unix_time)
|
||||
return '%02d %s %02d %02d:%02d:%02d' % \
|
||||
(msgtime[2], months[msgtime[1]], msgtime[0] % 100, \
|
||||
msgtime[3], msgtime[4], msgtime[5])
|
||||
|
||||
def get_message_header(self, message):
|
||||
return struct.pack('7H20s',\
|
||||
2,\
|
||||
message.addr_orig.node,\
|
||||
message.addr_dest.node,\
|
||||
message.addr_orig.net,\
|
||||
message.addr_dest.net,\
|
||||
0,\
|
||||
0,\
|
||||
self.get_time_string(message.unix_time)) + \
|
||||
message.user_dest[0:36] + '\0' + \
|
||||
message.user_orig[0:36] + '\0' + \
|
||||
message.subject[0:72] + '\0'
|
||||
|
||||
def get_packet_header(self):
|
||||
now = time.localtime(time.time())
|
||||
return struct.pack('13H8s12H',\
|
||||
self.addr_orig.node,\
|
||||
self.addr_dest.node,\
|
||||
now[0], # Year\
|
||||
now[1], # Month\
|
||||
now[2], # Day\
|
||||
now[3], # Hour\
|
||||
now[4], # Minute\
|
||||
now[5], # Second\
|
||||
9600, # Baud\
|
||||
2, # PKT type\
|
||||
self.addr_orig.net,\
|
||||
self.addr_dest.net,\
|
||||
254, # Prod. code + Rev. number\
|
||||
self.password,\
|
||||
self.addr_orig.zone,\
|
||||
self.addr_dest.zone,\
|
||||
0, # AuxNet\
|
||||
0, # CWvalidationCopy\
|
||||
0, # ProductCode + Revision \
|
||||
0, # CapabilWord\
|
||||
self.addr_orig.zone,\
|
||||
self.addr_dest.zone,\
|
||||
self.addr_orig.point,\
|
||||
self.addr_dest.point,\
|
||||
0,
|
||||
0)
|
||||
|
||||
def write(self, filename):
|
||||
fp = open(filename, "w")
|
||||
fp.write(self.get_packet_header())
|
||||
|
||||
for msg in self.messages:
|
||||
fp.write(self.get_message_header(msg))
|
||||
fp.write(msg.msgbody)
|
||||
fp.write('\0')
|
||||
|
||||
fp.write('\0\0')
|
||||
fp.close()
|
||||
|
||||
def add_message(self, message):
|
||||
self.messages.append(message)
|
||||
|
||||
def __init__(self):
|
||||
self.reset()
|
||||
|
||||
if __name__ == "__main__":
|
||||
tmp = address()
|
||||
tmp.parse('2:5020/2120')
|
||||
print tmp.string()
|
||||
@@ -0,0 +1,102 @@
|
||||
import time
|
||||
import gdbm
|
||||
import ufido
|
||||
|
||||
class nodestat:
|
||||
""" [[month_id, month_size, month_num, month_time],
|
||||
[week_id, seek_size, week_num, week_time],
|
||||
[day_id, day_size, day_num, day_time],
|
||||
[total_size, total_num, total_time]]
|
||||
"""
|
||||
def __init__(self, dbpath, address):
|
||||
self.addr = address
|
||||
self.key = address.string()
|
||||
self.stat_session_size = 0
|
||||
self.stat_session_num = 0
|
||||
self.stat_session_time = 0
|
||||
self.stat_day_size = 0
|
||||
self.stat_day_num = 0
|
||||
self.stat_day_time = 0
|
||||
self.stat_week_size = 0
|
||||
self.stat_week_num = 0
|
||||
self.stat_week_time = 0
|
||||
self.stat_month_size = 0
|
||||
self.stat_month_num = 0
|
||||
self.stat_month_time = 0
|
||||
self.stat_total_size = 0
|
||||
self.stat_total_num = 0
|
||||
self.stat_total_time = 0
|
||||
self.dbpath = dbpath
|
||||
tt = time.localtime()
|
||||
self.month_id = time.strftime('%Y%m', tt)
|
||||
self.week_id = time.strftime('%Y%W', tt)
|
||||
self.day_id = time.strftime('%Y%j', tt)
|
||||
self.notexist = 0 # Entry for this node doesn't exist yet?
|
||||
|
||||
def upd_stat(self, num, size):
|
||||
self.stat_session_size = self.stat_session_size + size
|
||||
self.stat_session_num = self.stat_session_num + num
|
||||
self.stat_month_size = self.stat_month_size + size
|
||||
self.stat_month_num = self.stat_month_num + num
|
||||
self.stat_week_size = self.stat_week_size + size
|
||||
self.stat_week_num = self.stat_week_num + num
|
||||
self.stat_day_size = self.stat_day_size + size
|
||||
self.stat_day_num = self.stat_day_num + num
|
||||
self.stat_total_size = self.stat_total_size + size
|
||||
self.stat_total_num = self.stat_total_num + num
|
||||
|
||||
def get_stat(self):
|
||||
try:
|
||||
db = gdbm.open(self.dbpath, 'r')
|
||||
except gdbm.error:
|
||||
return 0
|
||||
if not db.has_key(self.key):
|
||||
self.notexist = 1
|
||||
db.close()
|
||||
return 0
|
||||
entry = eval(db[self.key])
|
||||
# Check month statistic
|
||||
if entry[0][0] == self.month_id:
|
||||
self.stat_month_size = entry[0][1]
|
||||
self.stat_month_num = entry[0][2]
|
||||
self.stat_month_time = entry[0][3]
|
||||
# Check week statistic
|
||||
if entry[1][0] == self.week_id:
|
||||
self.stat_week_size = entry[1][1]
|
||||
self.stat_week_num = entry[1][2]
|
||||
self.stat_week_time = entry[1][3]
|
||||
# Check day statistic
|
||||
if entry[2][0] == self.day_id:
|
||||
self.stat_day_size = entry[2][1]
|
||||
self.stat_day_num = entry[2][2]
|
||||
self.stat_day_time = entry[2][3]
|
||||
# Get total statistic
|
||||
self.stat_total_size = entry[3][0]
|
||||
self.stat_total_num = entry[3][1]
|
||||
self.stat_total_time = entry[3][2]
|
||||
db.close()
|
||||
return 0
|
||||
|
||||
def put_stat(self):
|
||||
db = gdbm.open(self.dbpath, 'cf')
|
||||
# Don't handle exceptions
|
||||
entry = [[self.month_id, self.stat_month_size, self.stat_month_num, self.stat_month_time],
|
||||
[self.week_id, self.stat_week_size, self.stat_week_num, self.stat_week_time],
|
||||
[self.day_id, self.stat_day_size, self.stat_day_num, self.stat_day_time],
|
||||
[self.stat_total_size, self.stat_total_num, self.stat_total_time]]
|
||||
db[self.key] = repr(entry)
|
||||
db.close()
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
addr = ufido.address()
|
||||
addr.parse('2:5020/2120')
|
||||
ns = nodestat('./tmp.db', addr)
|
||||
ns.upd_stat(2, 32768)
|
||||
ns.put_stat()
|
||||
addr2 = ufido.address()
|
||||
addr2.parse('2:5020/2120')
|
||||
ns2 = nodestat('./tmp.db', addr2)
|
||||
ns2.get_stat()
|
||||
print ns2.stat_total_num, ns2.stat_total_size
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
import string
|
||||
|
||||
class template:
|
||||
def __init__(self):
|
||||
self.local_address = ''
|
||||
self.local_sysop = ''
|
||||
self.local_location = ''
|
||||
self.local_phone = ''
|
||||
self.remote_address = ''
|
||||
self.remote_sysop = ''
|
||||
self.remote_location = ''
|
||||
self.remote_phone = ''
|
||||
self.remote_cid = ''
|
||||
self.limit_size_day = -1
|
||||
self.limit_size_week = -1
|
||||
self.limit_size_month = -1
|
||||
self.sent_size_day = -1
|
||||
self.sent_size_week = -1
|
||||
self.sent_size_month = -1
|
||||
self.sent_size = -1
|
||||
self.conn_speed = -1
|
||||
self.text = None
|
||||
|
||||
def set(self, srif=None, conf=None, nodestat=None):
|
||||
if srif:
|
||||
self.remote_address = srif.aka.string()
|
||||
self.remote_sysop = srif.sysop
|
||||
self.remote_location = srif.site
|
||||
self.remote_cid = srif.callerid
|
||||
self.conn_speed = srif.baud
|
||||
if conf:
|
||||
self.local_address = conf.local_address.string()
|
||||
self.limit_size_day = conf.limit_size_day
|
||||
self.limit_size_week = conf.limit_size_week
|
||||
self.limit_size_month = conf.limit_size_month
|
||||
if nodestat:
|
||||
self.sent_session_size = nodestat.stat_session_size
|
||||
self.sent_session_num = nodestat.stat_session_num
|
||||
self.sent_day_size = nodestat.stat_day_size
|
||||
self.sent_day_num = nodestat.stat_day_num
|
||||
self.sent_week_size = nodestat.stat_week_size
|
||||
self.sent_week_num = nodestat.stat_week_num
|
||||
self.sent_month_size = nodestat.stat_month_size
|
||||
self.sent_month_num = nodestat.stat_month_num
|
||||
self.sent_total_size = nodestat.stat_total_size
|
||||
self.sent_total_num = nodestat.stat_total_num
|
||||
|
||||
def __cmd__(self, str):
|
||||
try:
|
||||
[fmt, arg] = string.split(str, ',', 1)
|
||||
return eval('"' + fmt + '" % self.' + arg)
|
||||
except ValueError:
|
||||
return '@ValueError@'
|
||||
except AttributeError:
|
||||
return '@AttributeError@'
|
||||
|
||||
def process(self, text=None):
|
||||
if text == None:
|
||||
text = self.text
|
||||
if text == None:
|
||||
return None
|
||||
pos = 0
|
||||
while 1:
|
||||
pos = string.find(text, '@', pos)
|
||||
if pos < 0:
|
||||
break
|
||||
end_pos = string.find(text, '@', pos+1)
|
||||
if end_pos < 0:
|
||||
break
|
||||
if end_pos - pos > 1:
|
||||
# Process escaped command
|
||||
replace = self.__cmd__(text[pos+1:end_pos])
|
||||
if replace:
|
||||
text = text[:pos]+replace+text[end_pos+1:]
|
||||
# Fix the current position
|
||||
pos = end_pos + len(replace)-(end_pos-pos+1)
|
||||
else:
|
||||
# Leave text untouched
|
||||
pos = end_pos + 1
|
||||
else:
|
||||
# Replace '@@' by the single '@'
|
||||
text = text[:pos+1]+text[pos+2:]
|
||||
pos = end_pos
|
||||
return text
|
||||
|
||||
def readfile(self, path):
|
||||
try:
|
||||
fp = open(path, 'r')
|
||||
self.text = fp.read()
|
||||
fp.close()
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
test = template()
|
||||
print test.process("'@@'\n'@@'\n'@%d,conn_speed@'\n'@@@'")
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
import string
|
||||
|
||||
# Header for the files information
|
||||
file_info_header = 'File Size Description\n'\
|
||||
+ '-' * 78
|
||||
|
||||
class ULog:
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
self.fp = open(path, 'a')
|
||||
|
||||
def puts(self, string):
|
||||
fp.puts(strftime('%b %d %H:%M:%S ', gmtime())+string)
|
||||
|
||||
def close(self):
|
||||
fp.close()
|
||||
|
||||
def format_desc(desc, offset, width=78):
|
||||
""" Format file's description
|
||||
"""
|
||||
yield = ''
|
||||
desc = string.expandtabs(desc, 1)
|
||||
for line in string.split(desc, '\n'):
|
||||
line = string.rstrip(line)
|
||||
if line == '':
|
||||
continue
|
||||
pos = 0
|
||||
endpos = width
|
||||
while line[pos:endpos]:
|
||||
if yield:
|
||||
yield = yield + '\n'
|
||||
yield = yield + offset * ' '
|
||||
yield = yield + line[pos:endpos]
|
||||
pos = endpos
|
||||
endpos = endpos + width
|
||||
return yield
|
||||
|
||||
def format_file_info(name, size, desc, line_length=78):
|
||||
""" Format file information to meet human requirements
|
||||
"""
|
||||
if size < 0:
|
||||
yield = '%-20s ' % name + 11 * ' '
|
||||
else:
|
||||
yield = '%-20s %-11d' % (name, size)
|
||||
if desc:
|
||||
offset = len(yield) + 1
|
||||
width = line_length - offset
|
||||
desc = format_desc(desc, offset, width)
|
||||
yield = yield + ' ' + string.lstrip(desc)
|
||||
else:
|
||||
yield = yield + ' Description not available'
|
||||
return yield
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys
|
||||
import posix
|
||||
import os
|
||||
import libconf
|
||||
import libfbase
|
||||
|
||||
USRIF_CONFIG = '/usr/local/etc/u-srif/u-srif.conf'
|
||||
|
||||
##############################
|
||||
# The main program starts here
|
||||
|
||||
# Read configuration
|
||||
Conf = libconf.config(USRIF_CONFIG)
|
||||
|
||||
# Open files index for writing
|
||||
FBase = libfbase.filebase(Conf.spool_dir)
|
||||
FBase.open('cwf')
|
||||
|
||||
file = libfbase.file()
|
||||
|
||||
# Process aliases from 'alias-list-file'
|
||||
for alias in Conf.read_alias_list():
|
||||
print 'Processing alias "%s": %s' % (alias.name, alias.filename)
|
||||
file_desc = libfbase.get_file_desc(alias.filename)
|
||||
file.set(alias.filename, name = alias.name, desc = file_desc)
|
||||
file.stat()
|
||||
FBase.put(file)
|
||||
|
||||
# Process dirs from 'dir-list-file'
|
||||
for dir in Conf.read_dir_list():
|
||||
area_desc = libfbase.get_area_desc(dir)
|
||||
print 'Processing: %s (%s)' % (dir, area_desc)
|
||||
files_list = posix.listdir(dir)
|
||||
for file_name in files_list:
|
||||
full_name = os.path.join(dir, file_name)
|
||||
if os.path.isfile(full_name):
|
||||
file_desc = libfbase.get_file_desc(full_name)
|
||||
file.set(full_name, area = area_desc, desc = file_desc)
|
||||
file.stat()
|
||||
FBase.put(file)
|
||||
|
||||
# Purge files index
|
||||
#print 'Purging removed files from files index'
|
||||
#FBase.clean()
|
||||
|
||||
FBase.close()
|
||||
sys.exit(0)
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#!/usr/local/bin/python
|
||||
|
||||
import sys
|
||||
|
||||
# Our own libraries
|
||||
sys.path.append('./lib')
|
||||
import uconfig
|
||||
import udbase
|
||||
from uutil import *
|
||||
|
||||
USRIF_CONFIG = '/usr/local/etc/u-srif/u-srif.conf'
|
||||
|
||||
##############################
|
||||
# The main program starts here
|
||||
if len(sys.argv) < 2:
|
||||
print 'usage:', sys.argv[0], '<[file] [file] ..>'
|
||||
sys.exit(1)
|
||||
|
||||
# Read configuration
|
||||
Conf = uconfig.Config(USRIF_CONFIG)
|
||||
|
||||
# Lookup files in the database
|
||||
FBase = udbase.filebase(Conf.spool_dir)
|
||||
FBase.open('r')
|
||||
yield = FBase.get_all(sys.argv[1:])
|
||||
FBase.close()
|
||||
|
||||
# Pretty printing
|
||||
print file_info_header
|
||||
for file in yield:
|
||||
file.stat()
|
||||
print format_file_info(file.name, file.size, file.desc)
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
#!/usr/local/bin/python
|
||||
|
||||
import string
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Our own libraries
|
||||
sys.path.append('./lib')
|
||||
import uconfig
|
||||
import udbase
|
||||
import ufido
|
||||
import utmpl
|
||||
import unodestat
|
||||
from uutil import *
|
||||
|
||||
USRIF_CONFIG = '/usr/local/etc/u-srif/u-srif.conf'
|
||||
|
||||
class freq_report(ufido.message):
|
||||
def write_packet(self, pktname):
|
||||
self.packet.addr_orig = self.addr_orig
|
||||
self.packet.addr_dest = self.addr_dest
|
||||
self.packet.write(pktname)
|
||||
|
||||
def add_file(self, name, size, desc):
|
||||
text = format_file_info(name, size, desc)
|
||||
self.append_text(text)
|
||||
|
||||
def __init__(self):
|
||||
ufido.message.__init__(self)
|
||||
self.packet = ufido.packet()
|
||||
self.packet.add_message(self)
|
||||
|
||||
class srif_file:
|
||||
def read_req_list(self):
|
||||
yield = []
|
||||
fp = open(self.requestlist, 'r')
|
||||
line = fp.readline()
|
||||
while line:
|
||||
line = string.strip(line)
|
||||
yield.append(line)
|
||||
line = fp.readline()
|
||||
fp.close()
|
||||
return yield
|
||||
|
||||
def write_resp_list(self, list):
|
||||
fp = open(self.responselist, 'w')
|
||||
for file in list:
|
||||
fp.write('+' + file + '\n')
|
||||
fp.close()
|
||||
|
||||
def read(self, name):
|
||||
fp = open(name, 'r')
|
||||
line = fp.readline()
|
||||
while line:
|
||||
line = string.strip(line)
|
||||
args = string.split(line, None, 1)
|
||||
if len(args) == 2:
|
||||
if string.lower(args[0]) == 'sysop':
|
||||
self.sysop = args[1]
|
||||
if string.lower(args[0]) == 'aka':
|
||||
self.aka.parse(args[1])
|
||||
elif string.lower(args[0]) == 'baud':
|
||||
self.baud = args[1]
|
||||
elif string.lower(args[0]) == 'requestlist':
|
||||
self.requestlist = args[1]
|
||||
elif string.lower(args[0]) == 'responselist':
|
||||
self.responselist = args[1]
|
||||
elif string.lower(args[0]) == 'remotestatus':
|
||||
self.remotestatus = args[1]
|
||||
elif string.lower(args[0]) == 'systemstatus':
|
||||
self.systemstatus = args[1]
|
||||
elif string.lower(args[0]) == 'site':
|
||||
self.site = args[1]
|
||||
elif string.lower(args[0]) == 'callerid':
|
||||
self.callerid = args[1]
|
||||
elif string.lower(args[0]) == 'password':
|
||||
self.password = args[1]
|
||||
else:
|
||||
print "skipping keyword", args[0], "in SRIF"
|
||||
line = fp.readline()
|
||||
fp.close()
|
||||
|
||||
def __init__(self, name):
|
||||
self.sysop = ''
|
||||
self.aka = ufido.address()
|
||||
self.baud = 0
|
||||
self.requestlist = ''
|
||||
self.responselist = ''
|
||||
self.remotestatus = ''
|
||||
self.systemstatus = ''
|
||||
self.site = ''
|
||||
self.callerid = ''
|
||||
self.password = ''
|
||||
self.read(name)
|
||||
|
||||
def remote_addr(self):
|
||||
return self.aka
|
||||
|
||||
def isprotected(self):
|
||||
if string.lower(self.remotestatus) == 'protected':
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def islisted(self):
|
||||
if string.lower(self.systemstatus) == 'listed':
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def append_new_file(fileslist, file):
|
||||
TotalFiles = TotalFiles + 1
|
||||
TotalSize = TotalSize + file.size
|
||||
fileslist.append(file.fullname)
|
||||
|
||||
##############################
|
||||
# The main program starts here
|
||||
|
||||
# Global variables
|
||||
yield_list = []
|
||||
|
||||
if len(sys.argv) <> 2:
|
||||
print 'usage: u-srif <srif file name>'
|
||||
sys.exit(1)
|
||||
|
||||
# Read configuration
|
||||
conf = uconfig.Config(USRIF_CONFIG)
|
||||
# Read SRIF files
|
||||
srif = srif_file(sys.argv[1])
|
||||
# Read node's statistic
|
||||
nodestat = unodestat.nodestat(conf.stat_dbase, srif.aka)
|
||||
nodestat.get_stat()
|
||||
|
||||
# Lookup requested files in the our database
|
||||
FBase = udbase.filebase(conf.spool_dir)
|
||||
FBase.open('r')
|
||||
yield = FBase.get_all(srif.read_req_list())
|
||||
FBase.close()
|
||||
|
||||
# Prepare found files for sending
|
||||
for file in yield:
|
||||
if not file.fake:
|
||||
file.stat()
|
||||
nodestat.upd_stat(1, file.size)
|
||||
yield_list.append(file.fullname)
|
||||
|
||||
# Store node's statistic
|
||||
nodestat.put_stat()
|
||||
|
||||
# Send FREQ report?
|
||||
if conf.send_report:
|
||||
# Prepare templates object
|
||||
tmpl = utmpl.template()
|
||||
tmpl.set(srif=srif, conf=conf, nodestat=nodestat)
|
||||
# Setup report object
|
||||
report = freq_report()
|
||||
report.newmsg(conf.local_address, conf.report_from, \
|
||||
srif.aka, srif.sysop, conf.report_subj)
|
||||
report.append_line('')
|
||||
# Append header
|
||||
tmpl.readfile(conf.report_header)
|
||||
text = tmpl.process()
|
||||
if text:
|
||||
report.append_text(text)
|
||||
# Append per files statistic
|
||||
for file in yield:
|
||||
report.add_file(file.name, file.size, file.desc)
|
||||
# Append footer
|
||||
tmpl.readfile(conf.report_footer)
|
||||
text = tmpl.process()
|
||||
if text:
|
||||
report.append_text(text)
|
||||
# Add empty line to the report
|
||||
report.append_line('')
|
||||
# Create netmail packet with the FREQ report
|
||||
pktname = '/var/tmp/12345678.pkt' # XXX
|
||||
report.write_packet(pktname)
|
||||
# Add packet file to the response files list
|
||||
yield_list.append(pktname)
|
||||
|
||||
# Dump reponse list
|
||||
srif.write_resp_list(yield_list)
|
||||
sys.exit(0)
|
||||
|
||||
Reference in New Issue
Block a user