diff options
Diffstat (limited to 'debian')
-rw-r--r-- | debian/patches/0100-new_syslog_format.patch | 2 | ||||
-rw-r--r-- | debian/patches/0100-new_syslog_format.patch~ | 1239 |
2 files changed, 1240 insertions, 1 deletions
diff --git a/debian/patches/0100-new_syslog_format.patch b/debian/patches/0100-new_syslog_format.patch index 5344f07..f3fc9a0 100644 --- a/debian/patches/0100-new_syslog_format.patch +++ b/debian/patches/0100-new_syslog_format.patch @@ -71,7 +71,7 @@ Index: trunk/mailgraph.pl + $self->{year}=$year; + } + else { -+ my($montxt, $mon); ++ my($montxt); + ($montxt, $day, $hour, $min, $sec, $host, $text) = $str =~ /^ + (\S{3})\s+(\d+) # date + \s diff --git a/debian/patches/0100-new_syslog_format.patch~ b/debian/patches/0100-new_syslog_format.patch~ new file mode 100644 index 0000000..5344f07 --- /dev/null +++ b/debian/patches/0100-new_syslog_format.patch~ @@ -0,0 +1,1239 @@ +Description: Add new syslog format +Author: M.D. Klapwijk +Origin: https://gist.github.com/mdklapwijk/4f8d2fc39f09f4aa615cbf8ffae0379a +Bug: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1051496 +Forwarded: not-needed +Last-Update: 2023-09-23 +--- +This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ +Index: trunk/mailgraph.pl +=================================================================== +--- trunk.orig/mailgraph.pl ++++ trunk/mailgraph.pl +@@ -5,6 +5,10 @@ + # copyright (c) 2000-2007 David Schweikert <david@schweikert.ch> + # released under the GNU General Public License + ++# modifications to handle rsyslog high precision format ++# copyright (c) 2018 by M.D. Klapwijk ++# released under the GNU General Public License ++ + ######## Parse::Syslog 1.09 (automatically embedded) ######## + package Parse::Syslog; + use Carp; +@@ -85,7 +89,7 @@ sub str2time($$$$$$$$) + # - compensate if yes + # note that we assume that the DST-switch goes like this: + # time 1:00 1:30 2:00 2:30 2:00 2:30 3:00 3:30 +- # stamp 1 2 3 4 3 3 7 8 ++ # stamp 1 2 3 4 3 3 7 8 + # comp. 0 0 0 0 2 2 0 0 + # result 1 2 3 4 5 6 7 8 + # old Time::Local versions behave differently (1 2 5 6 5 6 7 8) +@@ -202,27 +206,46 @@ sub _next_syslog($) + } + my $file = $self->{file}; + line: while(defined (my $str = $self->_next_line)) { +- # date, time and host +- $str =~ /^ +- (\S{3})\s+(\d+) # date -- 1, 2 +- \s +- (\d+):(\d+):(\d+) # time -- 3, 4, 5 +- (?:\s<\w+\.\w+>)? # FreeBSD's verbose-mode +- \s +- ([-\w\.\@:]+) # host -- 6 +- \s+ +- (?:\[LOG_[A-Z]+\]\s+)? # FreeBSD +- (.*) # text -- 7 +- $/x or do +- { +- warn "WARNING: line not in syslog format: $str"; +- next line; +- }; +- my $mon = $months_map{$1}; +- defined $mon or croak "unknown month $1\n"; +- $self->_year_increment($mon); ++ # date, time and host ++ my ($year, $mon, $day, $hour, $min, $sec, $host, $text); ++ if($self->{type} eq 'rsyslog') { ++ ($year, $mon, $day, $hour, $min, $sec, $host, $text) = $str =~ /^ ++ (\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+)\S+ # datetime ++ \s+ ++ (\S+) # host ++ \s+ ++ (.*) # text ++ $/x or do ++ { ++ warn "WARNING: line not in high precision rsyslog format: $str"; ++ next line; ++ }; ++ $mon--; ++ $self->{year}=$year; ++ } ++ else { ++ my($montxt, $mon); ++ ($montxt, $day, $hour, $min, $sec, $host, $text) = $str =~ /^ ++ (\S{3})\s+(\d+) # date ++ \s ++ (\d+):(\d+):(\d+) # time ++ (?:\s<\w+\.\w+>)? # FreeBSD's verbose-mode ++ \s ++ ([-\w\.\@:]+) # host ++ \s+ ++ (?:\[LOG_[A-Z]+\]\s+)? # FreeBSD ++ (.*) # text ++ $/x or do ++ { ++ warn "WARNING: line not in syslog format: $str"; ++ next line; ++ }; ++ $mon = $months_map{$montxt}; ++ defined $mon or croak "unknown month $montxt\n"; ++ $self->_year_increment($mon); ++ } + # convert to unix time +- my $time = $self->str2time($5,$4,$3,$2,$mon,$self->{year}-1900,$self->{GMT}); ++ my $time = $self->str2time($sec,$min,$hour,$day,$mon,$self->{year}-1900,$self->{GMT}); + if(not $self->{allow_future}) { + # accept maximum one day in the present future + if($time - time > 86400) { +@@ -230,7 +253,6 @@ sub _next_syslog($) + next line; + } + } +- my ($host, $text) = ($6, $7); + # last message repeated ... times + if($text =~ /^(?:last message repeated|above message repeats) (\d+) time/) { + next line if defined $self->{repeat} and not $self->{repeat}; +@@ -264,11 +286,11 @@ sub _next_syslog($) + }; + if($self->{arrayref}) { + $self->{_last_data}{$host} = [ +- $time, # 0: timestamp +- $host, # 1: host +- $1, # 2: program +- $2, # 3: pid +- $6, # 4: text ++ $time, # 0: timestamp ++ $host, # 1: host ++ $1, # 2: program ++ $2, # 3: pid ++ $6, # 4: text + ]; + } + else { +@@ -292,12 +314,12 @@ sub _next_metalog($) + my ($self) = @_; + my $file = $self->{file}; + line: while(my $str = $self->_next_line) { +- # date, time and host +- $str =~ /^ ++ # date, time and host ++ $str =~ /^ + (\S{3})\s+(\d+) # date -- 1, 2 + \s + (\d+):(\d+):(\d+) # time -- 3, 4, 5 +- # host is not logged ++ # host is not logged + \s+ + (.*) # text -- 6 + $/x or do +@@ -310,22 +332,22 @@ sub _next_metalog($) + $self->_year_increment($mon); + # convert to unix time + my $time = $self->str2time($5,$4,$3,$2,$mon,$self->{year}-1900,$self->{GMT}); +- my $text = $6; ++ my $text = $6; + $text =~ /^ + \[(.*?)\] # program -- 1 +- # no PID +- \s+ ++ # no PID ++ \s+ + (.*) # text -- 2 + $/x or do + { +- warn "WARNING: text line not in metalog format: $text ($str)"; ++ warn "WARNING: text line not in metalog format: $text ($str)"; + next line; + }; + if($self->{arrayref}) { + return [ +- $time, # 0: timestamp +- 'localhost', # 1: host +- $1, # 2: program ++ $time, # 0: timestamp ++ 'localhost', # 1: host ++ $1, # 2: program + undef, # 3: (no) pid + $2, # 4: text + ]; +@@ -344,7 +366,7 @@ sub _next_metalog($) + sub next($) + { + my ($self) = @_; +- if($self->{type} eq 'syslog') { ++ if($self->{type} eq 'syslog' || $self->{type} eq 'rsyslog') { + return $self->_next_syslog(); + } + elsif($self->{type} eq 'metalog') { +@@ -373,15 +395,16 @@ my $points_per_sample = 3; + + my $daemon_logfile = '/var/log/mailgraph.log'; + my $daemon_pidfile = '/var/run/mailgraph.pid'; +-my $daemon_rrd_dir = '/var/log'; ++my $daemon_rrd_dir = '/var/lib/mailgraph'; + + # global variables + my $logfile; + my $rrd = "mailgraph.rrd"; + my $rrd_virus = "mailgraph_virus.rrd"; ++my $rrd_greylist = "mailgraph_greylist.rrd"; + my $year; + my $this_minute; +-my %sum = ( sent => 0, received => 0, bounced => 0, rejected => 0, virus => 0, spam => 0 ); ++my %sum = ( sent => 0, received => 0, bounced => 0, rejected => 0, virus => 0, spam => 0, greylisted => 0, delayed => 0); + my $rrd_inited=0; + + my %opt = (); +@@ -395,499 +418,550 @@ sub event_bounced($); + sub event_rejected($); + sub event_virus($); + sub event_spam($); ++sub event_greylisted($); ++sub event_delayed($); + sub init_rrd($); + sub update($); + + sub usage + { +- print "usage: mailgraph [*options*]\n\n"; +- print " -h, --help display this help and exit\n"; +- print " -v, --verbose be verbose about what you do\n"; +- print " -V, --version output version information and exit\n"; +- print " -c, --cat causes the logfile to be only read and not monitored\n"; +- print " -l, --logfile f monitor logfile f instead of /var/log/syslog\n"; +- print " -t, --logtype t set logfile's type (default: syslog)\n"; +- print " -y, --year starting year of the log file (default: current year)\n"; +- print " --host=HOST use only entries for HOST (regexp) in syslog\n"; +- print " -d, --daemon start in the background\n"; +- print " --daemon-pid=FILE write PID to FILE instead of /var/run/mailgraph.pid\n"; +- print " --daemon-rrd=DIR write RRDs to DIR instead of /var/log\n"; +- print " --daemon-log=FILE write verbose-log to FILE instead of /var/log/mailgraph.log\n"; +- print " --ignore-localhost ignore mail to/from localhost (used for virus scanner)\n"; +- print " --ignore-host=HOST ignore mail to/from HOST regexp (used for virus scanner)\n"; +- print " --only-mail-rrd update only the mail rrd\n"; +- print " --only-virus-rrd update only the virus rrd\n"; +- print " --rrd-name=NAME use NAME.rrd and NAME_virus.rrd for the rrd files\n"; +- print " --rbl-is-spam count rbl rejects as spam\n"; +- print " --virbl-is-virus count virbl rejects as viruses\n"; ++ print "usage: mailgraph [*options*]\n\n"; ++ print " -h, --help display this help and exit\n"; ++ print " -v, --verbose be verbose about what you do\n"; ++ print " -V, --version output version information and exit\n"; ++ print " -c, --cat causes the logfile to be only read and not monitored\n"; ++ print " -l, --logfile f monitor logfile f instead of /var/log/syslog\n"; ++ print " -t, --logtype t set logfile's type (default: syslog)\n"; ++ print " -y, --year starting year of the log file (default: current year)\n"; ++ print " --host=HOST use only entries for HOST (regexp) in syslog\n"; ++ print " -d, --daemon start in the background\n"; ++ print " --daemon-pid=FILE write PID to FILE instead of /var/run/mailgraph.pid\n"; ++ print " --daemon-rrd=DIR write RRDs to DIR instead of /var/lib/mailgraph\n"; ++ print " --daemon-log=FILE write verbose-log to FILE instead of /var/log/mailgraph.log\n"; ++ print " --ignore-localhost ignore mail to/from localhost (used for virus scanner)\n"; ++ print " --ignore-host=HOST ignore mail to/from HOST regexp (used for virus scanner)\n"; ++ print " --no-mail-rrd no update mail rrd\n"; ++ print " --no-virus-rrd no update virus rrd\n"; ++ print " --no-greylist-rrd no update greylist rrd\n"; ++ print " --rrd-name=NAME use NAME.rrd and NAME_virus.rrd for the rrd files\n"; ++ print " --rbl-is-spam count rbl rejects as spam\n"; ++ print " --virbl-is-virus count virbl rejects as viruses\n"; + +- exit; ++ exit; + } + + sub main + { +- Getopt::Long::Configure('no_ignore_case'); +- GetOptions(\%opt, 'help|h', 'cat|c', 'logfile|l=s', 'logtype|t=s', 'version|V', +- 'year|y=i', 'host=s', 'verbose|v', 'daemon|d!', +- 'daemon_pid|daemon-pid=s', 'daemon_rrd|daemon-rrd=s', +- 'daemon_log|daemon-log=s', 'ignore-localhost!', 'ignore-host=s@', +- 'only-mail-rrd', 'only-virus-rrd', 'rrd_name|rrd-name=s', +- 'rbl-is-spam', 'virbl-is-virus' +- ) or exit(1); +- usage if $opt{help}; +- +- if($opt{version}) { +- print "mailgraph $VERSION by david\@schweikert.ch\n"; +- exit; +- } +- +- $daemon_pidfile = $opt{daemon_pid} if defined $opt{daemon_pid}; +- $daemon_logfile = $opt{daemon_log} if defined $opt{daemon_log}; +- $daemon_rrd_dir = $opt{daemon_rrd} if defined $opt{daemon_rrd}; +- $rrd = $opt{rrd_name}.".rrd" if defined $opt{rrd_name}; +- $rrd_virus = $opt{rrd_name}."_virus.rrd" if defined $opt{rrd_name}; +- +- # compile --ignore-host regexps +- if(defined $opt{'ignore-host'}) { +- for my $ih (@{$opt{'ignore-host'}}) { +- push @{$opt{'ignore-host-re'}}, qr{\brelay=[^\s,]*$ih}i; +- } +- } +- +- if($opt{daemon} or $opt{daemon_rrd}) { +- chdir $daemon_rrd_dir or die "mailgraph: can't chdir to $daemon_rrd_dir: $!"; +- -w $daemon_rrd_dir or die "mailgraph: can't write to $daemon_rrd_dir\n"; +- } +- +- daemonize if $opt{daemon}; +- +- my $logfile = defined $opt{logfile} ? $opt{logfile} : '/var/log/syslog'; +- my $file; +- if($opt{cat}) { +- $file = $logfile; +- } +- else { +- $file = File::Tail->new(name=>$logfile, tail=>-1); +- } +- my $parser = new Parse::Syslog($file, year => $opt{year}, arrayref => 1, +- type => defined $opt{logtype} ? $opt{logtype} : 'syslog'); +- +- if(not defined $opt{host}) { +- while(my $sl = $parser->next) { +- process_line($sl); +- } +- } +- else { +- my $host = qr/^$opt{host}$/i; +- while(my $sl = $parser->next) { +- process_line($sl) if $sl->[1] =~ $host; +- } +- } ++ Getopt::Long::Configure('no_ignore_case'); ++ GetOptions(\%opt, 'help|h', 'cat|c', 'logfile|l=s', 'logtype|t=s', 'version|V', ++ 'year|y=i', 'host=s', 'verbose|v', 'daemon|d!', ++ 'daemon_pid|daemon-pid=s', 'daemon_rrd|daemon-rrd=s', ++ 'daemon_log|daemon-log=s', 'ignore-localhost!', 'ignore-host=s@', ++ 'no-mail-rrd', 'no-virus-rrd', 'no-greylist-rrd', 'rrd_name|rrd-name=s', ++ 'rbl-is-spam', 'virbl-is-virus' ++ ) or exit(1); ++ usage if $opt{help}; ++ ++ if($opt{version}) { ++ print "mailgraph $VERSION by david\@schweikert.ch\n"; ++ exit; ++ } ++ ++ $daemon_pidfile = $opt{daemon_pid} if defined $opt{daemon_pid}; ++ $daemon_logfile = $opt{daemon_log} if defined $opt{daemon_log}; ++ $daemon_rrd_dir = $opt{daemon_rrd} if defined $opt{daemon_rrd}; ++ $rrd = $opt{rrd_name}.".rrd" if defined $opt{rrd_name}; ++ $rrd_virus = $opt{rrd_name}."_virus.rrd" if defined $opt{rrd_name}; ++ $rrd_greylist = $opt{rrd_name}."_greylist.rrd" if defined $opt{rrd_name}; ++ ++ # compile --ignore-host regexps ++ if(defined $opt{'ignore-host'}) { ++ for my $ih (@{$opt{'ignore-host'}}) { ++ push @{$opt{'ignore-host-re'}}, qr{\brelay=[^\s,]*$ih}i; ++ } ++ } ++ ++ if($opt{daemon} or $opt{daemon_rrd}) { ++ chdir $daemon_rrd_dir or die "mailgraph: can't chdir to $daemon_rrd_dir: $!"; ++ -w $daemon_rrd_dir or die "mailgraph: can't write to $daemon_rrd_dir\n"; ++ } ++ ++ daemonize if $opt{daemon}; ++ ++ my $logfile = defined $opt{logfile} ? $opt{logfile} : '/var/log/syslog'; ++ my $file; ++ if($opt{cat}) { ++ $file = $logfile; ++ } ++ else { ++ $file = File::Tail->new(name=>$logfile, tail=>-1); ++ } ++ my $parser = new Parse::Syslog($file, year => $opt{year}, arrayref => 1, ++ type => defined $opt{logtype} ? $opt{logtype} : 'syslog'); ++ ++ if(not defined $opt{host}) { ++ while(my $sl = $parser->next) { ++ process_line($sl); ++ } ++ } ++ else { ++ my $host = qr/^$opt{host}$/i; ++ while(my $sl = $parser->next) { ++ process_line($sl) if $sl->[1] =~ $host; ++ } ++ } + } + + sub daemonize() + { +- open STDIN, '/dev/null' or die "mailgraph: can't read /dev/null: $!"; +- if($opt{verbose}) { +- open STDOUT, ">>$daemon_logfile" +- or die "mailgraph: can't write to $daemon_logfile: $!"; +- } +- else { +- open STDOUT, '>/dev/null' +- or die "mailgraph: can't write to /dev/null: $!"; +- } +- defined(my $pid = fork) or die "mailgraph: can't fork: $!"; +- if($pid) { +- # parent +- open PIDFILE, ">$daemon_pidfile" +- or die "mailgraph: can't write to $daemon_pidfile: $!\n"; +- print PIDFILE "$pid\n"; +- close(PIDFILE); +- exit; +- } +- # child +- setsid or die "mailgraph: can't start a new session: $!"; +- open STDERR, '>&STDOUT' or die "mailgraph: can't dup stdout: $!"; ++ open STDIN, '/dev/null' or die "mailgraph: can't read /dev/null: $!"; ++ if($opt{verbose}) { ++ open STDOUT, ">>$daemon_logfile" ++ or die "mailgraph: can't write to $daemon_logfile: $!"; ++ } ++ else { ++ open STDOUT, '>/dev/null' ++ or die "mailgraph: can't write to /dev/null: $!"; ++ } ++ defined(my $pid = fork) or die "mailgraph: can't fork: $!"; ++ if($pid) { ++ # parent ++ open PIDFILE, ">$daemon_pidfile" ++ or die "mailgraph: can't write to $daemon_pidfile: $!\n"; ++ print PIDFILE "$pid\n"; ++ close(PIDFILE); ++ exit; ++ } ++ # child ++ setsid or die "mailgraph: can't start a new session: $!"; ++ open STDERR, '>&STDOUT' or die "mailgraph: can't dup stdout: $!"; + } + + sub init_rrd($) + { +- my $m = shift; +- my $rows = $xpoints/$points_per_sample; +- my $realrows = int($rows*1.1); # ensure that the full range is covered +- my $day_steps = int(3600*24 / ($rrdstep*$rows)); +- # use multiples, otherwise rrdtool could choose the wrong RRA +- my $week_steps = $day_steps*7; +- my $month_steps = $week_steps*5; +- my $year_steps = $month_steps*12; +- +- # mail rrd +- if(! -f $rrd and ! $opt{'only-virus-rrd'}) { +- RRDs::create($rrd, '--start', $m, '--step', $rrdstep, +- 'DS:sent:ABSOLUTE:'.($rrdstep*2).':0:U', +- 'DS:recv:ABSOLUTE:'.($rrdstep*2).':0:U', +- 'DS:bounced:ABSOLUTE:'.($rrdstep*2).':0:U', +- 'DS:rejected:ABSOLUTE:'.($rrdstep*2).':0:U', +- "RRA:AVERAGE:0.5:$day_steps:$realrows", # day +- "RRA:AVERAGE:0.5:$week_steps:$realrows", # week +- "RRA:AVERAGE:0.5:$month_steps:$realrows", # month +- "RRA:AVERAGE:0.5:$year_steps:$realrows", # year +- "RRA:MAX:0.5:$day_steps:$realrows", # day +- "RRA:MAX:0.5:$week_steps:$realrows", # week +- "RRA:MAX:0.5:$month_steps:$realrows", # month +- "RRA:MAX:0.5:$year_steps:$realrows", # year +- ); +- $this_minute = $m; +- } +- elsif(-f $rrd) { +- $this_minute = RRDs::last($rrd) + $rrdstep; +- } +- +- # virus rrd +- if(! -f $rrd_virus and ! $opt{'only-mail-rrd'}) { +- RRDs::create($rrd_virus, '--start', $m, '--step', $rrdstep, +- 'DS:virus:ABSOLUTE:'.($rrdstep*2).':0:U', +- 'DS:spam:ABSOLUTE:'.($rrdstep*2).':0:U', +- "RRA:AVERAGE:0.5:$day_steps:$realrows", # day +- "RRA:AVERAGE:0.5:$week_steps:$realrows", # week +- "RRA:AVERAGE:0.5:$month_steps:$realrows", # month +- "RRA:AVERAGE:0.5:$year_steps:$realrows", # year +- "RRA:MAX:0.5:$day_steps:$realrows", # day +- "RRA:MAX:0.5:$week_steps:$realrows", # week +- "RRA:MAX:0.5:$month_steps:$realrows", # month +- "RRA:MAX:0.5:$year_steps:$realrows", # year +- ); +- } +- elsif(-f $rrd_virus and ! defined $rrd_virus) { +- $this_minute = RRDs::last($rrd_virus) + $rrdstep; +- } ++ my $m = shift; ++ my $rows = $xpoints/$points_per_sample; ++ my $realrows = int($rows*1.1); # ensure that the full range is covered ++ my $day_steps = int(3600*24 / ($rrdstep*$rows)); ++ # use multiples, otherwise rrdtool could choose the wrong RRA ++ my $week_steps = $day_steps*7; ++ my $month_steps = $week_steps*5; ++ my $year_steps = $month_steps*12; ++ ++ # mail rrd ++ if(! -f $rrd and ! $opt{'no-mail-rrd'}) { ++ RRDs::create($rrd, '--start', $m, '--step', $rrdstep, ++ 'DS:sent:ABSOLUTE:'.($rrdstep*2).':0:U', ++ 'DS:recv:ABSOLUTE:'.($rrdstep*2).':0:U', ++ 'DS:bounced:ABSOLUTE:'.($rrdstep*2).':0:U', ++ 'DS:rejected:ABSOLUTE:'.($rrdstep*2).':0:U', ++ "RRA:AVERAGE:0.5:$day_steps:$realrows", # day ++ "RRA:AVERAGE:0.5:$week_steps:$realrows", # week ++ "RRA:AVERAGE:0.5:$month_steps:$realrows", # month ++ "RRA:AVERAGE:0.5:$year_steps:$realrows", # year ++ "RRA:MAX:0.5:$day_steps:$realrows", # day ++ "RRA:MAX:0.5:$week_steps:$realrows", # week ++ "RRA:MAX:0.5:$month_steps:$realrows", # month ++ "RRA:MAX:0.5:$year_steps:$realrows", # year ++ ); ++ $this_minute = $m; ++ } ++ elsif(-f $rrd) { ++ $this_minute = RRDs::last($rrd) + $rrdstep; ++ } ++ ++ # virus rrd ++ if(! -f $rrd_virus and ! $opt{'no-virus-rrd'}) { ++ RRDs::create($rrd_virus, '--start', $m, '--step', $rrdstep, ++ 'DS:virus:ABSOLUTE:'.($rrdstep*2).':0:U', ++ 'DS:spam:ABSOLUTE:'.($rrdstep*2).':0:U', ++ "RRA:AVERAGE:0.5:$day_steps:$realrows", # day ++ "RRA:AVERAGE:0.5:$week_steps:$realrows", # week ++ "RRA:AVERAGE:0.5:$month_steps:$realrows", # month ++ "RRA:AVERAGE:0.5:$year_steps:$realrows", # year ++ "RRA:MAX:0.5:$day_steps:$realrows", # day ++ "RRA:MAX:0.5:$week_steps:$realrows", # week ++ "RRA:MAX:0.5:$month_steps:$realrows", # month ++ "RRA:MAX:0.5:$year_steps:$realrows", # year ++ ); ++ } ++ elsif(-f $rrd_virus and ! defined $rrd_virus) { ++ $this_minute = RRDs::last($rrd_virus) + $rrdstep; ++ } ++ # greylist rrd ++ if(! -f $rrd_greylist and ! $opt{'no-greylist-rrd'}) { ++ RRDs::create($rrd_greylist, '--start', $m, '--step', $rrdstep, ++ 'DS:greylisted:ABSOLUTE:'.($rrdstep*2).':0:U', ++ 'DS:delayed:ABSOLUTE:'.($rrdstep*2).':0:U', ++ "RRA:AVERAGE:0.5:$day_steps:$realrows", # day ++ "RRA:AVERAGE:0.5:$week_steps:$realrows", # week ++ "RRA:AVERAGE:0.5:$month_steps:$realrows", # month ++ "RRA:AVERAGE:0.5:$year_steps:$realrows", # year ++ "RRA:MAX:0.5:$day_steps:$realrows", # day ++ "RRA:MAX:0.5:$week_steps:$realrows", # week ++ "RRA:MAX:0.5:$month_steps:$realrows", # month ++ "RRA:MAX:0.5:$year_steps:$realrows", # year ++ ); ++ $this_minute = $m; ++ } ++ elsif(-f $rrd_greylist and ! defined $rrd_greylist) { ++ $this_minute = RRDs::last($rrd_greylist) + $rrdstep; ++ } + +- $rrd_inited=1; ++ $rrd_inited=1; + } + + sub process_line($) + { +- my $sl = shift; +- my $time = $sl->[0]; +- my $prog = $sl->[2]; +- my $text = $sl->[4]; +- +- if($prog =~ /^postfix\/(.*)/) { +- my $prog = $1; +- if($prog eq 'smtp') { +- if($text =~ /\bstatus=sent\b/) { +- return if $opt{'ignore-localhost'} and +- $text =~ /\brelay=[^\s\[]*\[127\.0\.0\.1\]/; +- if(defined $opt{'ignore-host-re'}) { +- for my $ih (@{$opt{'ignore-host-re'}}) { +- warn "MATCH! $text\n" if $text =~ $ih; +- return if $text =~ $ih; +- } +- } +- event($time, 'sent'); +- } +- elsif($text =~ /\bstatus=bounced\b/) { +- event($time, 'bounced'); +- } +- } +- elsif($prog eq 'local') { +- if($text =~ /\bstatus=bounced\b/) { +- event($time, 'bounced'); +- } +- } +- elsif($prog eq 'smtpd') { +- if($text =~ /^[0-9A-Z]+: client=(\S+)/) { +- my $client = $1; +- return if $opt{'ignore-localhost'} and +- $client =~ /\[127\.0\.0\.1\]$/; +- return if $opt{'ignore-host'} and +- $client =~ /$opt{'ignore-host'}/oi; +- event($time, 'received'); +- } +- elsif($opt{'virbl-is-virus'} and $text =~ /^(?:[0-9A-Z]+: |NOQUEUE: )?reject: .*: 554.* blocked using virbl.dnsbl.bit.nl/) { +- event($time, 'virus'); +- } +- elsif($opt{'rbl-is-spam'} and $text =~ /^(?:[0-9A-Z]+: |NOQUEUE: )?reject: .*: 554.* blocked using/) { +- event($time, 'spam'); +- } +- elsif($text =~ /^(?:[0-9A-Z]+: |NOQUEUE: )?reject: /) { +- event($time, 'rejected'); +- } +- elsif($text =~ /^(?:[0-9A-Z]+: |NOQUEUE: )?milter-reject: /) { +- if($text =~ /Blocked by SpamAssassin/) { +- event($time, 'spam'); +- } +- else { +- event($time, 'rejected'); +- } +- } +- } +- elsif($prog eq 'error') { +- if($text =~ /\bstatus=bounced\b/) { +- event($time, 'bounced'); +- } +- } +- elsif($prog eq 'cleanup') { +- if($text =~ /^[0-9A-Z]+: (?:reject|discard): /) { +- event($time, 'rejected'); +- } +- } +- } +- elsif($prog eq 'sendmail' or $prog eq 'sm-mta') { +- if($text =~ /\bmailer=local\b/ ) { +- event($time, 'received'); +- } ++ my $sl = shift; ++ my $time = $sl->[0]; ++ my $prog = $sl->[2]; ++ my $text = $sl->[4]; ++ ++ if($prog =~ /^postfix\/(.*)/) { ++ my $prog = $1; ++ if($prog eq 'smtp') { ++ if($text =~ /\bstatus=sent\b/) { ++ return if $opt{'ignore-localhost'} and ++ $text =~ /\brelay=[^\s\[]*\[127\.0\.0\.1\]/; ++ if(defined $opt{'ignore-host-re'}) { ++ for my $ih (@{$opt{'ignore-host-re'}}) { ++ warn "MATCH! $text\n" if $text =~ $ih; ++ return if $text =~ $ih; ++ } ++ } ++ event($time, 'sent'); ++ } ++ elsif($text =~ /\bstatus=bounced\b/) { ++ event($time, 'bounced'); ++ } ++ } ++ elsif($prog eq 'local') { ++ if($text =~ /\bstatus=bounced\b/) { ++ event($time, 'bounced'); ++ } ++ } ++ elsif($prog eq 'smtpd' || $prog eq 'postscreen') { ++ if($text =~ /^(?:[\dA-F]+|[\dB-DF-HJ-NP-TV-Zb-df-hj-np-tv-z]+): client=(\S+)/) { ++ my $client = $1; ++ return if $opt{'ignore-localhost'} and ++ $client =~ /\[127\.0\.0\.1\]$/; ++ return if $opt{'ignore-host'} and ++ $client =~ /$opt{'ignore-host'}/oi; ++ event($time, 'received'); ++ } ++ elsif($opt{'virbl-is-virus'} and $text =~ /^(?:[\dA-F]+: |[\dB-DF-HJ-NP-TV-Zb-df-hj-np-tv-z]+: |NOQUEUE: )?reject: .*: 554.* blocked using virbl.dnsbl.bit.nl/) { ++ event($time, 'virus'); ++ } ++ elsif($opt{'rbl-is-spam'} and $text =~ /^(?:[\dA-F]+: |[\dB-DF-HJ-NP-TV-Zb-df-hj-np-tv-z]+: |NOQUEUE: )?reject: .*: 554.* blocked using/) { ++ event($time, 'spam'); ++ } ++ elsif($text =~ /Greylisted/) { ++ event($time, 'greylisted'); ++ } ++ elsif($text =~ /^(?:[\dA-F]+: |[\dB-DF-HJ-NP-TV-Zb-df-hj-np-tv-z]+: |NOQUEUE: )?reject: /) { ++ event($time, 'rejected'); ++ } ++ elsif($text =~ /^(?:[\dA-F]+: |[\dB-DF-HJ-NP-TV-Zb-df-hj-np-tv-z]+: |NOQUEUE: )?milter-reject: /) { ++ if($text =~ /Blocked by SpamAssassin/) { ++ event($time, 'spam'); ++ } ++ else { ++ event($time, 'rejected'); ++ } ++ } ++ } ++ elsif($prog eq 'error') { ++ if($text =~ /\bstatus=bounced\b/) { ++ event($time, 'bounced'); ++ } ++ } ++ elsif($prog eq 'cleanup') { ++ if($text =~ /(?:[\dA-F]+|[\dB-DF-HJ-NP-TV-Zb-df-hj-np-tv-z]+): (?:reject|discard): /) { ++ event($time, 'rejected'); ++ } ++ } ++ } ++ elsif($prog eq 'sendmail' or $prog eq 'sm-mta') { ++ if($text =~ /\bmailer=local\b/ ) { ++ event($time, 'received'); ++ } + elsif($text =~ /\bmailer=relay\b/) { + event($time, 'received'); + } +- elsif($text =~ /\bstat=Sent\b/ ) { +- event($time, 'sent'); +- } ++ elsif($text =~ /\bstat=Sent\b/ ) { ++ event($time, 'sent'); ++ } + elsif($text =~ /\bmailer=esmtp\b/ ) { + event($time, 'sent'); + } +- elsif($text =~ /\bruleset=check_XS4ALL\b/ ) { +- event($time, 'rejected'); +- } +- elsif($text =~ /\blost input channel\b/ ) { +- event($time, 'rejected'); +- } +- elsif($text =~ /\bruleset=check_rcpt\b/ ) { +- event($time, 'rejected'); +- } ++ elsif($text =~ /\bruleset=check_XS4ALL\b/ ) { ++ event($time, 'rejected'); ++ } ++ elsif($text =~ /\blost input channel\b/ ) { ++ event($time, 'rejected'); ++ } ++ elsif($text =~ /\bruleset=check_rcpt\b/ ) { ++ event($time, 'rejected'); ++ } + elsif($text =~ /\bstat=virus\b/ ) { + event($time, 'virus'); + } +- elsif($text =~ /\bruleset=check_relay\b/ ) { +- if (($opt{'virbl-is-virus'}) and ($text =~ /\bivirbl\b/ )) { +- event($time, 'virus'); +- } elsif ($opt{'rbl-is-spam'}) { +- event($time, 'spam'); +- } else { +- event($time, 'rejected'); +- } +- } +- elsif($text =~ /\bsender blocked\b/ ) { +- event($time, 'rejected'); +- } +- elsif($text =~ /\bsender denied\b/ ) { +- event($time, 'rejected'); +- } +- elsif($text =~ /\brecipient denied\b/ ) { +- event($time, 'rejected'); +- } +- elsif($text =~ /\brecipient unknown\b/ ) { +- event($time, 'rejected'); +- } +- elsif($text =~ /\bUser unknown$/i ) { +- event($time, 'bounced'); +- } +- elsif($text =~ /\bMilter:.*\breject=55/ ) { +- event($time, 'rejected'); +- } +- } +- elsif($prog eq 'exim') { +- if($text =~ /^[0-9a-zA-Z]{6}-[0-9a-zA-Z]{6}-[0-9a-zA-Z]{2} <= \S+/) { +- event($time, 'received'); +- } +- elsif($text =~ /^[0-9a-zA-Z]{6}-[0-9a-zA-Z]{6}-[0-9a-zA-Z]{2} => \S+/) { +- event($time, 'sent'); +- } +- elsif($text =~ / rejected because \S+ is in a black list at \S+/) { +- if($opt{'rbl-is-spam'}) { +- event($time, 'spam'); +- } else { +- event($time, 'rejected'); +- } +- } +- elsif($text =~ / rejected RCPT \S+: (Sender verify failed|Unknown user)/) { +- event($time, 'rejected'); +- } +- } +- elsif($prog eq 'amavis' || $prog eq 'amavisd') { +- if( $text =~ /^\([\w-]+\) (Passed|Blocked) SPAM(?:MY)?\b/) { +- if($text !~ /\btag2=/) { # ignore new per-recipient log entry (2.2.0) +- event($time, 'spam'); # since amavisd-new-2004xxxx +- } +- } +- elsif($text =~ /^\([\w-]+\) (Passed|Not-Delivered)\b.*\bquarantine spam/) { +- event($time, 'spam'); # amavisd-new-20030616 and earlier +- } +- elsif($text =~ /^\([\w-]+\) (Passed |Blocked )?INFECTED\b/) { +- if($text !~ /\btag2=/) { +- event($time, 'virus');# Passed|Blocked inserted since 2004xxxx +- } +- } +- elsif($text =~ /^\([\w-]+\) (Passed |Blocked )?BANNED\b/) { +- if($text !~ /\btag2=/) { +- event($time, 'virus'); +- } +- } +- elsif($text =~ /^Virus found\b/) { +- event($time, 'virus');# AMaViS 0.3.12 and amavisd-0.1 +- } +-# elsif($text =~ /^\([\w-]+\) Passed|Blocked BAD-HEADER\b/) { +-# event($time, 'badh'); +-# } +- } +- elsif($prog eq 'vagatefwd') { +- # Vexira antivirus (old) +- if($text =~ /^VIRUS/) { +- event($time, 'virus'); +- } +- } +- elsif($prog eq 'hook') { +- # Vexira antivirus +- if($text =~ /^\*+ Virus\b/) { +- event($time, 'virus'); +- } +- # Vexira antispam +- elsif($text =~ /\bcontains spam\b/) { +- event($time, 'spam'); +- } +- } +- elsif($prog eq 'avgatefwd' or $prog eq 'avmailgate.bin') { +- # AntiVir MailGate +- if($text =~ /^Alert!/) { +- event($time, 'virus'); +- } +- elsif($text =~ /blocked\.$/) { +- event($time, 'virus'); +- } +- } +- elsif($prog eq 'avcheck') { +- # avcheck +- if($text =~ /^infected/) { +- event($time, 'virus'); +- } +- } +- elsif($prog eq 'spamd') { +- if($text =~ /^(?:spamd: )?identified spam/) { +- event($time, 'spam'); +- } +- # ClamAV SpamAssassin-plugin +- elsif($text =~ /(?:result: )?CLAMAV/) { +- event($time, 'virus'); +- } +- } +- elsif($prog eq 'dspam') { +- if($text =~ /spam detected from/) { +- event($time, 'spam'); +- } +- } +- elsif($prog eq 'spamproxyd' or $prog eq 'spampd') { +- if($text =~ /^\s*SPAM/ or $text =~ /^identified spam/) { +- event($time, 'spam'); +- } +- } +- elsif($prog eq 'drweb-postfix') { +- # DrWeb +- if($text =~ /infected/) { +- event($time, 'virus'); +- } +- } +- elsif($prog eq 'BlackHole') { +- if($text =~ /Virus/) { +- event($time, 'virus'); +- } +- if($text =~ /(?:RBL|Razor|Spam)/) { +- event($time, 'spam'); +- } +- } +- elsif($prog eq 'MailScanner') { +- if($text =~ /(Virus Scanning: Found)/ ) { +- event($time, 'virus'); +- } +- elsif($text =~ /Bounce to/ ) { +- event($time, 'bounced'); +- } +- elsif($text =~ /^Spam Checks: Found ([0-9]+) spam messages/) { +- my $cnt = $1; +- for (my $i=0; $i<$cnt; $i++) { +- event($time, 'spam'); +- } +- } +- } +- elsif($prog eq 'clamsmtpd') { +- if($text =~ /status=VIRUS/) { +- event($time, 'virus'); +- } +- } +- elsif($prog eq 'clamav-milter') { +- if($text =~ /Intercepted/) { +- event($time, 'virus'); +- } +- } +- # uncommment for clamassassin: +- #elsif($prog eq 'clamd') { +- # if($text =~ /^stream: .* FOUND$/) { +- # event($time, 'virus'); +- # } +- #} +- elsif ($prog eq 'smtp-vilter') { +- if ($text =~ /clamd: found/) { +- event($time, 'virus'); +- } +- } +- elsif($prog eq 'avmilter') { +- # AntiVir Milter +- if($text =~ /^Alert!/) { +- event($time, 'virus'); +- } +- elsif($text =~ /blocked\.$/) { +- event($time, 'virus'); +- } +- } +- elsif($prog eq 'bogofilter') { +- if($text =~ /Spam/) { +- event($time, 'spam'); +- } +- } +- elsif($prog eq 'filter-module') { +- if($text =~ /\bspam_status\=(?:yes|spam)/) { +- event($time, 'spam'); +- } +- } +- elsif($prog eq 'sta_scanner') { +- if($text =~ /^[0-9A-F]+: virus/) { +- event($time, 'virus'); +- } +- } ++ elsif($text =~ /\bruleset=check_relay\b/ ) { ++ if (($opt{'virbl-is-virus'}) and ($text =~ /\bivirbl\b/ )) { ++ event($time, 'virus'); ++ } elsif ($opt{'rbl-is-spam'}) { ++ event($time, 'spam'); ++ } else { ++ event($time, 'rejected'); ++ } ++ } ++ elsif($text =~ /\bsender blocked\b/ ) { ++ event($time, 'rejected'); ++ } ++ elsif($text =~ /\bsender denied\b/ ) { ++ event($time, 'rejected'); ++ } ++ elsif($text =~ /\brecipient denied\b/ ) { ++ event($time, 'rejected'); ++ } ++ elsif($text =~ /\brecipient unknown\b/ ) { ++ event($time, 'rejected'); ++ } ++ elsif($text =~ /\bUser unknown$/i ) { ++ event($time, 'bounced'); ++ } ++ elsif($text =~ /\bMilter:.*\breject=55/ ) { ++ event($time, 'rejected'); ++ } ++ } ++ elsif($prog eq 'exim') { ++ if($text =~ /^[0-9a-zA-Z]{6}-[0-9a-zA-Z]{6}-[0-9a-zA-Z]{2} <= \S+/) { ++ event($time, 'received'); ++ } ++ elsif($text =~ /^[0-9a-zA-Z]{6}-[0-9a-zA-Z]{6}-[0-9a-zA-Z]{2} => \S+/) { ++ event($time, 'sent'); ++ } ++ elsif($text =~ / rejected because \S+ is in a black list at \S+/) { ++ if($opt{'rbl-is-spam'}) { ++ event($time, 'spam'); ++ } else { ++ event($time, 'rejected'); ++ } ++ } ++ elsif($text =~ / rejected RCPT \S+: (Sender verify failed|Unknown user)/) { ++ event($time, 'rejected'); ++ } ++ } ++ elsif($prog eq 'amavis' || $prog eq 'amavisd') { ++ if( $text =~ /^\([\w-]+\) (Passed|Blocked) SPAM(?:MY)?\b/) { ++ if($text !~ /\btag2=/) { # ignore new per-recipient log entry (2.2.0) ++ event($time, 'spam'); # since amavisd-new-2004xxxx ++ } ++ } ++ elsif($text =~ /^\([\w-]+\) (Passed|Not-Delivered)\b.*\bquarantine spam/) { ++ event($time, 'spam'); # amavisd-new-20030616 and earlier ++ } ++ elsif($text =~ /^\([\w-]+\) (Passed |Blocked )?INFECTED\b/) { ++ if($text !~ /\btag2=/) { ++ event($time, 'virus');# Passed|Blocked inserted since 2004xxxx ++ } ++ } ++ elsif($text =~ /^\([\w-]+\) (Passed |Blocked )?BANNED\b/) { ++ if($text !~ /\btag2=/) { ++ event($time, 'virus'); ++ } ++ } ++ elsif($text =~ /^Virus found\b/) { ++ event($time, 'virus');# AMaViS 0.3.12 and amavisd-0.1 ++ } ++# elsif($text =~ /^\([\w-]+\) Passed|Blocked BAD-HEADER\b/) { ++# event($time, 'badh'); ++# } ++ } ++ elsif($prog eq 'vagatefwd') { ++ # Vexira antivirus (old) ++ if($text =~ /^VIRUS/) { ++ event($time, 'virus'); ++ } ++ } ++ elsif($prog eq 'hook') { ++ # Vexira antivirus ++ if($text =~ /^\*+ Virus\b/) { ++ event($time, 'virus'); ++ } ++ # Vexira antispam ++ elsif($text =~ /\bcontains spam\b/) { ++ event($time, 'spam'); ++ } ++ } ++ elsif($prog eq 'avgatefwd' or $prog eq 'avmailgate.bin') { ++ # AntiVir MailGate ++ if($text =~ /^Alert!/) { ++ event($time, 'virus'); ++ } ++ elsif($text =~ /blocked\.$/) { ++ event($time, 'virus'); ++ } ++ } ++ elsif($prog eq 'avcheck') { ++ # avcheck ++ if($text =~ /^infected/) { ++ event($time, 'virus'); ++ } ++ } ++ elsif($prog eq 'spamd') { ++ if($text =~ /^(?:spamd: )?identified spam/) { ++ event($time, 'spam'); ++ } ++ # ClamAV SpamAssassin-plugin ++ elsif($text =~ /(?:result: )?CLAMAV/) { ++ event($time, 'virus'); ++ } ++ } ++ elsif($prog eq 'dspam') { ++ if($text =~ /spam detected from/) { ++ event($time, 'spam'); ++ } ++ elsif($text =~ /infected message from/) { ++ event($time, 'virus'); ++ } ++ } ++ elsif($prog eq 'spamproxyd' or $prog eq 'spampd') { ++ if($text =~ /^\s*SPAM/ or $text =~ /^identified spam/) { ++ event($time, 'spam'); ++ } ++ } ++ elsif($prog eq 'drweb-postfix') { ++ # DrWeb ++ if($text =~ /infected/) { ++ event($time, 'virus'); ++ } ++ } ++ elsif($prog eq 'BlackHole') { ++ if($text =~ /Virus/) { ++ event($time, 'virus'); ++ } ++ if($text =~ /(?:RBL|Razor|Spam)/) { ++ event($time, 'spam'); ++ } ++ } ++ elsif($prog eq 'MailScanner') { ++ if($text =~ /(Virus Scanning: Found)/ ) { ++ event($time, 'virus'); ++ } ++ elsif($text =~ /Bounce to/ ) { ++ event($time, 'bounced'); ++ } ++ elsif($text =~ /^Spam Checks: Found ([0-9]+) spam messages/) { ++ my $cnt = $1; ++ for (my $i=0; $i<$cnt; $i++) { ++ event($time, 'spam'); ++ } ++ } ++ } ++ elsif($prog eq 'clamsmtpd') { ++ if($text =~ /status=VIRUS/) { ++ event($time, 'virus'); ++ } ++ } ++ elsif($prog eq 'clamav-milter') { ++ if($text =~ /Intercepted/) { ++ event($time, 'virus'); ++ } ++ elsif($text =~ /Message.*infected by/) { ++ event($time, 'virus'); ++ } ++ } ++ # uncommment for clamassassin: ++ #elsif($prog eq 'clamd') { ++ # if($text =~ /^stream: .* FOUND$/) { ++ # event($time, 'virus'); ++ # } ++ #} ++ elsif ($prog eq 'smtp-vilter') { ++ if ($text =~ /clamd: found/) { ++ event($time, 'virus'); ++ } ++ } ++ elsif($prog eq 'avmilter') { ++ # AntiVir Milter ++ if($text =~ /^Alert!/) { ++ event($time, 'virus'); ++ } ++ elsif($text =~ /blocked\.$/) { ++ event($time, 'virus'); ++ } ++ } ++ elsif($prog eq 'bogofilter') { ++ if($text =~ /Spam/) { ++ event($time, 'spam'); ++ } ++ } ++ elsif($prog eq 'filter-module') { ++ if($text =~ /\bspam_status\=(?:yes|spam)/) { ++ event($time, 'spam'); ++ } ++ } ++ elsif($prog eq 'sta_scanner') { ++ if($text =~ /^[0-9A-F]+: virus/) { ++ event($time, 'virus'); ++ } ++ } ++ elsif($prog eq 'postgrey') { ++ # Old versions (up to 1.27) ++ if($text =~ /delayed [0-9]+ seconds: client/) { ++ event($time, 'delayed'); ++ } ++ # New versions (from 1.28) ++ if($text =~ /delay=[0-9]+/) { ++ event($time, 'delayed'); ++ } ++ } ++ elsif($prog eq 'grossd') { ++ if($text =~ /a\=greylist/) { ++ event($time, 'greylisted'); ++ } ++ } + } + + sub event($$) + { +- my ($t, $type) = @_; +- update($t) and $sum{$type}++; ++ my ($t, $type) = @_; ++ update($t) and $sum{$type}++; + } + + # returns 1 if $sum should be updated + sub update($) + { +- my $t = shift; +- my $m = $t - $t%$rrdstep; +- init_rrd($m) unless $rrd_inited; +- return 1 if $m == $this_minute; +- return 0 if $m < $this_minute; +- +- print "update $this_minute:$sum{sent}:$sum{received}:$sum{bounced}:$sum{rejected}:$sum{virus}:$sum{spam}\n" if $opt{verbose}; +- RRDs::update $rrd, "$this_minute:$sum{sent}:$sum{received}:$sum{bounced}:$sum{rejected}" unless $opt{'only-virus-rrd'}; +- RRDs::update $rrd_virus, "$this_minute:$sum{virus}:$sum{spam}" unless $opt{'only-mail-rrd'}; +- if($m > $this_minute+$rrdstep) { +- for(my $sm=$this_minute+$rrdstep;$sm<$m;$sm+=$rrdstep) { +- print "update $sm:0:0:0:0:0:0 (SKIP)\n" if $opt{verbose}; +- RRDs::update $rrd, "$sm:0:0:0:0" unless $opt{'only-virus-rrd'}; +- RRDs::update $rrd_virus, "$sm:0:0" unless $opt{'only-mail-rrd'}; +- } +- } +- $this_minute = $m; +- $sum{sent}=0; +- $sum{received}=0; +- $sum{bounced}=0; +- $sum{rejected}=0; +- $sum{virus}=0; +- $sum{spam}=0; +- return 1; ++ my $t = shift; ++ my $m = $t - $t%$rrdstep; ++ init_rrd($m) unless $rrd_inited; ++ return 1 if $m == $this_minute; ++ return 0 if $m < $this_minute; ++ ++ print "update $this_minute:$sum{sent}:$sum{received}:$sum{bounced}:$sum{rejected}:$sum{virus}:$sum{spam}:$sum{greylisted}:$sum{delayed}\n" if $opt{verbose}; ++ RRDs::update $rrd, "$this_minute:$sum{sent}:$sum{received}:$sum{bounced}:$sum{rejected}" unless $opt{'no-mail-rrd'}; ++ RRDs::update $rrd_virus, "$this_minute:$sum{virus}:$sum{spam}" unless $opt{'no-virus-rrd'}; ++ RRDs::update $rrd_greylist, "$this_minute:$sum{greylisted}:$sum{delayed}" unless $opt{'no-greylist-rrd'}; ++ if($m > $this_minute+$rrdstep) { ++ for(my $sm=$this_minute+$rrdstep;$sm<$m;$sm+=$rrdstep) { ++ print "update $sm:0:0:0:0:0:0:0:0 (SKIP)\n" if $opt{verbose}; ++ RRDs::update $rrd, "$sm:0:0:0:0" unless $opt{'no-mail-rrd'}; ++ RRDs::update $rrd_virus, "$sm:0:0" unless $opt{'no-virus-rrd'}; ++ RRDs::update $rrd_greylist, "$sm:0:0" unless $opt{'no-greylist-rrd'}; ++ } ++ } ++ $this_minute = $m; ++ $sum{sent}=0; ++ $sum{received}=0; ++ $sum{bounced}=0; ++ $sum{rejected}=0; ++ $sum{virus}=0; ++ $sum{spam}=0; ++ $sum{greylisted}=0; ++ $sum{delayed}=0; ++ return 1; + } + + main; +@@ -919,8 +993,9 @@ B<mailgraph> [I<options>...] + --daemon-log=FILE write verbose-log to FILE instead of /var/log/mailgraph.log + --ignore-localhost ignore mail to/from localhost (used for virus scanner) + --ignore-host=HOST ignore mail to/from HOST regexp (used for virus scanner) +- --only-mail-rrd update only the mail rrd +- --only-virus-rrd update only the virus rrd ++ --no-mail-rrd do not update mail rrd ++ --no-virus-rrd do not update virus rrd ++ --no-greylist-rrd do not update greylist rrd + --rrd-name=NAME use NAME.rrd and NAME_virus.rrd for the rrd files + --rbl-is-spam count rbl rejects as spam + --virbl-is-virus count virbl rejects as viruses +@@ -940,6 +1015,10 @@ The following types can be given to --lo + + Traditional "syslog" (default) + ++=item rsyslog ++ ++High precision format "rsyslog" ++ + =item metalog + + Metalog (see http://metalog.sourceforge.net/) +@@ -950,6 +1029,7 @@ Metalog (see http://metalog.sourceforge. + + Copyright (c) 2000-2007 by ETH Zurich + Copyright (c) 2000-2007 by David Schweikert ++Copyright (c) 2018 by M.D. Klapwijk + + =head1 LICENSE + +@@ -973,4 +1053,4 @@ S<David Schweikert E<lt>david@schweikert + + =cut + +-# vi: sw=8 ++# vi: sw=8 +\ No newline at end of file |