| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package TipJar::MTA; |
|
2
|
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
61282
|
use strict; |
|
|
2
|
|
|
|
|
6
|
|
|
|
2
|
|
|
|
|
90
|
|
|
4
|
2
|
|
|
2
|
|
12
|
use warnings; |
|
|
2
|
|
|
|
|
6
|
|
|
|
2
|
|
|
|
|
74
|
|
|
5
|
2
|
|
|
2
|
|
12
|
use Carp; |
|
|
2
|
|
|
|
|
12
|
|
|
|
2
|
|
|
|
|
244
|
|
|
6
|
|
|
|
|
|
|
sub mylog(@); |
|
7
|
2
|
|
|
2
|
|
1954
|
use POSIX qw/strftime/; |
|
|
2
|
|
|
|
|
18918
|
|
|
|
2
|
|
|
|
|
20
|
|
|
8
|
|
|
|
|
|
|
my $ONCE = 0; |
|
9
|
|
|
|
|
|
|
BEGIN { |
|
10
|
2
|
50
|
|
2
|
|
14876
|
if ( $ENV{TJMTADEBUG} ) { |
|
11
|
0
|
|
|
|
|
0
|
eval 'sub DEBUG(){1}'; |
|
12
|
|
|
|
|
|
|
} |
|
13
|
|
|
|
|
|
|
else { |
|
14
|
2
|
|
|
|
|
202
|
eval 'sub DEBUG(){0}'; |
|
15
|
|
|
|
|
|
|
} |
|
16
|
|
|
|
|
|
|
} |
|
17
|
2
|
|
|
|
|
650
|
use vars qw/ |
|
18
|
|
|
|
|
|
|
$VERSION $MyDomain $interval $basedir |
|
19
|
|
|
|
|
|
|
$ReturnAddress $Recipient $InitialRecipCount @Recipients |
|
20
|
|
|
|
|
|
|
$AgeBeforeDeferralReport |
|
21
|
|
|
|
|
|
|
$LogToStdout |
|
22
|
|
|
|
|
|
|
$OnlyOnce |
|
23
|
|
|
|
|
|
|
$LastChild |
|
24
|
|
|
|
|
|
|
$TimeStampFrequency |
|
25
|
|
|
|
|
|
|
$timeout |
|
26
|
|
|
|
|
|
|
$Domain $line |
|
27
|
|
|
|
|
|
|
$ConnectionProblem $dateheader |
|
28
|
|
|
|
|
|
|
$dnsmxpath $ConRetryDelay $ReuseQuota $ReuseQuotaInitial |
|
29
|
|
|
|
|
|
|
@NoBounceRegexList |
|
30
|
|
|
|
|
|
|
$MaxActiveKids |
|
31
|
|
|
|
|
|
|
$FourErrCacheLifetime |
|
32
|
|
|
|
|
|
|
$BindAddress |
|
33
|
|
|
|
|
|
|
%SMTProutes |
|
34
|
|
|
|
|
|
|
$PostDataTrouble |
|
35
|
2
|
|
|
2
|
|
28
|
/; |
|
|
2
|
|
|
|
|
6
|
|
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
$ConRetryDelay = 17 * 60; |
|
38
|
|
|
|
|
|
|
$FourErrCacheLifetime = 7 * 60; |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
# $dnsmxpath = 'dnsmx'; |
|
41
|
|
|
|
|
|
|
$ReuseQuotaInitial = 20; |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
my $res; # used by Net::DNS |
|
44
|
|
|
|
|
|
|
|
|
45
|
2
|
|
|
2
|
|
2014
|
use dateheader; |
|
|
2
|
|
|
|
|
992
|
|
|
|
2
|
|
|
|
|
14
|
|
|
46
|
|
|
|
|
|
|
sub concachetest($); |
|
47
|
|
|
|
|
|
|
sub cachepurge(); |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
$TimeStampFrequency = 200; # just under an hour at 17 seconds each |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
$MaxActiveKids = 5; # just how much spam are we sending? |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
sub CRLF() { |
|
54
|
|
|
|
|
|
|
"\015\012"; |
|
55
|
|
|
|
|
|
|
} |
|
56
|
|
|
|
|
|
|
|
|
57
|
2
|
|
|
2
|
|
220
|
use Fcntl ':flock'; # import LOCK_* constants |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
586
|
|
|
58
|
|
|
|
|
|
|
$interval = 17; |
|
59
|
|
|
|
|
|
|
$AgeBeforeDeferralReport = 4 * 3600; # four hours |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
$VERSION = '0.34'; |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
sub VERSION { |
|
64
|
0
|
0
|
|
0
|
0
|
0
|
$_[1] or return $VERSION; |
|
65
|
0
|
0
|
|
|
|
0
|
$_[1] <= 0.14 and croak 'TipJar::MTA now uses Net::DNS instead of dnsmx'; |
|
66
|
|
|
|
|
|
|
|
|
67
|
0
|
0
|
|
|
|
0
|
$_[1] > $VERSION |
|
68
|
|
|
|
|
|
|
and croak |
|
69
|
|
|
|
|
|
|
"you are requesting TipJar::MTA version $_[1] but this is only $VERSION"; |
|
70
|
|
|
|
|
|
|
|
|
71
|
0
|
|
|
|
|
0
|
$VERSION; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
|
|
74
|
2
|
|
|
2
|
|
2024
|
use Sys::Hostname; |
|
|
2
|
|
|
|
|
7260
|
|
|
|
2
|
|
|
|
|
13574
|
|
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
my $RealHostName = $MyDomain = ( hostname() || 'sys.hostname.returned.false' ); |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
my $time; |
|
79
|
|
|
|
|
|
|
sub newmessage($); |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub OneWeek() { 7 * 24 * 3600; } |
|
82
|
|
|
|
|
|
|
sub SixHours() { 6 * 3600; } |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub Scramble($) { |
|
85
|
0
|
|
|
0
|
0
|
0
|
my @a = @{ shift(@_) }; |
|
|
0
|
|
|
|
|
0
|
|
|
86
|
0
|
|
|
|
|
0
|
my ( $i, $ii ); |
|
87
|
0
|
|
|
|
|
0
|
my $max = @a; |
|
88
|
0
|
|
|
|
|
0
|
for ( $i = 0 ; $i < $max ; $i++ ) { |
|
89
|
0
|
|
|
|
|
0
|
$ii = rand $max; |
|
90
|
0
|
|
|
|
|
0
|
@a[ $i, $ii ] = @a[ $ii . $i ]; |
|
91
|
|
|
|
|
|
|
} |
|
92
|
0
|
|
|
|
|
0
|
@a; |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub import { |
|
96
|
2
|
|
|
2
|
|
20
|
shift; #package name |
|
97
|
2
|
50
|
|
|
|
14
|
if ( grep { m/^nodns$/i } @_ ) { |
|
|
0
|
|
|
|
|
0
|
|
|
98
|
|
|
|
|
|
|
*dnsmx = sub($) { |
|
99
|
0
|
|
|
0
|
|
0
|
my $host = lc(shift); |
|
100
|
0
|
0
|
|
|
|
0
|
if ( exists $SMTProutes{$host} ) { |
|
101
|
0
|
0
|
|
|
|
0
|
ref( $SMTProutes{$host} ) |
|
102
|
|
|
|
|
|
|
and return Scramble( $SMTProutes{$host} ); |
|
103
|
0
|
|
|
|
|
0
|
return $SMTProutes{$host}; |
|
104
|
|
|
|
|
|
|
} |
|
105
|
0
|
0
|
|
|
|
0
|
if ( exists $SMTProutes{SMARTHOST} ) { |
|
106
|
0
|
0
|
|
|
|
0
|
ref( $SMTProutes{SMARTHOST} ) |
|
107
|
|
|
|
|
|
|
and return Scramble( $SMTProutes{$host} ); |
|
108
|
0
|
|
|
|
|
0
|
return $SMTProutes{SMARTHOST}; |
|
109
|
|
|
|
|
|
|
} |
|
110
|
0
|
|
|
|
|
0
|
mylog "nodns: %SMTProutes has no entry for <$host> or SMARTHOST"; |
|
111
|
0
|
|
|
|
|
0
|
return $host; |
|
112
|
|
|
|
|
|
|
|
|
113
|
0
|
|
|
|
|
0
|
}; |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
else { |
|
116
|
2
|
50
|
|
2
|
|
2012
|
eval 'use Net::DNS; 1' or die "failed to load Net::DNS: $@"; |
|
|
2
|
|
|
|
|
670870
|
|
|
|
2
|
|
|
|
|
224
|
|
|
|
2
|
|
|
|
|
178
|
|
|
117
|
|
|
|
|
|
|
|
|
118
|
2
|
|
|
|
|
38
|
$res = Net::DNS::Resolver->new; |
|
119
|
2
|
|
|
|
|
1876
|
*dnsmx = \&_dnsmx; |
|
120
|
|
|
|
|
|
|
} |
|
121
|
2
|
|
|
|
|
8
|
$basedir = shift; |
|
122
|
2
|
|
50
|
|
|
20
|
$basedir ||= './MTAdir'; |
|
123
|
2
|
|
|
|
|
136
|
DEBUG and warn "basedir will be $basedir"; |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
$LogToStdout = 1; |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
{ |
|
130
|
|
|
|
|
|
|
my $LogTime = 0; |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
sub DLsave($); |
|
133
|
|
|
|
|
|
|
sub DLpurge(); |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub mylog(@) { |
|
136
|
|
|
|
|
|
|
|
|
137
|
5
|
100
|
|
5
|
0
|
35
|
if ( time - $LogTime > 30 ) { |
|
138
|
2
|
|
|
|
|
4
|
$LogTime = time; |
|
139
|
2
|
|
|
|
|
86
|
mylog scalar localtime; |
|
140
|
|
|
|
|
|
|
} |
|
141
|
|
|
|
|
|
|
|
|
142
|
5
|
100
|
|
|
|
22
|
defined $Recipient or $Recipient = 'no recipient'; |
|
143
|
|
|
|
|
|
|
|
|
144
|
5
|
50
|
0
|
|
|
335
|
open LOG, ">>$basedir/log/current" or print( @_, "\n" ) and return; |
|
145
|
5
|
50
|
|
|
|
66
|
flock LOG, LOCK_EX or die "flock: $!"; |
|
146
|
5
|
50
|
|
|
|
19
|
if ($LogToStdout) { |
|
147
|
5
|
|
|
|
|
833
|
seek STDOUT, 2, 0; |
|
148
|
5
|
|
|
|
|
166
|
print "$$ $Recipient ", @_; |
|
149
|
5
|
|
|
|
|
26
|
print "\n"; |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
else { |
|
152
|
0
|
|
|
|
|
0
|
seek LOG, 2, 0; |
|
153
|
0
|
|
|
|
|
0
|
print LOG "$$ $Recipient ", @_; |
|
154
|
0
|
|
|
|
|
0
|
print LOG "\n"; |
|
155
|
|
|
|
|
|
|
} |
|
156
|
5
|
|
|
|
|
36
|
flock LOG, LOCK_UN; # flushes before unlocking |
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
}; |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
my $ActiveKids = 0; |
|
162
|
|
|
|
|
|
|
$SIG{CHLD} = sub { $ActiveKids--; wait }; |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
sub recursive_immed($) { # "$qdir/$this"; |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# immediatize all files under here, then delete the dir. |
|
167
|
0
|
|
|
0
|
0
|
0
|
my $this = shift; |
|
168
|
0
|
|
|
|
|
0
|
my @dirs = ($this); |
|
169
|
0
|
|
|
|
|
0
|
my $e; |
|
170
|
|
|
|
|
|
|
my @rmdirs; |
|
171
|
0
|
|
|
|
|
0
|
while (@dirs) { |
|
172
|
0
|
|
|
|
|
0
|
$this = shift @dirs; |
|
173
|
0
|
|
|
|
|
0
|
DEBUG and warn "immanentizing $this"; |
|
174
|
0
|
|
|
|
|
0
|
opendir RI_DIR, $this; |
|
175
|
0
|
|
|
|
|
0
|
for $e ( readdir RI_DIR ) { |
|
176
|
0
|
0
|
|
|
|
0
|
$e =~ /^\.\.?$/ and next; |
|
177
|
0
|
|
|
|
|
0
|
my $abs = "$this/$e"; |
|
178
|
0
|
0
|
|
|
|
0
|
if ( -d $abs ) { |
|
|
|
0
|
|
|
|
|
|
|
179
|
0
|
|
|
|
|
0
|
push @dirs, $abs; |
|
180
|
|
|
|
|
|
|
} |
|
181
|
|
|
|
|
|
|
elsif ( -f _ ) { |
|
182
|
0
|
|
|
|
|
0
|
mylog "immanentizing $abs"; |
|
183
|
0
|
|
|
|
|
0
|
my $ext = 'Q'; |
|
184
|
0
|
|
|
|
|
0
|
my $newname; |
|
185
|
0
|
|
|
|
|
0
|
while ( -e "$basedir/immediate/$e$ext" ) { |
|
186
|
0
|
|
|
|
|
0
|
$ext++; |
|
187
|
|
|
|
|
|
|
} |
|
188
|
0
|
0
|
|
|
|
0
|
rename $abs, "$basedir/immediate/$e$ext" |
|
189
|
|
|
|
|
|
|
or mylog "rename failed (with extension $ext): $!"; |
|
190
|
|
|
|
|
|
|
} |
|
191
|
|
|
|
|
|
|
else { |
|
192
|
0
|
|
|
|
|
0
|
mylog "UNLINKING NONFILE NONDIR $abs"; |
|
193
|
|
|
|
|
|
|
# abs hasn't been opened, don't need to close it |
|
194
|
0
|
0
|
|
|
|
0
|
unlink $abs or mylog "UNLINK FAILED: $!"; |
|
195
|
|
|
|
|
|
|
} |
|
196
|
|
|
|
|
|
|
} |
|
197
|
0
|
|
|
|
|
0
|
unshift @rmdirs, $this; |
|
198
|
|
|
|
|
|
|
} |
|
199
|
0
|
0
|
|
|
|
0
|
for $e (@rmdirs) { rmdir $e or mylog "Can't rmdir $e: $!" } |
|
|
0
|
|
|
|
|
0
|
|
|
200
|
|
|
|
|
|
|
} |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
{ |
|
203
|
|
|
|
|
|
|
# static variables |
|
204
|
|
|
|
|
|
|
my $string = 'a'; |
|
205
|
|
|
|
|
|
|
my $outboundfname = 'a'; |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
sub run() { |
|
208
|
|
|
|
|
|
|
|
|
209
|
2
|
|
|
2
|
|
10
|
INIT { $string = 'a' } |
|
210
|
2
|
|
|
2
|
0
|
324
|
undef $Recipient; |
|
211
|
|
|
|
|
|
|
|
|
212
|
2
|
50
|
33
|
|
|
108
|
-d $basedir |
|
213
|
|
|
|
|
|
|
or mkdir $basedir, 0770 |
|
214
|
|
|
|
|
|
|
or die "could not mkdir $basedir: $!"; |
|
215
|
|
|
|
|
|
|
|
|
216
|
2
|
50
|
|
|
|
44
|
-w $basedir or croak "base dir <$basedir> must be writable!"; |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
# log dir contains logs (duh) |
|
219
|
2
|
50
|
33
|
|
|
48
|
-d "$basedir/log" |
|
220
|
|
|
|
|
|
|
or mkdir "$basedir/log", 0770 |
|
221
|
|
|
|
|
|
|
or die "could not mkdir $basedir/log: $!"; |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
# queue dir contains deferred messageobjects |
|
224
|
2
|
50
|
33
|
|
|
46
|
-d "$basedir/queue" |
|
225
|
|
|
|
|
|
|
or mkdir "$basedir/queue", 0770 |
|
226
|
|
|
|
|
|
|
or die "could not mkdir $basedir/queue: $!"; |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# domain dir contains lists of queued messages, per domain. |
|
229
|
2
|
50
|
33
|
|
|
44
|
-d "$basedir/domain" |
|
230
|
|
|
|
|
|
|
or mkdir "$basedir/domain", 0770 |
|
231
|
|
|
|
|
|
|
or die "could not mkdir $basedir/domain: $!"; |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# 4error dir contains lists of 4NN-error remote addresses, per domain. |
|
234
|
2
|
50
|
33
|
|
|
48
|
-d "$basedir/4error" |
|
235
|
|
|
|
|
|
|
or mkdir "$basedir/4error", 0770 |
|
236
|
|
|
|
|
|
|
or die "could not mkdir $basedir/4error: $!"; |
|
237
|
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
# 5error dir contains lists of 5NN-error remote addresses, per domain. |
|
239
|
2
|
50
|
33
|
|
|
42
|
-d "$basedir/5error" |
|
240
|
|
|
|
|
|
|
or mkdir "$basedir/5error", 0770 |
|
241
|
|
|
|
|
|
|
or die "could not mkdir $basedir/5error: $!"; |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# conerror dir contains domains we are having trouble connecting to. |
|
244
|
2
|
50
|
33
|
|
|
46
|
-d "$basedir/conerror" |
|
245
|
|
|
|
|
|
|
or mkdir "$basedir/conerror", 0770 |
|
246
|
|
|
|
|
|
|
or die "could not mkdir $basedir/conerror: $!"; |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
# temp dir contains message objects under construction |
|
249
|
2
|
50
|
33
|
|
|
46
|
-d "$basedir/temp" |
|
250
|
|
|
|
|
|
|
or mkdir "$basedir/temp", 0770 |
|
251
|
|
|
|
|
|
|
or die "could not mkdir $basedir/temp: $!"; |
|
252
|
|
|
|
|
|
|
|
|
253
|
2
|
50
|
|
|
|
14
|
$ONCE or do { # only one MTA at a time, so we can run this |
|
254
|
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
# from cron |
|
256
|
2
|
|
|
|
|
2382
|
open PID, ">>$basedir/temp/MTApid"; # "touch" sort of |
|
257
|
2
|
50
|
|
|
|
114
|
open PID, "+<$basedir/temp/MTApid" |
|
258
|
|
|
|
|
|
|
or die "could not open pid file '$basedir/temp/MTApid'"; |
|
259
|
2
|
|
|
|
|
22
|
flock PID, LOCK_EX; |
|
260
|
2
|
|
|
|
|
68
|
chomp( my $oldpid = ); |
|
261
|
|
|
|
|
|
|
|
|
262
|
2
|
50
|
33
|
|
|
58
|
if ( $oldpid and kill 0, $oldpid ) { |
|
263
|
0
|
|
|
|
|
0
|
print "$$ MTA process number $oldpid is still running\n"; |
|
264
|
0
|
|
|
|
|
0
|
mylog "MTA process number $oldpid is still running"; |
|
265
|
0
|
|
|
|
|
0
|
exit; |
|
266
|
|
|
|
|
|
|
} |
|
267
|
|
|
|
|
|
|
|
|
268
|
2
|
|
|
|
|
18
|
seek PID, 0, 0; |
|
269
|
2
|
|
|
|
|
4
|
DEBUG and warn "main proc is $$"; |
|
270
|
2
|
|
|
|
|
10
|
print PID "$$\n"; |
|
271
|
2
|
|
|
|
|
86
|
flock PID, LOCK_UN; |
|
272
|
2
|
|
|
|
|
24
|
close PID; |
|
273
|
|
|
|
|
|
|
}; |
|
274
|
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
# immediate dir contains reprioritized deferred objects |
|
276
|
2
|
50
|
33
|
|
|
54
|
-d "$basedir/immediate" |
|
277
|
|
|
|
|
|
|
or mkdir "$basedir/immediate", 0770 |
|
278
|
|
|
|
|
|
|
or die "could not mkdir $basedir/immediate: $!"; |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
# endless top level loop |
|
281
|
2
|
|
|
|
|
16
|
mylog "starting fork-and-wait loop: will launch every $interval seconds."; |
|
282
|
2
|
|
|
|
|
4
|
my $count; |
|
283
|
2
|
|
|
|
|
4
|
for ( ; ; ) { |
|
284
|
2
|
50
|
|
|
|
12
|
++$count % $TimeStampFrequency |
|
285
|
|
|
|
|
|
|
or mylog( time, ": ", scalar(localtime), " ", $count ); |
|
286
|
|
|
|
|
|
|
|
|
287
|
2
|
50
|
|
|
|
14
|
rand(1000) < 1 and cachepurge; # how long is 17000 seconds? |
|
288
|
|
|
|
|
|
|
|
|
289
|
2
|
50
|
|
|
|
14
|
if ( $ActiveKids > $MaxActiveKids ) { |
|
290
|
0
|
|
|
|
|
0
|
mylog "$ActiveKids child procs (more than $MaxActiveKids)"; |
|
291
|
0
|
|
|
|
|
0
|
sleep( 1 + int( $interval / 3 ) ); |
|
292
|
0
|
|
|
|
|
0
|
next; |
|
293
|
|
|
|
|
|
|
} |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
# new child drops out of the waiting loop |
|
296
|
2
|
50
|
|
|
|
10
|
$ONCE and last; |
|
297
|
2
|
100
|
|
|
|
11112
|
$LastChild = fork or last; |
|
298
|
1
|
|
|
|
|
29
|
$ActiveKids++; |
|
299
|
1
|
50
|
|
|
|
75
|
if ($OnlyOnce) { |
|
300
|
1
|
|
|
|
|
71
|
mylog "OnlyOnce flag set to [$OnlyOnce]"; |
|
301
|
1
|
|
|
|
|
47
|
return $OnlyOnce; |
|
302
|
|
|
|
|
|
|
} |
|
303
|
0
|
|
|
|
|
0
|
my $slept = 0; |
|
304
|
0
|
|
|
|
|
0
|
while ( $slept < $interval ) { |
|
305
|
0
|
|
|
|
|
0
|
$slept += sleep( 1 + $interval - $slept ); |
|
306
|
|
|
|
|
|
|
} |
|
307
|
|
|
|
|
|
|
} |
|
308
|
1
|
|
|
|
|
50
|
my $file; |
|
309
|
1
|
|
|
|
|
28
|
$time = time; |
|
310
|
1
|
|
|
|
|
58
|
DEBUG and warn "queuerunner launched at " . localtime $time; |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
# process new files if any |
|
313
|
1
|
|
|
|
|
165
|
opendir BASEDIR, $basedir; |
|
314
|
1
|
|
|
|
|
432
|
my @entries = readdir BASEDIR; |
|
315
|
1
|
|
|
|
|
19
|
my $outfile; |
|
316
|
1
|
|
|
|
|
100
|
for $file (@entries) { |
|
317
|
10
|
50
|
|
|
|
326
|
-f "$basedir/$file" or next; |
|
318
|
0
|
0
|
|
|
|
0
|
-s "$basedir/$file" or next; |
|
319
|
0
|
|
|
|
|
0
|
mylog "processing new message file $file"; |
|
320
|
|
|
|
|
|
|
rename "$basedir/$file", |
|
321
|
|
|
|
|
|
|
$outfile = "$basedir/temp/$$-" . $outboundfname++ . time |
|
322
|
0
|
0
|
|
|
|
0
|
or do { |
|
323
|
0
|
|
|
|
|
0
|
mylog "could not rename $file: $!"; |
|
324
|
0
|
|
|
|
|
0
|
next; |
|
325
|
|
|
|
|
|
|
}; |
|
326
|
0
|
|
|
|
|
0
|
DEBUG and warn "renamed new message $basedir/$file to $outfile"; |
|
327
|
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
# expand and write into temp, then try to |
|
329
|
|
|
|
|
|
|
# deliver each file as it is expanded |
|
330
|
0
|
0
|
|
|
|
0
|
unless ( open MESSAGE0, "<$outfile" ) { |
|
331
|
0
|
|
|
|
|
0
|
mylog "CRITICAL: Could not open $outfile for reading"; |
|
332
|
0
|
|
|
|
|
0
|
next; |
|
333
|
|
|
|
|
|
|
} |
|
334
|
|
|
|
|
|
|
eval |
|
335
|
0
|
|
|
|
|
0
|
" END{ close MESSAGE0; DEBUG and warn q{ unlinking $outfile }; unlink q{$outfile} or mylog q{CRITICAL: could not unlink $outfile}} "; |
|
336
|
|
|
|
|
|
|
|
|
337
|
0
|
|
|
|
|
0
|
my @MessData = (); |
|
338
|
0
|
|
|
|
|
0
|
mylog scalar(@MessData), "lines of message data"; |
|
339
|
|
|
|
|
|
|
|
|
340
|
0
|
|
|
|
|
0
|
chomp( my $FirstLine = shift @MessData ); |
|
341
|
0
|
|
|
|
|
0
|
mylog "from [[$FirstLine]]"; |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
# never mind $FirstLine =~ s/\s*<*([^<>\s]*).*$/$1/s; |
|
344
|
|
|
|
|
|
|
|
|
345
|
0
|
|
|
|
|
0
|
my $Recip; |
|
346
|
|
|
|
|
|
|
my %DOMAIN_MATRIX; |
|
347
|
0
|
|
|
|
|
0
|
my $bestmx; |
|
348
|
0
|
|
|
|
|
0
|
for ( ; ; ) { |
|
349
|
0
|
|
|
|
|
0
|
chomp( $Recip = shift @MessData ); |
|
350
|
0
|
|
|
|
|
0
|
DEBUG and warn "recip $Recip"; |
|
351
|
0
|
0
|
|
|
|
0
|
unless (@MessData) { |
|
352
|
0
|
|
|
|
|
0
|
mylog "no body in message file $outfile"; |
|
353
|
0
|
|
|
|
|
0
|
die "no body in message file $outfile"; |
|
354
|
|
|
|
|
|
|
} |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
# never mind $Recip =~ s/\s*<*([^<>\s]+\@[\w\-\.]+).*$/$1/s or last; |
|
357
|
0
|
0
|
|
|
|
0
|
($Domain) = $Recip =~ /\@([\w\-\.]+)/ or last; |
|
358
|
0
|
|
|
|
|
0
|
($bestmx) = dnsmx($Domain); |
|
359
|
0
|
|
|
|
|
0
|
mylog "for $Recip (via $bestmx)"; |
|
360
|
0
|
|
|
|
|
0
|
push @{ $DOMAIN_MATRIX{$bestmx} }, $Recip; |
|
|
0
|
|
|
|
|
0
|
|
|
361
|
|
|
|
|
|
|
} |
|
362
|
|
|
|
|
|
|
|
|
363
|
0
|
|
|
|
|
0
|
foreach $bestmx ( keys %DOMAIN_MATRIX ) { |
|
364
|
0
|
|
|
|
|
0
|
DEBUG and warn "mx $bestmx gets @{$DOMAIN_MATRIX{$bestmx}}"; |
|
365
|
0
|
|
|
|
|
0
|
$string++; |
|
366
|
0
|
0
|
|
|
|
0
|
open TEMP, ">$basedir/temp/$time.$$.$string" or die "FAILURE: $!"; |
|
367
|
0
|
|
|
|
|
0
|
DEBUG and warn "in $basedir/temp/$time.$$.$string"; |
|
368
|
0
|
|
|
|
|
0
|
print TEMP "$FirstLine\n@{$DOMAIN_MATRIX{$bestmx}}\n", @MessData, |
|
|
0
|
|
|
|
|
0
|
|
|
369
|
|
|
|
|
|
|
"\n"; |
|
370
|
0
|
|
|
|
|
0
|
close TEMP; |
|
371
|
0
|
0
|
|
|
|
0
|
rename |
|
372
|
|
|
|
|
|
|
"$basedir/temp/$time.$$.$string", |
|
373
|
|
|
|
|
|
|
"$basedir/immediate/$time.$$.$string.$bestmx" |
|
374
|
|
|
|
|
|
|
or die "rename: $!"; |
|
375
|
|
|
|
|
|
|
} |
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
} |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
# process all messages in immediate directory |
|
380
|
1
|
50
|
|
|
|
98
|
opendir BASEDIR, "$basedir/immediate" |
|
381
|
|
|
|
|
|
|
or die "could not open immediate dir: $!"; |
|
382
|
1
|
|
|
|
|
23
|
@entries = readdir BASEDIR; |
|
383
|
1
|
|
|
|
|
3
|
for $file (@entries) { |
|
384
|
2
|
50
|
|
|
|
56
|
my $M = newmessage "$basedir/immediate/$file" or next; |
|
385
|
0
|
|
|
|
|
0
|
DEBUG and warn "created message object $M for immediate message file $file"; |
|
386
|
0
|
|
|
|
|
0
|
$M->attempt(); # will skip or requeue or delete |
|
387
|
0
|
|
|
|
|
0
|
undef $Recipient; |
|
388
|
|
|
|
|
|
|
} |
|
389
|
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
# reprioritize deferred messages |
|
391
|
1
|
|
|
|
|
5
|
my $qdir = "$basedir/queue"; |
|
392
|
|
|
|
|
|
|
|
|
393
|
1
|
|
|
|
|
27
|
my @reprime; |
|
394
|
1
|
|
|
|
|
272
|
for my $NEXTPIECE ( split / /, strftime "%Y %m %d %H %M %S", localtime ) { |
|
395
|
1
|
|
|
|
|
2
|
DEBUG and warn "looking at queue dir $qdir"; |
|
396
|
1
|
|
|
|
|
39
|
opendir QDIR, $qdir; |
|
397
|
1
|
|
|
|
|
2
|
my $this; |
|
398
|
1
|
|
|
|
|
20
|
while ( defined( $this = readdir QDIR ) ) { |
|
399
|
2
|
50
|
|
|
|
126
|
if ( -f "$qdir/$this" ) { |
|
400
|
0
|
|
|
|
|
0
|
mylog "immanentizing $qdir/$this"; |
|
401
|
0
|
|
|
|
|
0
|
rename "$qdir/$this", "$basedir/immediate/${this}Q"; |
|
402
|
0
|
|
|
|
|
0
|
next; |
|
403
|
|
|
|
|
|
|
} |
|
404
|
2
|
50
|
|
|
|
1284
|
unless ( -d "$qdir/$this" ) { |
|
405
|
0
|
|
|
|
|
0
|
mylog "UNLINKING NONFILE NONDIR $qdir/$this"; |
|
406
|
|
|
|
|
|
|
# hasn't been opened no need to close it |
|
407
|
0
|
0
|
|
|
|
0
|
unlink "$qdir/$this" or mylog "UNLINK FAILED: $!"; |
|
408
|
0
|
|
|
|
|
0
|
next; |
|
409
|
|
|
|
|
|
|
} |
|
410
|
|
|
|
|
|
|
|
|
411
|
2
|
50
|
|
|
|
191
|
$this =~ /^\.\.?$/ and next; |
|
412
|
|
|
|
|
|
|
|
|
413
|
0
|
0
|
|
|
|
0
|
if ( $this < $NEXTPIECE ) { |
|
414
|
0
|
|
|
|
|
0
|
recursive_immed "$qdir/$this"; |
|
415
|
|
|
|
|
|
|
} |
|
416
|
|
|
|
|
|
|
} |
|
417
|
1
|
|
|
|
|
140
|
$qdir .= "/$NEXTPIECE"; |
|
418
|
1
|
50
|
|
|
|
79
|
-d $qdir or last; |
|
419
|
|
|
|
|
|
|
} |
|
420
|
|
|
|
|
|
|
|
|
421
|
1
|
50
|
|
|
|
2003
|
$ONCE or exit; |
|
422
|
|
|
|
|
|
|
} # end sub run |
|
423
|
|
|
|
|
|
|
|
|
424
|
0
|
|
|
0
|
0
|
0
|
sub once { $ONCE = 1; run} |
|
|
0
|
|
|
|
|
0
|
|
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
}; # end sub run and enclosing scope |
|
428
|
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
# only one active message per process. |
|
430
|
|
|
|
|
|
|
# (MESSAGE, $ReturnAddress, $Recipient) are all global. |
|
431
|
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
sub newmessage($) { |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
#my $pack = shift; |
|
435
|
2
|
|
|
2
|
0
|
16
|
my $messageID = shift; |
|
436
|
2
|
50
|
|
|
|
325
|
-f $messageID or return undef; |
|
437
|
0
|
0
|
|
|
|
0
|
-s $messageID or do { |
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
# eliminate freeze on zero-length message files |
|
440
|
|
|
|
|
|
|
# hasn't been opened no need to close it |
|
441
|
0
|
|
|
|
|
0
|
unlink $messageID; |
|
442
|
0
|
|
|
|
|
0
|
return undef; |
|
443
|
|
|
|
|
|
|
}; |
|
444
|
0
|
0
|
|
|
|
0
|
open MESSAGE, "<$messageID" or return undef; |
|
445
|
0
|
0
|
|
|
|
0
|
flock MESSAGE, LOCK_EX | LOCK_NB or return undef; |
|
446
|
0
|
|
|
|
|
0
|
chomp( $ReturnAddress = ); |
|
447
|
0
|
|
|
|
|
0
|
chomp( $Recipient = ); |
|
448
|
0
|
|
|
|
|
0
|
@Recipients = split / +/, $Recipient; |
|
449
|
0
|
|
|
|
|
0
|
$InitialRecipCount = @Recipients; |
|
450
|
0
|
|
|
|
|
0
|
undef $PostDataTrouble; |
|
451
|
0
|
|
|
|
|
0
|
bless \$messageID; |
|
452
|
|
|
|
|
|
|
} |
|
453
|
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
my $purgecount; |
|
455
|
|
|
|
|
|
|
sub purgedir($); |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
sub purgedir($) { |
|
458
|
0
|
|
|
0
|
0
|
0
|
my $now = time(); |
|
459
|
0
|
|
|
|
|
0
|
my $dir = shift; |
|
460
|
0
|
|
|
|
|
0
|
my $nonempty; |
|
461
|
|
|
|
|
|
|
my @dirs; |
|
462
|
0
|
|
|
|
|
0
|
opendir SUBDIR, $dir; |
|
463
|
0
|
|
|
|
|
0
|
foreach ( readdir SUBDIR ) { |
|
464
|
0
|
0
|
|
|
|
0
|
/^\.{1,2}$/ and next; |
|
465
|
0
|
|
|
|
|
0
|
$nonempty = 1; |
|
466
|
0
|
0
|
|
|
|
0
|
-d "$dir/$_" and push @dirs, $_; |
|
467
|
0
|
0
|
|
|
|
0
|
-f "$dir/$_" or next; |
|
468
|
0
|
|
|
|
|
0
|
my @statresult = stat(_); |
|
469
|
0
|
|
|
|
|
0
|
my $mtime = $statresult[9]; |
|
470
|
0
|
0
|
|
|
|
0
|
if ( ( $now - $mtime ) > ( 4 * 60 * 60 ) ) { |
|
471
|
0
|
0
|
|
|
|
0
|
unlink "$dir/$_" or mylog "problem unlinking $dir/$_: $!"; |
|
472
|
0
|
|
|
|
|
0
|
$purgecount++; |
|
473
|
|
|
|
|
|
|
} |
|
474
|
|
|
|
|
|
|
} |
|
475
|
0
|
|
|
|
|
0
|
foreach my $sdir (@dirs) { |
|
476
|
0
|
|
|
|
|
0
|
purgedir("$dir/$sdir"); |
|
477
|
|
|
|
|
|
|
} |
|
478
|
0
|
0
|
|
|
|
0
|
rmdir $dir unless ($nonempty); # patience is a virtue |
|
479
|
|
|
|
|
|
|
} |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
sub cachepurge() { |
|
482
|
0
|
|
|
0
|
0
|
0
|
$purgecount = 0; |
|
483
|
0
|
|
|
|
|
0
|
opendir DIR, "$basedir/4error/"; |
|
484
|
0
|
|
|
|
|
0
|
my @fours = map { "$basedir/4error/$_" } readdir DIR; |
|
|
0
|
|
|
|
|
0
|
|
|
485
|
|
|
|
|
|
|
|
|
486
|
0
|
|
|
|
|
0
|
opendir DIR, "$basedir/5error/"; |
|
487
|
0
|
|
|
|
|
0
|
my @fives = map { "$basedir/5error/$_" } readdir DIR; |
|
|
0
|
|
|
|
|
0
|
|
|
488
|
|
|
|
|
|
|
|
|
489
|
0
|
|
|
|
|
0
|
foreach ( @fours, @fives ) { |
|
490
|
0
|
0
|
|
|
|
0
|
/error\/\.\.?$/ and next; |
|
491
|
0
|
|
|
|
|
0
|
purgedir($_); |
|
492
|
|
|
|
|
|
|
} |
|
493
|
0
|
|
|
|
|
0
|
mylog "purged 4XX,5XX cache and eliminated $purgecount entries"; |
|
494
|
|
|
|
|
|
|
|
|
495
|
0
|
|
|
|
|
0
|
opendir DIR, "$basedir/conerror/"; |
|
496
|
0
|
|
|
|
|
0
|
foreach ( readdir DIR ) { concachetest $_; } |
|
|
0
|
|
|
|
|
0
|
|
|
497
|
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
} |
|
499
|
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
sub concache($) { |
|
501
|
0
|
|
|
0
|
0
|
0
|
mylog "caching connection failure to $_[0]"; |
|
502
|
0
|
|
|
|
|
0
|
open TOUCH, ">>$basedir/conerror/$_[0]"; |
|
503
|
0
|
|
|
|
|
0
|
print TOUCH '.'; |
|
504
|
0
|
|
|
|
|
0
|
close TOUCH; |
|
505
|
|
|
|
|
|
|
} |
|
506
|
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
sub concachetest($) { |
|
508
|
0
|
0
|
|
0
|
0
|
0
|
-f "$basedir/conerror/$_[0]" or return undef; |
|
509
|
0
|
|
|
|
|
0
|
my @SR = stat(_); |
|
510
|
0
|
0
|
|
|
|
0
|
( time() - $SR[9] ) < $ConRetryDelay and return 1; |
|
511
|
|
|
|
|
|
|
|
|
512
|
0
|
|
|
|
|
0
|
mylog "ready to try connecting to $_[0] again"; |
|
513
|
0
|
0
|
|
|
|
0
|
unlink "$basedir/conerror/$_[0]" or mylog "trouble unlinking $basedir/conerror/$_[0]: $!"; |
|
514
|
|
|
|
|
|
|
|
|
515
|
0
|
|
|
|
|
0
|
undef; |
|
516
|
|
|
|
|
|
|
} |
|
517
|
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
sub cache4($) { |
|
519
|
0
|
|
|
0
|
0
|
0
|
mylog "caching ", $_[0], $line; |
|
520
|
0
|
0
|
|
|
|
0
|
my ( $user, $host ) = split '@', $_[0], 2 or return undef; |
|
521
|
0
|
|
|
|
|
0
|
$host =~ y/A-Z/a-z/; |
|
522
|
0
|
|
|
|
|
0
|
$host =~ s/([^\w\.\-])/'X'.ord($1).'Y'/ge; |
|
|
0
|
|
|
|
|
0
|
|
|
523
|
0
|
|
|
|
|
0
|
$user =~ y/A-Z/a-z/; |
|
524
|
0
|
|
|
|
|
0
|
$user =~ s/([^\w\.\-])/'X'.ord($1).'Y'/ge; |
|
|
0
|
|
|
|
|
0
|
|
|
525
|
0
|
0
|
0
|
|
|
0
|
-d "$basedir/4error/$host" |
|
526
|
|
|
|
|
|
|
or mkdir "$basedir/4error/$host", 0770 |
|
527
|
|
|
|
|
|
|
or die "could not mkdir $basedir/4error/$host: $!"; |
|
528
|
0
|
|
|
|
|
0
|
open CACHE, ">$basedir/4error/$host/$user.TMP$$"; |
|
529
|
0
|
|
|
|
|
0
|
print CACHE time(), "\n$line cached " . localtime() . "\n"; |
|
530
|
0
|
|
|
|
|
0
|
close CACHE; |
|
531
|
0
|
|
|
|
|
0
|
rename "$basedir/4error/$host/$user.TMP$$", "$basedir/4error/$host/$user"; |
|
532
|
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
} |
|
534
|
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
sub cache4test($) { |
|
536
|
0
|
0
|
|
0
|
0
|
0
|
my ( $user, $host ) = split '@', $_[0], 2 or return undef; |
|
537
|
0
|
|
|
|
|
0
|
$host =~ y/A-Z/a-z/; |
|
538
|
0
|
|
|
|
|
0
|
$host =~ s/([^\w\.\-])/'X'.ord($1).'Y'/ge; |
|
|
0
|
|
|
|
|
0
|
|
|
539
|
0
|
|
|
|
|
0
|
$user =~ y/A-Z/a-z/; |
|
540
|
0
|
|
|
|
|
0
|
$user =~ s/([^\w\.\-])/'X'.ord($1).'Y'/ge; |
|
|
0
|
|
|
|
|
0
|
|
|
541
|
0
|
0
|
|
|
|
0
|
-d "$basedir/4error/$host" or return undef; |
|
542
|
0
|
0
|
|
|
|
0
|
-f "$basedir/4error/$host/$user" or return undef; |
|
543
|
0
|
|
|
|
|
0
|
open CACHE, "<$basedir/4error/$host/$user"; |
|
544
|
0
|
|
|
|
|
0
|
my $ctime; |
|
545
|
0
|
|
|
|
|
0
|
( $ctime, $line ) = ; |
|
546
|
0
|
|
|
|
|
0
|
close CACHE; |
|
547
|
|
|
|
|
|
|
|
|
548
|
0
|
0
|
|
|
|
0
|
if ( ( time() - $ctime ) > $FourErrCacheLifetime ) { |
|
549
|
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
# 4-file is more than seven minutes old |
|
551
|
0
|
0
|
|
|
|
0
|
unlink "$basedir/4error/$host/$user" or mylog "trouble unlinking $basedir/4error/$host/$user: $!"; |
|
552
|
0
|
|
|
|
|
0
|
return undef; |
|
553
|
|
|
|
|
|
|
} |
|
554
|
0
|
|
|
|
|
0
|
mylog "4cached ", $line; |
|
555
|
0
|
|
|
|
|
0
|
return $ctime; |
|
556
|
|
|
|
|
|
|
} |
|
557
|
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
sub cache5($) { |
|
559
|
0
|
|
|
0
|
0
|
0
|
mylog "caching ", $_[0], $line; |
|
560
|
0
|
0
|
|
|
|
0
|
my ( $user, $host ) = split '@', $_[0], 2 or return undef; |
|
561
|
0
|
|
|
|
|
0
|
$host =~ y/A-Z/a-z/; |
|
562
|
0
|
|
|
|
|
0
|
$host =~ s/([^\w\.\-])/'X'.ord($1).'Y'/ge; |
|
|
0
|
|
|
|
|
0
|
|
|
563
|
0
|
|
|
|
|
0
|
$user =~ y/A-Z/a-z/; |
|
564
|
0
|
|
|
|
|
0
|
$user =~ s/([^\w\.\-])/'X'.ord($1).'Y'/ge; |
|
|
0
|
|
|
|
|
0
|
|
|
565
|
0
|
0
|
0
|
|
|
0
|
-d "$basedir/5error/$host" |
|
566
|
|
|
|
|
|
|
or mkdir "$basedir/5error/$host", 0770 |
|
567
|
|
|
|
|
|
|
or die "could not mkdir $basedir/5error/$host: $!"; |
|
568
|
0
|
0
|
|
|
|
0
|
open CACHE, ">$basedir/5error/$host/$user.TMP$$" |
|
569
|
|
|
|
|
|
|
or mylog "CACHEfile: $basedir/5error/$host/$user.TMP$$ $!"; |
|
570
|
0
|
|
|
|
|
0
|
print CACHE time(), "\n$line cached " . localtime() . "\n"; |
|
571
|
0
|
|
|
|
|
0
|
close CACHE; |
|
572
|
0
|
|
|
|
|
0
|
rename "$basedir/5error/$host/$user.TMP$$", "$basedir/5error/$host/$user"; |
|
573
|
|
|
|
|
|
|
} |
|
574
|
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
sub cache5test($) { |
|
576
|
0
|
0
|
|
0
|
0
|
0
|
my ( $user, $host ) = split '@', $_[0], 2 or return undef; |
|
577
|
0
|
|
|
|
|
0
|
$host =~ y/A-Z/a-z/; |
|
578
|
0
|
|
|
|
|
0
|
$host =~ s/([^\w\.\-])/'X'.ord($1).'Y'/ge; |
|
|
0
|
|
|
|
|
0
|
|
|
579
|
0
|
|
|
|
|
0
|
$user =~ y/A-Z/a-z/; |
|
580
|
0
|
|
|
|
|
0
|
$user =~ s/([^\w\.\-])/'X'.ord($1).'Y'/ge; |
|
|
0
|
|
|
|
|
0
|
|
|
581
|
0
|
0
|
|
|
|
0
|
-d "$basedir/5error/$host" or return undef; |
|
582
|
0
|
0
|
|
|
|
0
|
-f "$basedir/5error/$host/$user" or return undef; |
|
583
|
0
|
|
|
|
|
0
|
open CACHE, "<$basedir/5error/$host/$user"; |
|
584
|
0
|
|
|
|
|
0
|
flock CACHE, LOCK_SH; |
|
585
|
0
|
|
|
|
|
0
|
my $ctime; |
|
586
|
0
|
|
|
|
|
0
|
( $ctime, $line ) = ; |
|
587
|
0
|
|
|
|
|
0
|
close CACHE; |
|
588
|
|
|
|
|
|
|
|
|
589
|
0
|
0
|
|
|
|
0
|
if ( ( time() - $ctime ) > ( 4 * 60 * 60 ) ) { |
|
590
|
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
# 5-file is more than 4 hours old |
|
592
|
0
|
0
|
|
|
|
0
|
unlink "$basedir/5error/$host/$user" or mylog "trouble unlinking $basedir/5error/$host/$user: $!"; |
|
593
|
0
|
|
|
|
|
0
|
return undef; |
|
594
|
|
|
|
|
|
|
} |
|
595
|
0
|
|
|
|
|
0
|
mylog "5cached ", $line; |
|
596
|
0
|
|
|
|
|
0
|
return $ctime; |
|
597
|
|
|
|
|
|
|
} |
|
598
|
|
|
|
|
|
|
|
|
599
|
2
|
|
|
2
|
|
27088
|
use Socket; |
|
|
2
|
|
|
|
|
10162
|
|
|
|
2
|
|
|
|
|
16070
|
|
|
600
|
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
# { no warnings; sub dnsmx($){ |
|
602
|
|
|
|
|
|
|
# # look up MXes for domain |
|
603
|
|
|
|
|
|
|
# my @mxresults = sort {$a <=> $b} `$dnsmxpath $_[0]`; |
|
604
|
|
|
|
|
|
|
# # djbdns program dnsmx provides lines of form /\d+ $domain\n |
|
605
|
|
|
|
|
|
|
# return map {/\d+ (\S+)/; $1} @mxresults; |
|
606
|
|
|
|
|
|
|
# };}; |
|
607
|
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
# use Net::DNS; now in Import |
|
609
|
|
|
|
|
|
|
# now in import = Net::DNS::Resolver->new; |
|
610
|
|
|
|
|
|
|
sub _dnsmx($) { |
|
611
|
|
|
|
|
|
|
|
|
612
|
2
|
|
|
2
|
|
416
|
my $name = shift; |
|
613
|
|
|
|
|
|
|
|
|
614
|
2
|
|
|
|
|
6
|
my $host = $name; |
|
615
|
2
|
50
|
|
|
|
12
|
if ( exists $SMTProutes{$host} ) { |
|
616
|
0
|
0
|
|
|
|
0
|
ref( $SMTProutes{$host} ) |
|
617
|
|
|
|
|
|
|
and return Scramble( $SMTProutes{$host} ); |
|
618
|
0
|
|
|
|
|
0
|
return ($SMTProutes{$host}); |
|
619
|
|
|
|
|
|
|
} |
|
620
|
2
|
50
|
|
|
|
8
|
if ( exists $SMTProutes{SMARTHOST} ) { |
|
621
|
0
|
0
|
|
|
|
0
|
ref( $SMTProutes{SMARTHOST} ) |
|
622
|
|
|
|
|
|
|
and return Scramble( $SMTProutes{$host} ); |
|
623
|
0
|
|
|
|
|
0
|
return ($SMTProutes{SMARTHOST}); |
|
624
|
|
|
|
|
|
|
}; |
|
625
|
|
|
|
|
|
|
|
|
626
|
2
|
|
|
|
|
14
|
my @mx = map { $_->exchange } mx( $res, $name ); |
|
|
6
|
|
|
|
|
47128
|
|
|
627
|
2
|
50
|
|
|
|
86
|
@mx or return ($name); |
|
628
|
|
|
|
|
|
|
|
|
629
|
2
|
|
|
|
|
14
|
return @mx; |
|
630
|
|
|
|
|
|
|
} |
|
631
|
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
# my $calls; |
|
633
|
|
|
|
|
|
|
# sub SOCKready(){ |
|
634
|
|
|
|
|
|
|
# my $rin=''; |
|
635
|
|
|
|
|
|
|
# vec($rin,fileno('SOCK'),1) = 1; |
|
636
|
|
|
|
|
|
|
# my ($n, $tl) = select(my $r=$rin,undef,undef,0.25); |
|
637
|
|
|
|
|
|
|
# print "$calls\n"; |
|
638
|
|
|
|
|
|
|
# $calls++ > 200 and exit; |
|
639
|
|
|
|
|
|
|
# return $n; |
|
640
|
|
|
|
|
|
|
# }; |
|
641
|
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
my $CRLF = CRLF; |
|
643
|
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
sub eofSOCK() { |
|
645
|
2
|
|
|
2
|
|
30
|
no warnings; |
|
|
2
|
|
|
|
|
6
|
|
|
|
2
|
|
|
|
|
23940
|
|
|
646
|
0
|
|
|
0
|
0
|
|
my $hersockaddr = getpeername(SOCK); |
|
647
|
0
|
0
|
|
|
|
|
if ( defined $hersockaddr ) { |
|
648
|
0
|
|
|
|
|
|
return undef; |
|
649
|
|
|
|
|
|
|
} |
|
650
|
|
|
|
|
|
|
else { |
|
651
|
0
|
|
|
|
|
|
mylog "SOCK not connected"; |
|
652
|
0
|
|
|
|
|
|
return 1; |
|
653
|
|
|
|
|
|
|
} |
|
654
|
|
|
|
|
|
|
} |
|
655
|
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
sub getresponse($) { |
|
657
|
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
# mylog "sending: [$_[0]]"; |
|
659
|
|
|
|
|
|
|
|
|
660
|
0
|
0
|
|
0
|
0
|
|
if (eofSOCK) { |
|
661
|
0
|
|
|
|
|
|
mylog "problem with SOCK"; |
|
662
|
0
|
|
|
|
|
|
return undef; |
|
663
|
|
|
|
|
|
|
} |
|
664
|
|
|
|
|
|
|
|
|
665
|
0
|
|
|
|
|
|
$timeout = 0; |
|
666
|
0
|
|
|
|
|
|
alarm 130; |
|
667
|
0
|
0
|
|
|
|
|
unless ( print SOCK "$_[0]$CRLF" ) { |
|
668
|
0
|
|
|
|
|
|
mylog "print SOCK: $!"; |
|
669
|
0
|
|
|
|
|
|
return undef; |
|
670
|
|
|
|
|
|
|
} |
|
671
|
|
|
|
|
|
|
|
|
672
|
0
|
|
|
|
|
|
DEBUG and mylog "sent $_[0]"; |
|
673
|
|
|
|
|
|
|
|
|
674
|
0
|
|
|
|
|
|
my ( $dash, $response ) = ( '-', '' ); |
|
675
|
0
|
|
|
|
|
|
while ( $dash eq '-' ) { |
|
676
|
0
|
|
|
|
|
|
my $letter; |
|
677
|
|
|
|
|
|
|
my @letters; |
|
678
|
0
|
|
|
|
|
|
my $i = 0; |
|
679
|
0
|
|
|
|
|
|
my $more = 1; |
|
680
|
0
|
|
|
|
|
|
my $BOL = 1; # "beginning of line" |
|
681
|
0
|
|
|
|
|
|
do { |
|
682
|
0
|
0
|
|
|
|
|
if ($timeout) { |
|
683
|
0
|
|
|
|
|
|
mylog "timeout in getresponse"; |
|
684
|
0
|
|
|
|
|
|
return undef; |
|
685
|
|
|
|
|
|
|
} |
|
686
|
0
|
0
|
|
|
|
|
if (eofSOCK) { |
|
687
|
0
|
|
|
|
|
|
mylog "eofSOCK"; |
|
688
|
0
|
|
|
|
|
|
return undef; |
|
689
|
|
|
|
|
|
|
} |
|
690
|
0
|
|
|
|
|
|
sysread( SOCK, $letter, 1 ); |
|
691
|
0
|
0
|
0
|
|
|
|
if ( $letter eq "\r" or $letter eq "\n" ) { |
|
692
|
0
|
|
|
|
|
|
$more = $BOL; |
|
693
|
|
|
|
|
|
|
} |
|
694
|
|
|
|
|
|
|
else { |
|
695
|
0
|
|
|
|
|
|
$BOL = 0; |
|
696
|
0
|
0
|
|
|
|
|
if ( length($letter) ) { |
|
697
|
0
|
|
|
|
|
|
$letters[ $i++ ] = $letter; |
|
698
|
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
# mylog @letters; |
|
700
|
|
|
|
|
|
|
} |
|
701
|
|
|
|
|
|
|
else { |
|
702
|
0
|
|
|
|
|
|
sleep 1; |
|
703
|
|
|
|
|
|
|
} |
|
704
|
|
|
|
|
|
|
} |
|
705
|
|
|
|
|
|
|
} while ($more); |
|
706
|
|
|
|
|
|
|
|
|
707
|
0
|
|
|
|
|
|
my $iline = join( '', @letters ); |
|
708
|
|
|
|
|
|
|
|
|
709
|
0
|
|
|
|
|
|
DEBUG and mylog "received: [$iline]"; |
|
710
|
0
|
|
|
|
|
|
$response .= $iline; |
|
711
|
0
|
|
|
|
|
|
($dash) = $iline =~ /^\d+([\-\ ])/; |
|
712
|
|
|
|
|
|
|
} |
|
713
|
0
|
|
|
|
|
|
$response; |
|
714
|
|
|
|
|
|
|
} |
|
715
|
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
my $onioning = 0; |
|
717
|
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
sub deferralmessage { |
|
719
|
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
# usage: $message->deferralmessage("reason we are deferring") |
|
721
|
|
|
|
|
|
|
|
|
722
|
0
|
0
|
|
0
|
0
|
|
$ReturnAddress =~ /\@/ or return; #suppress doublebounces |
|
723
|
0
|
|
|
|
|
|
my $filename = join '.', time, 'DeferralReport', rand(10000000); |
|
724
|
0
|
|
|
|
|
|
open BOUNCE, ">$basedir/temp/$filename"; |
|
725
|
0
|
|
|
|
|
|
print BOUNCE <
|
|
726
|
|
|
|
|
|
|
<> |
|
727
|
|
|
|
|
|
|
$ReturnAddress |
|
728
|
|
|
|
|
|
|
$dateheader |
|
729
|
|
|
|
|
|
|
Message-Id: <$filename\@$MyDomain> |
|
730
|
|
|
|
|
|
|
From: MAILER-DAEMON |
|
731
|
|
|
|
|
|
|
To: $ReturnAddress |
|
732
|
|
|
|
|
|
|
Subject: delivery deferral to <$Recipient> |
|
733
|
|
|
|
|
|
|
Content-type: text/plain |
|
734
|
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
$_[0] |
|
736
|
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
The first eighty lines of the message follow below: |
|
738
|
|
|
|
|
|
|
------------------------------------------------------------- |
|
739
|
|
|
|
|
|
|
EOF |
|
740
|
|
|
|
|
|
|
|
|
741
|
0
|
|
|
|
|
|
seek( MESSAGE, 0, 0 ); |
|
742
|
0
|
|
|
|
|
|
for ( 1 .. 80 ) { |
|
743
|
0
|
0
|
|
|
|
|
defined( my $lin = ) or last; |
|
744
|
0
|
|
|
|
|
|
print BOUNCE $lin; |
|
745
|
|
|
|
|
|
|
} |
|
746
|
0
|
|
|
|
|
|
close BOUNCE; |
|
747
|
0
|
|
|
|
|
|
rename "$basedir/temp/$filename", "$basedir/immediate/$filename"; |
|
748
|
|
|
|
|
|
|
} |
|
749
|
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
# end sub deferralmessage |
|
751
|
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
sub attempt { |
|
753
|
0
|
0
|
|
0
|
0
|
|
$onioning or $ReuseQuota = $ReuseQuotaInitial; |
|
754
|
0
|
|
|
|
|
|
$line = ''; |
|
755
|
0
|
|
|
|
|
|
$ConnectionProblem = 0; |
|
756
|
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
# deliver and delete, or requeue; also send bounces if appropriate |
|
758
|
0
|
|
|
|
|
|
my $message = shift; |
|
759
|
0
|
|
|
|
|
|
mylog "Attempting [$ReturnAddress] -> [$Recipient]"; |
|
760
|
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
# Message Data is supposed to start on third line |
|
762
|
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
######################################## |
|
764
|
|
|
|
|
|
|
# reuse sock or define global $Domain |
|
765
|
|
|
|
|
|
|
######################################## |
|
766
|
0
|
0
|
0
|
|
|
|
if ( defined($Domain) and $Domain and $Recipient =~ /\@$Domain$/i ) { |
|
|
|
|
0
|
|
|
|
|
|
767
|
0
|
0
|
|
|
|
|
eofSOCK or goto HaveSOCK; |
|
768
|
|
|
|
|
|
|
} |
|
769
|
|
|
|
|
|
|
|
|
770
|
0
|
0
|
|
|
|
|
unless ( ($Domain) = $Recipient =~ /\@([^\s>]+)/ ) { |
|
771
|
0
|
|
|
|
|
|
mylog "no domain in recipient [$Recipient], discarding message"; |
|
772
|
0
|
|
|
|
|
|
close MESSAGE; |
|
773
|
0
|
0
|
|
|
|
|
unlink $$message or mylog "trouble unlinking $$message: $!"; |
|
774
|
|
|
|
|
|
|
|
|
775
|
0
|
|
|
|
|
|
return; |
|
776
|
|
|
|
|
|
|
} |
|
777
|
0
|
|
|
|
|
|
$Domain =~ y/A-Z/a-z/; |
|
778
|
|
|
|
|
|
|
######################################## |
|
779
|
|
|
|
|
|
|
# $Domain is now defined |
|
780
|
|
|
|
|
|
|
######################################## |
|
781
|
|
|
|
|
|
|
|
|
782
|
0
|
0
|
|
|
|
|
if ( concachetest $Domain) { |
|
783
|
0
|
|
|
|
|
|
mylog "$Domain connection failure cached"; |
|
784
|
0
|
|
|
|
|
|
goto ReQueue_unconnected; |
|
785
|
|
|
|
|
|
|
} |
|
786
|
|
|
|
|
|
|
|
|
787
|
0
|
|
|
|
|
|
my @dnsmxes; |
|
788
|
0
|
|
|
|
|
|
@dnsmxes = dnsmx($Domain); |
|
789
|
0
|
|
|
|
|
|
my $dnsmx_count = @dnsmxes; |
|
790
|
0
|
|
|
|
|
|
mylog "[[$Domain]] MX handled by @dnsmxes"; |
|
791
|
0
|
0
|
|
|
|
|
unless (@dnsmxes) { |
|
792
|
0
|
|
|
|
|
|
mylog "requeueing due to empty dnsmx result"; |
|
793
|
0
|
|
|
|
|
|
goto ReQueue_unconnected; |
|
794
|
|
|
|
|
|
|
} |
|
795
|
0
|
|
|
|
|
|
my $Peerout; |
|
796
|
|
|
|
|
|
|
|
|
797
|
0
|
0
|
|
|
|
|
cache4test $Recipient |
|
798
|
|
|
|
|
|
|
and goto ReQueue; |
|
799
|
0
|
0
|
|
|
|
|
cache5test $Recipient |
|
800
|
|
|
|
|
|
|
and goto Bounce; |
|
801
|
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
TryAgain: |
|
803
|
|
|
|
|
|
|
|
|
804
|
0
|
|
|
|
|
|
while ( $Peerout = shift @dnsmxes ) { |
|
805
|
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
# mylog "attempting $Peerout"; |
|
807
|
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
# connect to $Peerout, smtp |
|
809
|
0
|
|
|
|
|
|
my @GHBNres; |
|
810
|
0
|
0
|
|
|
|
|
unless ( @GHBNres = gethostbyname($Peerout) ) { |
|
811
|
0
|
0
|
0
|
|
|
|
if ( $dnsmx_count == 1 |
|
812
|
|
|
|
|
|
|
and $Peerout eq $Domain ) |
|
813
|
|
|
|
|
|
|
{ |
|
814
|
0
|
|
|
|
|
|
mylog $line= "Apparently there is no valid MX for $Domain"; |
|
815
|
0
|
|
|
|
|
|
$ConnectionProblem = 0; |
|
816
|
0
|
|
|
|
|
|
goto Bounce; |
|
817
|
|
|
|
|
|
|
} |
|
818
|
0
|
|
|
|
|
|
next; |
|
819
|
|
|
|
|
|
|
} |
|
820
|
0
|
0
|
|
|
|
|
my $iaddr = $GHBNres[4] or next; |
|
821
|
0
|
|
|
|
|
|
my $paddr = sockaddr_in( 25, $iaddr ); |
|
822
|
0
|
0
|
|
|
|
|
socket( SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp') ) |
|
823
|
|
|
|
|
|
|
or die "$$ socket: $!"; |
|
824
|
|
|
|
|
|
|
|
|
825
|
0
|
0
|
|
|
|
|
if (defined $BindAddress){ |
|
826
|
0
|
0
|
|
|
|
|
bind(SOCK, sockaddr_in(0, inet_aton($BindAddress))) |
|
827
|
|
|
|
|
|
|
or die "could not bind to $BindAddress: $!"; |
|
828
|
|
|
|
|
|
|
}; |
|
829
|
|
|
|
|
|
|
|
|
830
|
0
|
0
|
|
|
|
|
connect( SOCK, $paddr ) || next; |
|
831
|
0
|
|
|
|
|
|
mylog "connected to $Peerout"; |
|
832
|
0
|
|
|
|
|
|
my $oldfh = select(SOCK); |
|
833
|
0
|
|
|
|
|
|
$| = 1; |
|
834
|
0
|
|
|
|
|
|
select($oldfh); |
|
835
|
0
|
|
|
|
|
|
goto SMTPsession; |
|
836
|
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
} |
|
838
|
|
|
|
|
|
|
|
|
839
|
0
|
|
|
|
|
|
concache $Domain; |
|
840
|
0
|
|
|
|
|
|
mylog "Unable to establish SMTP connection to $Domain MX"; |
|
841
|
0
|
|
|
|
|
|
$ConnectionProblem = 1; |
|
842
|
0
|
|
|
|
|
|
goto ReQueue_unconnected; |
|
843
|
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
# talk SMTP |
|
845
|
|
|
|
|
|
|
SMTPsession: |
|
846
|
|
|
|
|
|
|
$SIG{ALRM} = sub { |
|
847
|
0
|
|
|
0
|
|
|
mylog 'TIMEOUT -- caught alarm signal in attempt()'; |
|
848
|
0
|
|
|
|
|
|
$message->requeue("timed out during SMTP interaction"); |
|
849
|
0
|
|
|
|
|
|
close MESSAGE; |
|
850
|
0
|
0
|
|
|
|
|
unlink $$message or mylog "trouble unlinking $$message: $!"; |
|
851
|
0
|
0
|
|
|
|
|
$onioning and unlink "$basedir/domain/$Domain.$$"; |
|
852
|
0
|
0
|
|
|
|
|
$ONCE or exit; |
|
853
|
0
|
|
|
|
|
|
}; |
|
854
|
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
# expect 220 |
|
856
|
0
|
|
|
|
|
|
alarm 60; |
|
857
|
0
|
|
|
|
|
|
my $Greetingcounter = 0; |
|
858
|
0
|
|
|
|
|
|
ExpectGreeting: |
|
859
|
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
my @GreetArr = (); |
|
861
|
0
|
|
|
|
|
|
do { |
|
862
|
0
|
0
|
|
|
|
|
eval { defined( $line = ) or die "no line from socket. [$!]"; }; |
|
|
0
|
|
|
|
|
|
|
|
863
|
0
|
0
|
0
|
|
|
|
if ( $@ or ++$Greetingcounter > 20 ) { |
|
864
|
0
|
|
|
|
|
|
mylog @GreetArr, "Error: $@"; |
|
865
|
0
|
|
|
|
|
|
close SOCK; |
|
866
|
0
|
|
|
|
|
|
goto TryAgain; |
|
867
|
|
|
|
|
|
|
} |
|
868
|
0
|
|
|
|
|
|
chomp $line; |
|
869
|
0
|
|
|
|
|
|
mylog $line; |
|
870
|
0
|
|
|
|
|
|
push @GreetArr, $line; |
|
871
|
|
|
|
|
|
|
} while ( substr( $line, 0, 4 ) ne '220 ' ) |
|
872
|
|
|
|
|
|
|
; # this condition will enforce greeting compliance |
|
873
|
|
|
|
|
|
|
|
|
874
|
0
|
|
|
|
|
|
$line = join ' / ', @GreetArr; |
|
875
|
0
|
|
|
|
|
|
$line =~ s/[\r\n]//g; |
|
876
|
0
|
0
|
|
|
|
|
@GreetArr > 1 and mylog "extended greeting: $line"; |
|
877
|
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
# print SOCK "HELO $MyDomain",CRLF; |
|
879
|
|
|
|
|
|
|
# expect 250 |
|
880
|
|
|
|
|
|
|
# $line = getresponse "HELO $MyDomain" or goto TryAgain; |
|
881
|
0
|
0
|
|
|
|
|
$line = getresponse "EHLO $MyDomain" or goto TryAgain; |
|
882
|
0
|
0
|
|
|
|
|
unless ( $line =~ /^250[ \-]/ ) { |
|
883
|
0
|
|
|
|
|
|
mylog "peer not happy with EHLO: [$line]"; |
|
884
|
0
|
0
|
|
|
|
|
$line = getresponse "HELO $MyDomain" or goto TryAgain; |
|
885
|
0
|
0
|
|
|
|
|
unless ( $line =~ /^250[ \-]/ ) { |
|
886
|
0
|
|
|
|
|
|
mylog "peer not happy with HELO: [$line]"; |
|
887
|
0
|
|
|
|
|
|
close SOCK; |
|
888
|
0
|
|
|
|
|
|
goto TryAgain; |
|
889
|
|
|
|
|
|
|
} |
|
890
|
|
|
|
|
|
|
} |
|
891
|
0
|
|
|
|
|
|
mylog $line; |
|
892
|
|
|
|
|
|
|
|
|
893
|
0
|
0
|
|
|
|
|
HaveSOCK: |
|
894
|
|
|
|
|
|
|
$line = getresponse "RSET" or goto TryAgain; |
|
895
|
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
# expect 250 |
|
897
|
|
|
|
|
|
|
# $line = getresponse; |
|
898
|
|
|
|
|
|
|
# mylog "RSET and got [$line]"; |
|
899
|
0
|
0
|
|
|
|
|
unless ( $line =~ /^250[ \-]/ ) { |
|
900
|
0
|
|
|
|
|
|
mylog |
|
901
|
|
|
|
|
|
|
"peer not happy with RSET: [$line] will not reuse this connection"; |
|
902
|
0
|
|
|
|
|
|
$ReuseQuota = 0; |
|
903
|
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
# close SOCK; |
|
905
|
|
|
|
|
|
|
# goto TryAgain; |
|
906
|
|
|
|
|
|
|
} |
|
907
|
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
# remove angle brackets if any |
|
909
|
0
|
|
|
|
|
|
$ReturnAddress =~ s/^.*/; |
|
910
|
0
|
|
|
|
|
|
$ReturnAddress =~ s/>.*$//; |
|
911
|
|
|
|
|
|
|
|
|
912
|
0
|
0
|
|
|
|
|
$line = getresponse "MAIL FROM:<$ReturnAddress>" or goto TryAgain; |
|
913
|
0
|
|
|
|
|
|
mylog "$line"; |
|
914
|
0
|
0
|
|
|
|
|
unless ( $line =~ /^[2]/ ) { |
|
915
|
0
|
|
|
|
|
|
mylog "peer not happy with return address: [$line]"; |
|
916
|
0
|
0
|
|
|
|
|
if ( $line =~ /^[4]/ ) { |
|
917
|
0
|
|
|
|
|
|
mylog "requeueing"; |
|
918
|
0
|
|
|
|
|
|
goto ReQueue; |
|
919
|
|
|
|
|
|
|
} |
|
920
|
0
|
0
|
|
|
|
|
if ( $line =~ /^[5]/ ) { |
|
921
|
0
|
|
|
|
|
|
goto Bounce; |
|
922
|
|
|
|
|
|
|
} |
|
923
|
0
|
|
|
|
|
|
mylog "and response was neither 2,4 or 5 coded."; |
|
924
|
0
|
|
|
|
|
|
goto TryAgain; |
|
925
|
|
|
|
|
|
|
} |
|
926
|
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
# print SOCK "RCPT TO: <$Recipient>\r\n"; |
|
928
|
|
|
|
|
|
|
# expect 250 |
|
929
|
0
|
|
|
|
|
|
my @recips4; |
|
930
|
|
|
|
|
|
|
my @recips5; |
|
931
|
|
|
|
|
|
|
|
|
932
|
0
|
0
|
|
|
|
|
@Recipients > 1 and do { |
|
933
|
0
|
|
|
|
|
|
for ( my $i = 0 ; $i < @Recipients ; $i++ ) { |
|
934
|
0
|
|
|
|
|
|
my $r = int rand @Recipients; |
|
935
|
0
|
|
|
|
|
|
@Recipients[ $i, $r ] = @Recipients[ $r, $i ]; |
|
936
|
|
|
|
|
|
|
} |
|
937
|
|
|
|
|
|
|
}; |
|
938
|
|
|
|
|
|
|
|
|
939
|
0
|
|
|
|
|
|
my @GoodR; |
|
940
|
|
|
|
|
|
|
my @emsgmap; |
|
941
|
0
|
|
|
|
|
|
foreach (@Recipients) { |
|
942
|
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
# remove angle brackets if any |
|
944
|
0
|
|
|
|
|
|
s/^.*/; |
|
945
|
0
|
|
|
|
|
|
s/>.*$//; |
|
946
|
|
|
|
|
|
|
|
|
947
|
0
|
0
|
|
|
|
|
$line = getresponse "RCPT TO:<$_>" or goto TryAgain; |
|
948
|
0
|
0
|
|
|
|
|
if ( $line =~ /^2/ ) { |
|
949
|
0
|
|
|
|
|
|
push @GoodR, $_; |
|
950
|
|
|
|
|
|
|
} |
|
951
|
|
|
|
|
|
|
else { |
|
952
|
0
|
|
|
|
|
|
mylog "peer not happy with recipient $_: [$line]"; |
|
953
|
0
|
0
|
|
|
|
|
if ( $line =~ /^4/ ) { |
|
|
|
0
|
|
|
|
|
|
|
954
|
0
|
0
|
|
|
|
|
if ( @Recipients > 1 ) { |
|
955
|
0
|
|
|
|
|
|
push @recips4, $_; |
|
956
|
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
# no emsgmap4 is needed because 4-deferred recipients |
|
958
|
|
|
|
|
|
|
# get split apart, eventually there will be only one |
|
959
|
|
|
|
|
|
|
# in the message and then 4-bounces will happen |
|
960
|
|
|
|
|
|
|
} |
|
961
|
|
|
|
|
|
|
else { |
|
962
|
0
|
|
|
|
|
|
cache4 $Recipient; |
|
963
|
0
|
|
|
|
|
|
mylog "requeueing"; |
|
964
|
0
|
|
|
|
|
|
goto ReQueue; |
|
965
|
|
|
|
|
|
|
} |
|
966
|
|
|
|
|
|
|
} |
|
967
|
|
|
|
|
|
|
elsif ( $line =~ /^5/ ) { |
|
968
|
0
|
0
|
|
|
|
|
if ( @Recipients > 1 ) { |
|
969
|
0
|
0
|
|
|
|
|
if (/\@$Domain$/) { |
|
970
|
0
|
|
|
|
|
|
push @recips5, $_; |
|
971
|
0
|
|
|
|
|
|
push @emsgmap, " $_: $line"; |
|
972
|
|
|
|
|
|
|
} |
|
973
|
|
|
|
|
|
|
else { |
|
974
|
0
|
|
|
|
|
|
push @recips4, $_; |
|
975
|
|
|
|
|
|
|
} |
|
976
|
|
|
|
|
|
|
} |
|
977
|
|
|
|
|
|
|
else { |
|
978
|
0
|
|
|
|
|
|
cache5 $Recipient; |
|
979
|
0
|
|
|
|
|
|
goto Bounce; |
|
980
|
|
|
|
|
|
|
} |
|
981
|
|
|
|
|
|
|
} |
|
982
|
|
|
|
|
|
|
else { |
|
983
|
0
|
|
|
|
|
|
mylog |
|
984
|
|
|
|
|
|
|
"noncompliant SMTP peer [$Peerout] gave funny response $line"; |
|
985
|
0
|
|
|
|
|
|
goto TryAgain; |
|
986
|
|
|
|
|
|
|
} |
|
987
|
|
|
|
|
|
|
} |
|
988
|
|
|
|
|
|
|
} |
|
989
|
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
ReQueueFours: |
|
991
|
0
|
0
|
|
|
|
|
if ( @recips4 + @recips5 ) { |
|
992
|
0
|
|
|
|
|
|
DEBUG and warn "4: @recips4"; |
|
993
|
0
|
|
|
|
|
|
DEBUG and warn "5: @recips5"; |
|
994
|
0
|
0
|
|
|
|
|
if ( @recips5 == @Recipients ) { |
|
995
|
0
|
|
|
|
|
|
goto Bounce; |
|
996
|
|
|
|
|
|
|
} |
|
997
|
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
# if ((@recips5 + @recips4) == @Recipients){ |
|
999
|
|
|
|
|
|
|
# goto ReQueue; |
|
1000
|
|
|
|
|
|
|
# }; |
|
1001
|
|
|
|
|
|
|
|
|
1002
|
2
|
|
|
2
|
|
14
|
my $counter = $ReQ::counter++; INIT { $ReQ::counter='a' }; |
|
|
0
|
|
|
|
|
|
|
|
1003
|
0
|
|
|
|
|
|
open BODY, ">$basedir/temp/BODY.$$.$counter"; |
|
1004
|
0
|
|
|
|
|
|
eval "END{ close BODY; unlink '$basedir/temp/BODY.$$.$counter' }"; |
|
1005
|
0
|
|
|
|
|
|
while () { |
|
1006
|
0
|
|
|
|
|
|
print BODY $_; |
|
1007
|
|
|
|
|
|
|
} |
|
1008
|
0
|
|
|
|
|
|
close BODY; |
|
1009
|
0
|
|
|
|
|
|
open MESSAGE, "<$basedir/temp/BODY.$$.$counter"; |
|
1010
|
|
|
|
|
|
|
|
|
1011
|
0
|
0
|
|
|
|
|
if (@recips4) { |
|
1012
|
0
|
|
|
|
|
|
DEBUG and warn "requeing for @recips4"; |
|
1013
|
0
|
|
|
|
|
|
open ONE, ">$basedir/temp/RETRY.$$.$counter.ONE"; |
|
1014
|
0
|
|
|
|
|
|
print ONE "$ReturnAddress\n"; |
|
1015
|
0
|
0
|
|
|
|
|
if (@recips4 > 1 ){ |
|
1016
|
0
|
|
|
|
|
|
open TWO, ">$basedir/temp/RETRY.$$.$counter.TWO"; |
|
1017
|
0
|
|
|
|
|
|
print TWO "$ReturnAddress\n"; |
|
1018
|
0
|
|
|
|
|
|
while (@recips4) { |
|
1019
|
0
|
|
|
|
|
|
print ONE ( ( shift @recips4 ) . "\n" ); |
|
1020
|
0
|
0
|
|
|
|
|
@recips4 and print TWO ( ( shift @recips4 ) . "\n" ); |
|
1021
|
|
|
|
|
|
|
} |
|
1022
|
0
|
|
|
|
|
|
print ONE "\nX-TipJar-Mta-Requeue-A-$dateheader"; |
|
1023
|
0
|
|
|
|
|
|
print TWO "\nX-TipJar-Mta-Requeue-B-$dateheader"; |
|
1024
|
0
|
|
|
|
|
|
while () { |
|
1025
|
0
|
|
|
|
|
|
print ONE $_; |
|
1026
|
0
|
|
|
|
|
|
print TWO $_; |
|
1027
|
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
} |
|
1029
|
0
|
|
|
|
|
|
close TWO; |
|
1030
|
0
|
|
|
|
|
|
close ONE; |
|
1031
|
0
|
|
|
|
|
|
rename "$basedir/temp/RETRY.$$.$counter.ONE", |
|
1032
|
|
|
|
|
|
|
"$basedir/RETRY4a" . rand(98765); |
|
1033
|
0
|
|
|
|
|
|
rename "$basedir/temp/RETRY.$$.$counter.TWO", |
|
1034
|
|
|
|
|
|
|
"$basedir/RETRY4b" . rand(98765); |
|
1035
|
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
}else{ |
|
1037
|
0
|
|
|
|
|
|
print ONE ( ( shift @recips4 ) . "\n\n" ); |
|
1038
|
0
|
|
|
|
|
|
print ONE "X-TipJar-Mta-Singleton-Requeue-$dateheader"; |
|
1039
|
0
|
|
|
|
|
|
print ONE (); |
|
1040
|
0
|
|
|
|
|
|
close ONE; |
|
1041
|
0
|
|
|
|
|
|
rename "$basedir/temp/RETRY.$$.$counter.ONE", |
|
1042
|
|
|
|
|
|
|
"$basedir/".rand(99999)."RETRY4singleton" . rand(98765); |
|
1043
|
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
}; |
|
1045
|
0
|
|
|
|
|
|
open MESSAGE, "<$basedir/temp/BODY.$$.$counter"; |
|
1046
|
|
|
|
|
|
|
RECIP5: |
|
1047
|
0
|
|
|
|
|
|
while (@recips5) { |
|
1048
|
0
|
0
|
|
|
|
|
$ReturnAddress =~ /\@/ or last; #suppress doublebounces |
|
1049
|
|
|
|
|
|
|
|
|
1050
|
|
|
|
|
|
|
# grep {$ReturnAddress =~ m/$_/} @NoBounceRegexList and goto GoodDelivery |
|
1051
|
0
|
|
|
|
|
|
for (@NoBounceRegexList) { |
|
1052
|
0
|
0
|
|
|
|
|
if ( $ReturnAddress =~ m/$_/ ) { |
|
1053
|
0
|
|
|
|
|
|
mylog "suppressing bounce to <$ReturnAddress>"; |
|
1054
|
0
|
|
|
|
|
|
next RECIP5; |
|
1055
|
|
|
|
|
|
|
} |
|
1056
|
|
|
|
|
|
|
} |
|
1057
|
0
|
|
|
|
|
|
mylog "bouncing to <$ReturnAddress>"; |
|
1058
|
0
|
|
|
|
|
|
my $filename = join '.', time(), 'HardFail', rand(10000000); |
|
1059
|
0
|
|
|
|
|
|
open BOUNCE, ">$basedir/temp/$filename"; |
|
1060
|
0
|
|
|
|
|
|
local $" = "\n"; |
|
1061
|
0
|
|
|
|
|
|
print BOUNCE <
|
|
1062
|
|
|
|
|
|
|
<> |
|
1063
|
|
|
|
|
|
|
$ReturnAddress |
|
1064
|
|
|
|
|
|
|
$dateheader |
|
1065
|
|
|
|
|
|
|
Message-Id: <$filename\@$MyDomain> |
|
1066
|
|
|
|
|
|
|
From: MAILER-DAEMON |
|
1067
|
|
|
|
|
|
|
To: $ReturnAddress |
|
1068
|
|
|
|
|
|
|
Subject: multiple SMTP rejections for <@recips5> |
|
1069
|
|
|
|
|
|
|
Content-type: text/plain |
|
1070
|
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
While connected to SMTP peer $Peerout, |
|
1072
|
|
|
|
|
|
|
the $MyDomain e-mail system received the error messages |
|
1073
|
|
|
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
@emsgmap |
|
1075
|
|
|
|
|
|
|
|
|
1076
|
|
|
|
|
|
|
which indicate permanent errors. |
|
1077
|
|
|
|
|
|
|
The first hundred and fifty lines of the message follow below: |
|
1078
|
|
|
|
|
|
|
------------------------------------------------------------- |
|
1079
|
|
|
|
|
|
|
EOF |
|
1080
|
|
|
|
|
|
|
|
|
1081
|
0
|
|
|
|
|
|
for ( 1 .. 150 ) { |
|
1082
|
0
|
0
|
|
|
|
|
defined( my $lin = ) or last; |
|
1083
|
0
|
|
|
|
|
|
print BOUNCE $lin; |
|
1084
|
|
|
|
|
|
|
} |
|
1085
|
0
|
|
|
|
|
|
close BOUNCE; |
|
1086
|
0
|
|
|
|
|
|
mylog "renaming temp file to immediate $filename"; |
|
1087
|
0
|
|
|
|
|
|
rename "$basedir/temp/$filename", |
|
1088
|
|
|
|
|
|
|
"$basedir/immediate/$filename"; |
|
1089
|
|
|
|
|
|
|
} |
|
1090
|
0
|
|
|
|
|
|
@recips5 = (); |
|
1091
|
|
|
|
|
|
|
} |
|
1092
|
0
|
|
|
|
|
|
open MESSAGE, "<$basedir/temp/BODY.$$.$counter"; |
|
1093
|
|
|
|
|
|
|
} |
|
1094
|
|
|
|
|
|
|
|
|
1095
|
0
|
0
|
|
|
|
|
$PostDataTrouble and goto GoodDelivery; |
|
1096
|
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
# DATA_TRANSACTION: |
|
1098
|
0
|
|
|
|
|
|
$Recipient = "@GoodR"; |
|
1099
|
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
# print SOCK "DATA\r\n"; |
|
1101
|
|
|
|
|
|
|
# expect 354 |
|
1102
|
0
|
0
|
|
|
|
|
$line = getresponse 'DATA' or goto TryAgain; |
|
1103
|
0
|
0
|
|
|
|
|
unless ( $line =~ /^354 / ) { |
|
1104
|
0
|
|
|
|
|
|
mylog "peer not happy with DATA: [$line]"; |
|
1105
|
0
|
0
|
|
|
|
|
if ( @GoodR == 1 ) { |
|
1106
|
0
|
0
|
|
|
|
|
if ( $line =~ /^4/ ) { |
|
1107
|
0
|
|
|
|
|
|
goto ReQueue; |
|
1108
|
|
|
|
|
|
|
} |
|
1109
|
0
|
0
|
|
|
|
|
if ( $line =~ /^5/ ) { |
|
1110
|
0
|
|
|
|
|
|
goto Bounce; |
|
1111
|
|
|
|
|
|
|
} |
|
1112
|
0
|
|
|
|
|
|
mylog "reporting noncompliant SMTP peer [$Peerout]"; |
|
1113
|
0
|
|
|
|
|
|
goto TryAgain; |
|
1114
|
|
|
|
|
|
|
} |
|
1115
|
0
|
|
|
|
|
|
@recips4 = @GoodR; |
|
1116
|
0
|
|
|
|
|
|
$PostDataTrouble = 1; |
|
1117
|
0
|
|
|
|
|
|
goto ReQueueFours; |
|
1118
|
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
} |
|
1120
|
0
|
|
|
|
|
|
my $linecount; |
|
1121
|
|
|
|
|
|
|
my $bytecount; |
|
1122
|
0
|
0
|
|
|
|
|
print SOCK "X-Tipjar-Mta-Transmitted-By: $MyDomain\r\n" or die $!; |
|
1123
|
0
|
|
|
|
|
|
while () { |
|
1124
|
0
|
|
|
|
|
|
$linecount++; |
|
1125
|
0
|
|
|
|
|
|
$bytecount += length; |
|
1126
|
0
|
|
|
|
|
|
chomp; |
|
1127
|
0
|
|
|
|
|
|
eval { |
|
1128
|
0
|
|
|
|
|
|
alarm 60; |
|
1129
|
0
|
0
|
|
|
|
|
if ( $_ eq '.' ) { |
|
1130
|
0
|
0
|
|
|
|
|
print SOCK "..\r\n" or die $!; |
|
1131
|
|
|
|
|
|
|
} |
|
1132
|
|
|
|
|
|
|
else { |
|
1133
|
0
|
0
|
|
|
|
|
print SOCK $_, "\r\n" or die $!; |
|
1134
|
|
|
|
|
|
|
} |
|
1135
|
|
|
|
|
|
|
}; |
|
1136
|
0
|
0
|
|
|
|
|
if ($@) { |
|
1137
|
0
|
|
|
|
|
|
mylog $@; |
|
1138
|
0
|
|
|
|
|
|
goto TryAgain; |
|
1139
|
|
|
|
|
|
|
} |
|
1140
|
|
|
|
|
|
|
} |
|
1141
|
0
|
|
|
|
|
|
close MESSAGE; |
|
1142
|
|
|
|
|
|
|
# print SOCK ".\r\n"; |
|
1143
|
|
|
|
|
|
|
# expect 250 |
|
1144
|
0
|
|
|
|
|
|
mylog "$linecount lines ($bytecount chars) of message data, sending dot" |
|
1145
|
|
|
|
|
|
|
; # TryAgain will pop the MX list when there are more than 1 MX |
|
1146
|
0
|
0
|
|
|
|
|
$line = getresponse '.' or goto TryAgain; |
|
1147
|
0
|
0
|
|
|
|
|
unless ( $line =~ /^2/ ) { |
|
1148
|
0
|
|
|
|
|
|
mylog "peer not happy with message body: [$line]"; |
|
1149
|
0
|
0
|
|
|
|
|
if ( $line =~ /^4/ ) { |
|
1150
|
0
|
|
|
|
|
|
@recips4 = @GoodR; |
|
1151
|
0
|
|
|
|
|
|
$PostDataTrouble = 1; |
|
1152
|
0
|
0
|
|
|
|
|
@recips4 > 1 and goto ReQueueFours; |
|
1153
|
0
|
|
|
|
|
|
mylog "requeueing"; |
|
1154
|
0
|
|
|
|
|
|
goto ReQueue; |
|
1155
|
|
|
|
|
|
|
} |
|
1156
|
0
|
0
|
|
|
|
|
if ( $line =~ /^5/ ) { |
|
1157
|
0
|
|
|
|
|
|
goto Bounce; |
|
1158
|
|
|
|
|
|
|
} |
|
1159
|
0
|
|
|
|
|
|
mylog "reporting noncompliant SMTP peer [$Peerout]"; |
|
1160
|
0
|
|
|
|
|
|
goto TryAgain; |
|
1161
|
|
|
|
|
|
|
} |
|
1162
|
|
|
|
|
|
|
|
|
1163
|
0
|
|
|
|
|
|
goto GoodDelivery; |
|
1164
|
|
|
|
|
|
|
|
|
1165
|
0
|
|
|
|
|
|
ReQueue: |
|
1166
|
|
|
|
|
|
|
$message->requeue($line); |
|
1167
|
0
|
|
|
|
|
|
goto GoodDelivery; |
|
1168
|
|
|
|
|
|
|
|
|
1169
|
0
|
|
|
|
|
|
ReQueue_unconnected: |
|
1170
|
|
|
|
|
|
|
$message->requeue($line); |
|
1171
|
0
|
|
|
|
|
|
return undef; |
|
1172
|
|
|
|
|
|
|
|
|
1173
|
0
|
0
|
|
|
|
|
Bounce: |
|
1174
|
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
$ReturnAddress =~ /\@/ or goto GoodDelivery; #suppress doublebounces |
|
1176
|
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
# grep {$ReturnAddress =~ m/$_/} @NoBounceRegexList and goto GoodDelivery |
|
1178
|
0
|
|
|
|
|
|
for (@NoBounceRegexList) { |
|
1179
|
0
|
0
|
|
|
|
|
if ( $ReturnAddress =~ m/$_/ ) { |
|
1180
|
0
|
|
|
|
|
|
mylog "suppressing bounce to <$ReturnAddress>"; |
|
1181
|
|
|
|
|
|
|
|
|
1182
|
0
|
|
|
|
|
|
goto GoodDelivery; |
|
1183
|
|
|
|
|
|
|
} |
|
1184
|
|
|
|
|
|
|
} |
|
1185
|
0
|
|
|
|
|
|
mylog "bouncing to <$ReturnAddress>"; |
|
1186
|
0
|
|
|
|
|
|
my $filename = join '.', time(), 'HardFail', rand(10000000); |
|
1187
|
0
|
|
|
|
|
|
open BOUNCE, ">$basedir/temp/$filename"; |
|
1188
|
0
|
0
|
|
|
|
|
defined($line) or $line = 'unknown reason'; |
|
1189
|
0
|
0
|
|
|
|
|
defined($Recipient) or $Recipient = 'unknown recipient'; |
|
1190
|
0
|
0
|
|
|
|
|
defined($ReturnAddress) or $ReturnAddress = '<>'; |
|
1191
|
0
|
0
|
|
|
|
|
defined($Peerout) or $Peerout = 'unknown peer'; |
|
1192
|
|
|
|
|
|
|
|
|
1193
|
0
|
|
|
|
|
|
print BOUNCE <
|
|
1194
|
|
|
|
|
|
|
<> |
|
1195
|
|
|
|
|
|
|
$ReturnAddress |
|
1196
|
|
|
|
|
|
|
$dateheader |
|
1197
|
|
|
|
|
|
|
Message-Id: <$filename\@$MyDomain> |
|
1198
|
|
|
|
|
|
|
From: MAILER-DAEMON |
|
1199
|
|
|
|
|
|
|
To: $ReturnAddress |
|
1200
|
|
|
|
|
|
|
Subject: delivery failure to <$Recipient> |
|
1201
|
|
|
|
|
|
|
Content-type: text/plain |
|
1202
|
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
While connected to SMTP peer $Peerout, |
|
1204
|
|
|
|
|
|
|
the $MyDomain e-mail system received the error message |
|
1205
|
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
$line |
|
1207
|
|
|
|
|
|
|
|
|
1208
|
|
|
|
|
|
|
which indicates a permanent error. |
|
1209
|
|
|
|
|
|
|
The first hundred and fifty lines of the message follow below: |
|
1210
|
|
|
|
|
|
|
------------------------------------------------------------- |
|
1211
|
|
|
|
|
|
|
EOF |
|
1212
|
|
|
|
|
|
|
|
|
1213
|
0
|
|
|
|
|
|
seek( MESSAGE, 0, 0 ); |
|
1214
|
0
|
|
|
|
|
|
for ( 1 .. 150 ) { |
|
1215
|
0
|
0
|
|
|
|
|
defined( my $lin = ) or last; |
|
1216
|
0
|
|
|
|
|
|
print BOUNCE $lin; |
|
1217
|
|
|
|
|
|
|
} |
|
1218
|
0
|
|
|
|
|
|
close BOUNCE; |
|
1219
|
0
|
|
|
|
|
|
rename "$basedir/temp/$filename", "$basedir/immediate/$filename"; |
|
1220
|
|
|
|
|
|
|
|
|
1221
|
0
|
|
|
|
|
|
GoodDelivery: |
|
1222
|
|
|
|
|
|
|
undef $Recipient; |
|
1223
|
0
|
|
|
|
|
|
close MESSAGE; # windows can't unlink an open file |
|
1224
|
0
|
0
|
|
|
|
|
unlink $$message or die "FAILED TO UNLINK $$message: $!"; # "true" |
|
1225
|
|
|
|
|
|
|
|
|
1226
|
0
|
|
|
|
|
|
alarm 0; |
|
1227
|
0
|
0
|
|
|
|
|
if ($onioning) { |
|
1228
|
0
|
|
|
|
|
|
mylog "already onioning"; |
|
1229
|
0
|
|
|
|
|
|
return; |
|
1230
|
|
|
|
|
|
|
} |
|
1231
|
0
|
0
|
|
|
|
|
if ( -f "$basedir/domain/$Domain" ) { |
|
1232
|
0
|
|
|
|
|
|
mylog "onioning $Domain"; |
|
1233
|
0
|
|
|
|
|
|
open DOMAINLOCK, ">>$basedir/domain/.lock"; |
|
1234
|
0
|
|
|
|
|
|
flock DOMAINLOCK, LOCK_EX; |
|
1235
|
0
|
|
|
|
|
|
rename "$basedir/domain/$Domain", "$basedir/domain/$Domain.$$"; |
|
1236
|
0
|
|
|
|
|
|
flock DOMAINLOCK, LOCK_UN; |
|
1237
|
0
|
|
|
|
|
|
close DOMAINLOCK; |
|
1238
|
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
# sleep 4; # let any writers finish writing |
|
1240
|
0
|
|
|
|
|
|
local *DOMAINLIST; |
|
1241
|
0
|
|
|
|
|
|
$onioning++; |
|
1242
|
0
|
|
|
|
|
|
open DOMAINLIST, "<$basedir/domain/$Domain.$$"; |
|
1243
|
0
|
|
|
|
|
|
while () { |
|
1244
|
0
|
|
|
|
|
|
chomp; |
|
1245
|
0
|
0
|
|
|
|
|
-f $_ or next; |
|
1246
|
0
|
0
|
0
|
|
|
|
if ( --$ReuseQuota < 0 or eofSOCK ) { # no more socket reuse. |
|
1247
|
0
|
|
|
|
|
|
open MOREDOMAIN, ">>$basedir/domain/$Domain"; |
|
1248
|
0
|
|
|
|
|
|
flock MOREDOMAIN, LOCK_EX; |
|
1249
|
0
|
|
|
|
|
|
seek MOREDOMAIN, 2, 0; |
|
1250
|
0
|
|
|
|
|
|
while () { |
|
1251
|
0
|
|
|
|
|
|
chomp; |
|
1252
|
0
|
0
|
|
|
|
|
-f $_ or next; |
|
1253
|
0
|
|
|
|
|
|
print MOREDOMAIN "$_\n"; |
|
1254
|
|
|
|
|
|
|
} |
|
1255
|
0
|
|
|
|
|
|
flock MOREDOMAIN, LOCK_UN; |
|
1256
|
0
|
|
|
|
|
|
close MOREDOMAIN; |
|
1257
|
0
|
|
|
|
|
|
last; |
|
1258
|
|
|
|
|
|
|
} |
|
1259
|
0
|
|
|
|
|
|
mylog "reusing sock with $_"; |
|
1260
|
0
|
|
|
|
|
|
my $M = newmessage $_; # sets some globals |
|
1261
|
0
|
0
|
|
|
|
|
$M or next; |
|
1262
|
0
|
|
|
|
|
|
$M->attempt(); |
|
1263
|
0
|
|
|
|
|
|
undef $Recipient; |
|
1264
|
|
|
|
|
|
|
}; |
|
1265
|
0
|
|
|
|
|
|
close DOMAINLIST; |
|
1266
|
0
|
0
|
|
|
|
|
unlink "$basedir/domain/$Domain.$$" or mylog "trouble unlinking DOMAINLIST domain/$Domain.$$: $!"; |
|
1267
|
0
|
|
|
|
|
|
$onioning--; |
|
1268
|
|
|
|
|
|
|
} |
|
1269
|
|
|
|
|
|
|
else { |
|
1270
|
0
|
|
|
|
|
|
mylog "no onion file for $Domain"; |
|
1271
|
|
|
|
|
|
|
} |
|
1272
|
|
|
|
|
|
|
|
|
1273
|
0
|
0
|
|
|
|
|
eofSOCK or mylog getresponse 'QUIT'; |
|
1274
|
0
|
|
|
|
|
|
close SOCK; |
|
1275
|
|
|
|
|
|
|
|
|
1276
|
0
|
|
|
|
|
|
return; |
|
1277
|
|
|
|
|
|
|
|
|
1278
|
|
|
|
|
|
|
} |
|
1279
|
|
|
|
|
|
|
|
|
1280
|
|
|
|
|
|
|
sub requeue { |
|
1281
|
0
|
|
|
0
|
0
|
|
my $message = shift; |
|
1282
|
0
|
0
|
|
|
|
|
-f $$message or do { |
|
1283
|
0
|
|
|
|
|
|
mylog "message $$message is missing, probably already reQd."; |
|
1284
|
0
|
|
|
|
|
|
return; |
|
1285
|
|
|
|
|
|
|
}; |
|
1286
|
0
|
|
|
|
|
|
my @stat = stat(_); |
|
1287
|
0
|
|
|
|
|
|
my $reason = shift; |
|
1288
|
0
|
|
|
|
|
|
my ( $fdir, $fname ) = $$message =~ m#^(.+)/([^/]+)$#; |
|
1289
|
0
|
|
|
|
|
|
my $age = $time - $stat[9]; |
|
1290
|
0
|
|
|
|
|
|
mylog "reQing $$message which is $age seconds old"; |
|
1291
|
0
|
|
|
|
|
|
DEBUG and warn "reQing $$message which is $age seconds old"; |
|
1292
|
|
|
|
|
|
|
|
|
1293
|
0
|
0
|
|
|
|
|
if ( $age > OneWeek ) { |
|
1294
|
0
|
|
|
|
|
|
mylog "bouncing message $age seconds old"; |
|
1295
|
0
|
0
|
|
|
|
|
$ReturnAddress =~ /\@/ or goto unlinkme; #suppress doublebounces |
|
1296
|
0
|
|
|
|
|
|
my $filename = join '.', time, $$, 'FinalFail', rand(10000000); |
|
1297
|
0
|
|
|
|
|
|
open BOUNCE, ">$basedir/temp/$filename"; |
|
1298
|
0
|
|
|
|
|
|
print BOUNCE <
|
|
1299
|
|
|
|
|
|
|
<> |
|
1300
|
|
|
|
|
|
|
$ReturnAddress |
|
1301
|
|
|
|
|
|
|
$dateheader |
|
1302
|
|
|
|
|
|
|
Message-Id: <$filename\@$MyDomain> |
|
1303
|
|
|
|
|
|
|
From: MAILER-DAEMON |
|
1304
|
|
|
|
|
|
|
To: $ReturnAddress |
|
1305
|
|
|
|
|
|
|
Subject: delivery failure to <$Recipient> |
|
1306
|
|
|
|
|
|
|
Content-type: text/plain |
|
1307
|
|
|
|
|
|
|
|
|
1308
|
|
|
|
|
|
|
A message has been enqueued for delivery for over a week, |
|
1309
|
|
|
|
|
|
|
the $MyDomain e-mail system is deleting it. |
|
1310
|
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
Final temporary deferral reason: |
|
1312
|
|
|
|
|
|
|
$reason |
|
1313
|
|
|
|
|
|
|
|
|
1314
|
|
|
|
|
|
|
The first hundred and fifty lines of the message follow below: |
|
1315
|
|
|
|
|
|
|
------------------------------------------------------------- |
|
1316
|
|
|
|
|
|
|
EOF |
|
1317
|
|
|
|
|
|
|
|
|
1318
|
0
|
|
|
|
|
|
seek( MESSAGE, 0, 0 ); |
|
1319
|
0
|
|
|
|
|
|
for ( 1 .. 150 ) { |
|
1320
|
0
|
0
|
|
|
|
|
defined( my $lin = ) or last; |
|
1321
|
0
|
|
|
|
|
|
print BOUNCE $lin; |
|
1322
|
|
|
|
|
|
|
} |
|
1323
|
0
|
|
|
|
|
|
close BOUNCE; |
|
1324
|
0
|
|
|
|
|
|
rename "$basedir/temp/$filename", "$basedir/immediate/$filename"; |
|
1325
|
|
|
|
|
|
|
|
|
1326
|
0
|
|
|
|
|
|
unlinkme: |
|
1327
|
|
|
|
|
|
|
close MESSAGE; |
|
1328
|
0
|
0
|
|
|
|
|
unlink $$message or mylog "trouble unlinking $$message: $!"; |
|
1329
|
|
|
|
|
|
|
|
|
1330
|
|
|
|
|
|
|
# clean up per-domain queue |
|
1331
|
0
|
|
|
|
|
|
DLpurge; |
|
1332
|
0
|
|
|
|
|
|
return; |
|
1333
|
|
|
|
|
|
|
} |
|
1334
|
|
|
|
|
|
|
|
|
1335
|
0
|
0
|
0
|
|
|
|
if ( |
|
|
|
|
0
|
|
|
|
|
|
1336
|
|
|
|
|
|
|
$age > $AgeBeforeDeferralReport |
|
1337
|
|
|
|
|
|
|
and $reason |
|
1338
|
|
|
|
|
|
|
and $ReturnAddress =~ /\@/ # suppress doublebounces |
|
1339
|
|
|
|
|
|
|
) |
|
1340
|
|
|
|
|
|
|
{ |
|
1341
|
0
|
|
|
|
|
|
my $filename = join '.', time, $$, 'ReQueue', rand(10000000); |
|
1342
|
0
|
|
|
|
|
|
open BOUNCE, ">$basedir/temp/$filename"; |
|
1343
|
0
|
|
|
|
|
|
print BOUNCE <
|
|
1344
|
|
|
|
|
|
|
<> |
|
1345
|
|
|
|
|
|
|
$ReturnAddress |
|
1346
|
|
|
|
|
|
|
$dateheader |
|
1347
|
|
|
|
|
|
|
Message-Id: <$filename\@$MyDomain> |
|
1348
|
|
|
|
|
|
|
From: MAILER-DAEMON |
|
1349
|
|
|
|
|
|
|
To: $ReturnAddress |
|
1350
|
|
|
|
|
|
|
Subject: delivery deferral to <$Recipient> |
|
1351
|
|
|
|
|
|
|
Content-type: text/plain |
|
1352
|
|
|
|
|
|
|
|
|
1353
|
|
|
|
|
|
|
The $MyDomain e-mail system is not able to deliver |
|
1354
|
|
|
|
|
|
|
a message to $Recipient right now. |
|
1355
|
|
|
|
|
|
|
Attempts will continue until the message is over a week old. |
|
1356
|
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
Temporary deferral reason: |
|
1358
|
|
|
|
|
|
|
$reason |
|
1359
|
|
|
|
|
|
|
|
|
1360
|
|
|
|
|
|
|
The first hundred and fifty lines of the message follow below: |
|
1361
|
|
|
|
|
|
|
------------------------------------------------------------- |
|
1362
|
|
|
|
|
|
|
EOF |
|
1363
|
|
|
|
|
|
|
|
|
1364
|
0
|
|
|
|
|
|
seek( MESSAGE, 0, 0 ); |
|
1365
|
0
|
|
|
|
|
|
for ( 1 .. 150 ) { |
|
1366
|
0
|
0
|
|
|
|
|
defined( my $lin = ) or last; |
|
1367
|
0
|
|
|
|
|
|
print BOUNCE $lin; |
|
1368
|
|
|
|
|
|
|
} |
|
1369
|
0
|
|
|
|
|
|
close BOUNCE; |
|
1370
|
0
|
|
|
|
|
|
rename "$basedir/temp/$filename", "$basedir/immediate/$filename"; |
|
1371
|
|
|
|
|
|
|
|
|
1372
|
|
|
|
|
|
|
} |
|
1373
|
|
|
|
|
|
|
; # if old enough to report as deferred |
|
1374
|
|
|
|
|
|
|
|
|
1375
|
0
|
|
|
|
|
|
my $futuretime = int( time + 100 + ( $age * ( 3 + rand(2) ) / 4 ) ); |
|
1376
|
|
|
|
|
|
|
|
|
1377
|
|
|
|
|
|
|
# print "futuretime will be $futuretime\n"; |
|
1378
|
0
|
|
|
|
|
|
my @DirPieces = split / /, strftime "%Y %m %d %H %M %S", |
|
1379
|
|
|
|
|
|
|
localtime $futuretime; |
|
1380
|
|
|
|
|
|
|
|
|
1381
|
|
|
|
|
|
|
# print "dir,subdir is $dir,$subdir\n"; |
|
1382
|
0
|
|
|
|
|
|
my $dir = "$basedir/queue"; |
|
1383
|
0
|
|
|
|
|
|
while (@DirPieces) { |
|
1384
|
0
|
|
|
|
|
|
$dir .= ( '/' . shift @DirPieces ); |
|
1385
|
0
|
0
|
0
|
|
|
|
-d $dir |
|
1386
|
|
|
|
|
|
|
or mkdir $dir, 0777 |
|
1387
|
|
|
|
|
|
|
or croak "$$ Permissions problems: mkdir $dir: [$!]\n"; |
|
1388
|
|
|
|
|
|
|
} |
|
1389
|
|
|
|
|
|
|
|
|
1390
|
0
|
|
|
|
|
|
rename $$message, "$dir/$fname"; |
|
1391
|
0
|
|
|
|
|
|
mylog "message queued to $dir/$fname"; |
|
1392
|
|
|
|
|
|
|
|
|
1393
|
0
|
0
|
|
|
|
|
$ConnectionProblem and DLsave("$dir/$fname"); |
|
1394
|
|
|
|
|
|
|
} |
|
1395
|
|
|
|
|
|
|
|
|
1396
|
|
|
|
|
|
|
sub DLpurge() { |
|
1397
|
|
|
|
|
|
|
|
|
1398
|
|
|
|
|
|
|
# -f "$basedir/domain/$Domain" or return; |
|
1399
|
|
|
|
|
|
|
# rename fails when source file ain't there |
|
1400
|
0
|
0
|
|
0
|
0
|
|
rename "$basedir/domain/$Domain", "$basedir/domain/$Domain$$" or return; |
|
1401
|
0
|
|
|
|
|
|
my $fn; |
|
1402
|
0
|
|
|
|
|
|
open DOMAINLIST, "<$basedir/domain/$Domain$$"; |
|
1403
|
|
|
|
|
|
|
|
|
1404
|
0
|
|
|
|
|
|
while ( $fn = ) { |
|
1405
|
0
|
|
|
|
|
|
chomp $fn; |
|
1406
|
0
|
|
|
|
|
|
my ($namepart) = ( $fn =~ m{([^/]+)$} ); |
|
1407
|
0
|
|
|
|
|
|
rename $fn, "$basedir/immediate/DRUSH$$.$namepart"; |
|
1408
|
|
|
|
|
|
|
} |
|
1409
|
|
|
|
|
|
|
|
|
1410
|
0
|
|
|
|
|
|
close DOMAINLIST; |
|
1411
|
0
|
0
|
|
|
|
|
unlink "$basedir/domain/$Domain$$" or mylog "trouble unlinking domainlist $Domain$$: $!"; |
|
1412
|
|
|
|
|
|
|
} |
|
1413
|
|
|
|
|
|
|
|
|
1414
|
|
|
|
|
|
|
sub DLsave($) { |
|
1415
|
0
|
0
|
|
0
|
0
|
|
open DOMAINLISTLOCK, ">>$basedir/domain/.lock" |
|
1416
|
|
|
|
|
|
|
or return mylog "could not open [$basedir/domain/.lock] for append"; |
|
1417
|
0
|
|
|
|
|
|
alarm 0; # we're going to block for the lock |
|
1418
|
0
|
|
|
|
|
|
flock DOMAINLISTLOCK, LOCK_EX; |
|
1419
|
0
|
0
|
|
|
|
|
open DOMAINLIST, ">>$basedir/domain/$Domain" |
|
1420
|
|
|
|
|
|
|
or return mylog "could not open [$basedir/domain/$Domain] for append"; |
|
1421
|
0
|
|
|
|
|
|
print DOMAINLIST "$_[0]\n"; |
|
1422
|
0
|
|
|
|
|
|
close DOMAINLIST; |
|
1423
|
0
|
|
|
|
|
|
flock DOMAINLISTLOCK, LOCK_UN; |
|
1424
|
0
|
|
|
|
|
|
close DOMAINLISTLOCK; |
|
1425
|
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
} |
|
1427
|
|
|
|
|
|
|
|
|
1428
|
|
|
|
|
|
|
1; |
|
1429
|
|
|
|
|
|
|
__END__ |