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__ |