]>
Commit | Line | Data |
---|---|---|
e84bf942 DM |
1 | package PMG::Quarantine; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | use Net::SMTP; | |
6 | ||
7 | use PVE::SafeSyslog; | |
8 | use PVE::Tools; | |
9 | ||
10 | use PMG::Utils; | |
11 | use PMG::RuleDB; | |
12 | use PMG::MailQueue; | |
13 | ||
14 | sub add_to_blackwhite { | |
15 | my ($dbh, $username, $listname, $addrs, $delete) = @_; | |
16 | ||
17 | my $name = $listname eq 'BL' ? 'BL' : 'WL'; | |
18 | my $oname = $listname eq 'BL' ? 'WL' : 'BL'; | |
19 | my $qu = $dbh->quote ($username); | |
20 | ||
21 | my $sth = $dbh->prepare( | |
22 | "SELECT * FROM UserPrefs WHERE pmail = $qu AND (Name = 'BL' OR Name = 'WL')"); | |
23 | $sth->execute(); | |
24 | ||
25 | my $list = { 'WL' => {}, 'BL' => {} }; | |
26 | ||
27 | while (my $ref = $sth->fetchrow_hashref()) { | |
28 | my $data = $ref->{data}; | |
29 | $data =~ s/[,;]/ /g; | |
30 | my @alist = split('\s+', $data); | |
31 | ||
32 | my $tmp = {}; | |
33 | foreach my $a (@alist) { | |
34 | if ($a =~ m/^[[:ascii:]]+$/) { | |
35 | $tmp->{$a} = 1; | |
36 | } | |
37 | } | |
38 | ||
39 | $list->{$ref->{name}} = $tmp; | |
40 | } | |
41 | ||
42 | $sth->finish; | |
43 | ||
44 | if ($addrs) { | |
45 | ||
46 | foreach my $v (@$addrs) { | |
47 | die "email address '$v' is too long (> 512 characters)\n" | |
48 | if length($v) > 512; | |
49 | ||
50 | if ($delete) { | |
51 | delete($list->{$name}->{$v}); | |
52 | } else { | |
53 | if ($v =~ m/[[:^ascii:]]/) { | |
54 | die "email address '$v' contains invalid characters\n"; | |
55 | } | |
56 | $list->{$name}->{$v} = 1; | |
57 | delete ($list->{$oname}->{$v}); | |
58 | } | |
59 | } | |
60 | ||
61 | my $wlist = $dbh->quote(join (',', keys %{$list->{WL}}) || ''); | |
62 | my $blist = $dbh->quote(join (',', keys %{$list->{BL}}) || ''); | |
63 | ||
64 | if (!$delete) { | |
65 | my $maxlen = 200000; | |
66 | die "whitelist size exceeds limit (> $maxlen bytes)\n" | |
67 | if length($wlist) > $maxlen; | |
68 | die "blacklist size exceeds limit (> $maxlen bytes)\n" | |
69 | if length($blist) > $maxlen; | |
70 | } | |
71 | ||
72 | $dbh->do( | |
73 | "DELETE FROM UserPrefs WHERE pmail = $qu AND (Name = 'WL' OR Name = 'BL');" . | |
74 | "INSERT INTO UserPrefs (PMail, Name, Data, MTime) " . | |
75 | "VALUES ($qu, 'BL', $blist, EXTRACT (EPOCH FROM now()));" . | |
76 | "INSERT INTO UserPrefs (PMail, Name, Data, MTime) " . | |
77 | "VALUES ($qu, 'WL', $wlist, EXTRACT (EPOCH FROM now()));"); | |
78 | } | |
79 | ||
80 | my $values = [ keys %{$list->{$name}} ]; | |
81 | ||
82 | return $values; | |
83 | } | |
84 | ||
85 | sub deliver_quarantined_mail { | |
c7e20f13 | 86 | my ($dbh, $ref, $receiver) = @_; |
e84bf942 DM |
87 | |
88 | my $filename = $ref->{file}; | |
89 | my $spooldir = $PMG::MailQueue::spooldir; | |
90 | my $path = "$spooldir/$filename"; | |
91 | ||
666b5e8f | 92 | my $id = 'C' . $ref->{cid} . 'R' . $ref->{rid} . 'T' . $ref->{ticketid};; |
e84bf942 DM |
93 | |
94 | my $sender = 'postmaster'; # notify postmaster if something fails | |
95 | ||
96 | my $smtp; | |
97 | ||
98 | eval { | |
99 | my $smtp = Net::SMTP->new ('127.0.0.1', Port => 10025, Hello => 'quarantine') || | |
100 | die "unable to connect to localhost at port 10025\n"; | |
101 | ||
102 | my $resid; | |
103 | ||
104 | if (!$smtp->mail($sender)) { | |
105 | die sprintf("smtp from error - got: %s %s\n", $smtp->code, $smtp->message); | |
106 | } | |
107 | ||
c7e20f13 | 108 | if (!$smtp->to($receiver)) { |
e84bf942 DM |
109 | die sprintf("smtp to error - got: %s %s\n", $smtp->code, $smtp->message); |
110 | } | |
111 | ||
112 | $smtp->data(); | |
113 | ||
114 | my $header = 1; | |
115 | ||
116 | open(my $fh, '<', $path) || die "unable to open file '$path' - $!\n"; | |
117 | ||
118 | while (defined(my $line = <$fh>)) { | |
119 | chomp $line; | |
120 | if ($header && ($line =~ m/^\s*$/)) { | |
121 | $header = 0; | |
122 | } | |
123 | ||
124 | # skip Delivered-To and Return-Path (avoid problem with postfix | |
125 | # forwarding loop detection (man local)) | |
126 | next if ($header && (($line =~ m/^Delivered-To:/i) || ($line =~ m/^Return-Path:/i))); | |
127 | ||
128 | # rfc821 requires this | |
129 | $line =~ s/^\./\.\./mg; | |
130 | $smtp->datasend("$line\n"); | |
131 | } | |
132 | close($fh); | |
133 | ||
134 | if ($smtp->dataend()) { | |
135 | my (@msgs) = $smtp->message; | |
136 | my ($last_msg) = $msgs[$#msgs]; | |
137 | ($resid) = $last_msg =~ m/Ok: queued as ([0-9A-Z]+)/; | |
138 | if (!$resid) { | |
139 | die sprintf("smtp error - got: %s %s\n", $smtp->code, $smtp->message); | |
140 | } | |
141 | } else { | |
142 | die sprintf("sending data failed - got: %s %s\n", $smtp->code, $smtp->message); | |
143 | } | |
144 | ||
145 | my $sth = $dbh->prepare( | |
146 | "UPDATE CMSReceivers SET Status='D', MTime = ? " . | |
666b5e8f DM |
147 | "WHERE CMailStore_CID = ? AND CMailStore_RID = ? AND TicketID = ?"); |
148 | $sth->execute(time(), $ref->{cid}, $ref->{rid}, $ref->{ticketid}); | |
e84bf942 DM |
149 | $sth->finish; |
150 | }; | |
151 | my $err = $@; | |
152 | ||
153 | $smtp->quit if $smtp; | |
154 | ||
155 | if ($err) { | |
156 | my $msg = "deliver quarantined mail '$id' ($path) failed: $err"; | |
157 | syslog('err', $msg); | |
158 | die "$msg\n"; | |
159 | } | |
160 | ||
161 | syslog('info', "delivered quarantined mail '$id' ($path)"); | |
162 | ||
163 | return 1; | |
164 | } | |
165 | ||
166 | sub delete_quarantined_mail { | |
666b5e8f | 167 | my ($dbh, $ref) = @_; |
e84bf942 DM |
168 | |
169 | my $filename = $ref->{file}; | |
170 | my $spooldir = $PMG::MailQueue::spooldir; | |
171 | my $path = "$spooldir/$filename"; | |
172 | ||
666b5e8f | 173 | my $id = 'C' . $ref->{cid} . 'R' . $ref->{rid} . 'T' . $ref->{ticketid};; |
e84bf942 DM |
174 | |
175 | eval { | |
176 | my $sth = $dbh->prepare( | |
177 | "UPDATE CMSReceivers SET Status='D', MTime = ? WHERE " . | |
666b5e8f DM |
178 | "CMailStore_CID = ? AND CMailStore_RID = ? AND TicketID = ?"); |
179 | $sth->execute (time(), $ref->{cid}, $ref->{rid}, $ref->{ticketid}); | |
e84bf942 DM |
180 | $sth->finish; |
181 | }; | |
182 | if (my $err = $@) { | |
183 | my $msg = "delete quarantined mail '$id' ($path) failed: $err"; | |
184 | syslog ('err', $msg); | |
185 | die "$msg\n"; | |
186 | } | |
187 | ||
188 | syslog ('info', "marked quarantined mail '$id' as deleted ($path)"); | |
189 | ||
190 | return 1; | |
191 | } | |
192 | ||
193 | ||
194 | 1; |