File Coverage

blib/lib/Mail/SpamAssassin/Conf/SQL.pm
Criterion Covered Total %
statement 12 85 14.1
branch 0 22 0.0
condition 0 6 0.0
subroutine 4 10 40.0
pod 1 5 20.0
total 17 128 13.2


line stmt bran cond sub pod time code
1             # <@LICENSE>
2             # Licensed to the Apache Software Foundation (ASF) under one or more
3             # contributor license agreements. See the NOTICE file distributed with
4             # this work for additional information regarding copyright ownership.
5             # The ASF licenses this file to you under the Apache License, Version 2.0
6             # (the "License"); you may not use this file except in compliance with
7             # the License. You may obtain a copy of the License at:
8             #
9             # http://www.apache.org/licenses/LICENSE-2.0
10             #
11             # Unless required by applicable law or agreed to in writing, software
12             # distributed under the License is distributed on an "AS IS" BASIS,
13             # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14             # See the License for the specific language governing permissions and
15             # limitations under the License.
16             # </@LICENSE>
17              
18             =head1 NAME
19              
20             Mail::SpamAssassin::Conf::SQL - load SpamAssassin scores from SQL database
21              
22             =head1 SYNOPSIS
23              
24             (see Mail::SpamAssassin)
25            
26              
27             =head1 DESCRIPTION
28              
29             Mail::SpamAssassin is a module to identify spam using text analysis and
30             several internet-based realtime blacklists.
31              
32             This class is used internally by SpamAssassin to load scores from an SQL
33             database. Please refer to the C<Mail::SpamAssassin> documentation for public
34             interfaces.
35              
36             =head1 METHODS
37              
38             =over 4
39              
40             =cut
41              
42              
43             use Mail::SpamAssassin::Logger;
44 41     41   272  
  41         86  
  41         2516  
45             use strict;
46 41     41   227 use warnings;
  41         78  
  41         793  
47 41     41   187 # use bytes;
  41         72  
  41         1134  
48             use re 'taint';
49 41     41   186  
  41         70  
  41         29103  
50             our @ISA = qw();
51              
52             ###########################################################################
53              
54             my $class = shift;
55             $class = ref($class) || $class;
56 0     0 0   my ($main) = @_;
57 0   0        
58 0           my $self = {
59             'main' => $main
60 0           };
61              
62             bless ($self, $class);
63             $self;
64 0           }
65 0            
66             ###########################################################################
67              
68             eval {
69             require DBI;
70             };
71 0     0 0    
72 0           # do any other preloading that will speed up operation
73             }
74              
75             ###########################################################################
76              
77             =item $f->load ($username)
78              
79             Read configuration parameters from SQL database and parse scores from it.
80              
81             =back
82              
83             =cut
84              
85             my ($self, $username) = @_;
86              
87             my $conf = $self->{main}->{conf};
88             my $dsn = $conf->{user_scores_dsn};
89 0     0 1   if (!defined($dsn) || $dsn eq '') {
90             dbg("config: no DSN defined; skipping sql");
91 0           return 1;
92 0           }
93 0 0 0        
94 0           eval {
95 0           # make sure we can see croak messages from DBI
96             local $SIG{'__DIE__'} = sub { die "$_[0]"; };
97             require DBI;
98             load_with_dbi($self, $username, $dsn);
99             1;
100 0     0     } or do {
  0            
101 0           my $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat;
102 0           if ($conf->{user_scores_fail_to_global}) {
103 0           info("config: failed to load user (%s) scores from SQL database, ".
104 0 0         "using a global default: %s", $username, $eval_stat);
105 0 0         return 1;
  0            
106 0 0         } else {
107 0           warn sprintf(
108             "config: failed to load user (%s) scores from SQL database: %s\n",
109 0           $username, $eval_stat);
110             return 0;
111 0           }
112             };
113             return 1;
114 0           }
115              
116             my ($self, $username, $dsn) = @_;
117 0            
118             my $main = $self->{main};
119             my $conf = $main->{conf};
120             my $dbuser = $conf->{user_scores_sql_username};
121 0     0 0   my $dbpass = $conf->{user_scores_sql_password};
122             my $custom_query = $conf->{user_scores_sql_custom_query};
123 0            
124 0           my $f_preference = 'preference';
125 0           my $f_value = 'value';
126 0           my $f_username = 'username';
127 0           my $f_table = 'userpref';
128              
129 0           my $dbh = DBI->connect($dsn, $dbuser, $dbpass, {'PrintError' => 0});
130 0            
131 0           if ($dbh) {
132 0           my $sql;
133             if (defined($custom_query)) {
134 0           $sql = $custom_query;
135             my $quoted_username = $dbh->quote($username);
136 0 0         my ($mailbox, $domain) = split('@', $username);
137 0           my $quoted_mailbox = $dbh->quote($mailbox);
138 0 0         my $quoted_domain = $dbh->quote($domain);
139 0            
140 0           $sql =~ s/_USERNAME_/$quoted_username/g;
141 0           $sql =~ s/_TABLE_/$f_table/g;
142 0           $sql =~ s/_MAILBOX_/$quoted_mailbox/g;
143 0           $sql =~ s/_DOMAIN_/$quoted_domain/g;
144             }
145 0           else {
146 0           $sql = "select $f_preference, $f_value from $f_table where ".
147 0           "$f_username = ".$dbh->quote($username).
148 0           " or $f_username = '\@GLOBAL' order by $f_username asc";
149             }
150             dbg("config: Conf::SQL: executing SQL: $sql");
151 0           my $sth = $dbh->prepare($sql);
152             if ($sth) {
153             my $rv = $sth->execute();
154             if ($rv) {
155 0           dbg("config: retrieving prefs for $username from SQL server");
156 0           my @row;
157 0 0         my $config_text = '';
158 0           while (@row = $sth->fetchrow_array()) {
159 0 0         $config_text .= (defined($row[0]) ? $row[0] : '') . "\t" .
160 0           (defined($row[1]) ? $row[1] : '') . "\n";
161 0           }
162 0           if ($config_text ne '') {
163 0           $conf->{main} = $main;
164 0 0         $conf->parse_scores_only($config_text);
    0          
165             delete $conf->{main};
166             }
167 0 0         $sth->finish();
168 0           undef $sth;
169 0           }
170 0           else {
171             die "config: SQL error: $sql\n".$sth->errstr."\n";
172 0           }
173 0           }
174             else {
175             die "config: SQL error: " . $dbh->errstr . "\n";
176 0           }
177             $dbh->disconnect();
178             }
179             else {
180 0           die "config: SQL error: " . DBI->errstr . "\n";
181             }
182 0           }
183              
184             ###########################################################################
185 0            
186              
187             ###########################################################################
188              
189             1;