SpamAssassin plugin: Update license foo and add timout
[collectd.git] / contrib / SpamAssassin / Collectd.pm
1 #!/usr/bin/perl
2 # $Id: Collectd.pm 7 2006-12-07 06:13:12Z formorer $
3
4 =head1 NAME
5
6 Collectd - plugin for filling collectd with stats 
7
8 =head1 INSTALLATION
9
10 Just copy Collectd.pm into your SpamAssassin Plugin path 
11 (e.g /usr/share/perl5/Mail/SpamAssassin/Plugin/) and
12 add a loadplugin call into your init.pre file. 
13
14 =head1 SYNOPSIS
15
16   loadplugin    Mail::SpamAssassin::Plugin::Collectd
17
18 =head1 USER SETTINGS
19
20 =over 4
21
22 =item collectd_socket [ socket path ]       (default: /tmp/.collectd-email)
23
24 Where the collectd socket is
25
26 =cut 
27
28 =item collectd_buffersize [ size ] (default: 256) 
29
30 the email plugin uses a fixed buffer, if a line exceeds this size
31 it has to be continued in another line. (This is of course handled internally)
32 If you have changed this setting please get it in sync with the SA Plugin
33 config. 
34
35 =cut 
36 =head1 DESCRIPTION
37
38 This modules uses the email plugin of collectd from Sebastian Harl to
39 collect statistical informations in rrd files to create some nice looking
40 graphs with rrdtool. They communicate over a unix socket that the collectd
41 plugin creates. The generated graphs will be placed in /var/lib/collectd/email
42
43 =head1 AUTHOR
44
45 Alexander Wirt <formorer@formorer.de>
46
47 =head1 COPYRIGHT
48
49  Copyright 2006 Alexander Wirt <formorer@formorer.de> 
50  
51  This program is free software; you can redistribute it and/or modify 
52  it under the the terms of either: 
53
54  a) the Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
55
56  or
57
58  b) the "Artistic License" which comes with perl
59  (http://www.perl.com/pub/a/language/misc/Artistic.html) 
60
61  use whatever you like more. 
62
63 =cut
64
65 package Mail::SpamAssassin::Plugin::Collectd;
66
67 use Mail::SpamAssassin::Plugin;
68 use Mail::SpamAssassin::Logger;
69 use strict;
70 use bytes; 
71 use warnings;
72 use IO::Socket;
73
74 use vars qw(@ISA);
75 @ISA = qw(Mail::SpamAssassin::Plugin);
76
77 sub new {
78     my ($class, $mailsa) = @_;
79
80     # the usual perlobj boilerplate to create a subclass object
81     $class = ref($class) || $class;
82     my $self = $class->SUPER::new($mailsa);
83     bless ($self, $class);
84
85     # register our config options
86     $self->set_config($mailsa->{conf});
87
88     # and return the new plugin object
89     return $self;
90 }
91
92 sub set_config {
93     my ($self, $conf) = @_;
94     my @cmds = ();
95
96     push (@cmds, {
97             setting => 'collectd_buffersize',
98             default => 256,
99             type =>
100             $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC,
101         });
102
103     push (@cmds, {
104             setting => 'collectd_socket', 
105             default => '/tmp/.collectd-email',
106             type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING,
107     });
108
109         push (@cmds, {
110                         setting => 'collectd_timeout',
111                         default => 2,
112                         type =>
113                         $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC,
114         });
115
116     $conf->{parser}->register_commands(\@cmds);
117 }
118
119 sub check_end {
120     my ($self, $params) = @_;
121     my $message_status = $params->{permsgstatus};
122         #create  new connection to our socket
123         eval {
124                 local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required
125                 die "alarm\n";
126                 #generate a timeout
127                 alarm $self->{main}->{conf}->{collectd_timeout};
128
129                 my $sock = new IO::Socket::UNIX ( $self->{main}->{conf}->{collectd_socket});
130                 # debug some informations if collectd is not running or anything else went
131                 # wrong
132                 if ( ! $sock ) {
133                         dbg("collect: could not connect to " .
134                                 $self->{main}->{conf}->{collectd_socket} . ": $! - collectd plugin
135                                 disabled"); 
136                         return 0; 
137                 }
138                 $sock->autoflush(1);
139
140                 my $score = $message_status->{score};
141                 #get the size of the message 
142                 my $body = $message_status->{msg}->{pristine_body};
143
144                 my $len = length($body);
145
146                 if ($message_status->{score} >= $self->{main}->{conf}->{required_score} ) {
147                         #hey we have spam
148                         print $sock "e:spam:$len\n";
149                 } else {
150                         print $sock "e:ham:$len\n";
151                 }
152                 print $sock "s:$score\n";
153                 my @tmp_array; 
154                 my @tests = @{$message_status->{test_names_hit}};
155
156                 my $buffersize = $self->{main}->{conf}->{collectd_buffersize}; 
157                 dbg("collectd: buffersize: $buffersize"); 
158
159                 while  (scalar(@tests) > 0) {
160                 push (@tmp_array, pop(@tests)); 
161                         if (length(join(',', @tmp_array) . '\n') > $buffersize) {
162                                 push (@tests, pop(@tmp_array)); 
163                                         if (length(join(',', @tmp_array) . '\n') > $buffersize or scalar(@tmp_array) == 0) {
164                                                 dbg("collectd: this shouldn't happen. Do you have tests"
165                                                         ." with names that have more than ~ $buffersize Bytes?");
166                                                 return 1; 
167                                         } else {
168                                                 dbg ( "collectd: c:" . join(',', @tmp_array) . "\n" ); 
169                                                 print $sock "c:" . join(',', @tmp_array) . "\n"; 
170                                                 #clean the array
171                                                 @tmp_array = ();
172                                         } 
173                         } elsif ( scalar(@tests) == 0 ) {
174                                 dbg ( "collectd: c:" . join(',', @tmp_array) . '\n' );
175                                 print $sock "c:" . join(',', @tmp_array) . "\n";
176                         }
177                 }
178                 close($sock); 
179                 alarm 0; 
180         };
181         if ($@ eq "alarm\n") {
182                 info("Connection to collectd timed out");
183                 return -1; 
184         }
185 }
186
187 1;
188
189 # vim: syntax=perl sw=4 ts=4 noet shiftround