line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Haineko::SMTPD::Session; |
2
|
3
|
|
|
3
|
|
3002
|
use feature ':5.10'; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
389
|
|
3
|
3
|
|
|
3
|
|
19
|
use strict; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
106
|
|
4
|
3
|
|
|
3
|
|
17
|
use warnings; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
89
|
|
5
|
3
|
|
|
3
|
|
942
|
use Class::Accessor::Lite; |
|
3
|
|
|
|
|
1117
|
|
|
3
|
|
|
|
|
27
|
|
6
|
3
|
|
|
3
|
|
25045
|
use Haineko::SMTPD::Response; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
112
|
|
7
|
3
|
|
|
3
|
|
2494
|
use Haineko::SMTPD::Address; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
92
|
|
8
|
3
|
|
|
3
|
|
1201
|
use Time::Piece; |
|
3
|
|
|
|
|
21752
|
|
|
3
|
|
|
|
|
26
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
my $rwaccessors = [ |
11
|
|
|
|
|
|
|
'stage', # (Integer) |
12
|
|
|
|
|
|
|
'started', # (Time::Piece) When it connected |
13
|
|
|
|
|
|
|
'response', # (Ref->Array->Haineko::SMTPD::Response) SMTP Reponse |
14
|
|
|
|
|
|
|
'addresser', # (Haineko::SMTPD::Address) Envelope sender |
15
|
|
|
|
|
|
|
'recipient', # (Ref->Arrey->Haineko::SMTPD::Address) Envelope recipients |
16
|
|
|
|
|
|
|
]; |
17
|
|
|
|
|
|
|
my $roaccessors = [ |
18
|
|
|
|
|
|
|
'queueid', # (String) Queue ID |
19
|
|
|
|
|
|
|
'referer', # (String) HTTP REFERER |
20
|
|
|
|
|
|
|
'useragent', # (String) User agent name |
21
|
|
|
|
|
|
|
'remoteaddr', # (String) Client IP address |
22
|
|
|
|
|
|
|
'remoteport', # (String) Client port number |
23
|
|
|
|
|
|
|
]; |
24
|
|
|
|
|
|
|
my $woaccessors = []; |
25
|
|
|
|
|
|
|
Class::Accessor::Lite->mk_accessors( @$rwaccessors ); |
26
|
|
|
|
|
|
|
Class::Accessor::Lite->mk_ro_accessors( @$roaccessors ); |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
sub new { |
30
|
15
|
|
|
15
|
1
|
573
|
my $class = shift; |
31
|
15
|
|
|
|
|
91
|
my $argvs = { @_ }; |
32
|
15
|
|
100
|
|
|
82
|
my $nekor = $argvs->{'response'} || undef; |
33
|
15
|
|
50
|
|
|
124
|
my $nekos = { |
|
|
|
66
|
|
|
|
|
34
|
|
|
|
|
|
|
'stage' => $argvs->{'stage'} // 0, |
35
|
|
|
|
|
|
|
'started' => Time::Piece->new, |
36
|
|
|
|
|
|
|
'queueid' => $argvs->{'queueid'} || __PACKAGE__->make_queueid, |
37
|
|
|
|
|
|
|
}; |
38
|
|
|
|
|
|
|
|
39
|
15
|
100
|
|
|
|
866
|
if( $nekor ) { |
40
|
2
|
100
|
|
|
|
13
|
if( ref $nekor eq 'Haineko::SMTPD::Response' ) { |
|
|
50
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# Response in the argument is an object |
42
|
1
|
|
|
|
|
3
|
$nekos->{'response'} = [ $nekor ]; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
} elsif( ref $nekor eq 'ARRAY' ) { |
45
|
|
|
|
|
|
|
# Response in the argument is an array reference |
46
|
1
|
|
|
|
|
3
|
$nekos->{'response'} = []; |
47
|
1
|
|
|
|
|
3
|
for my $e ( @$nekor ) { |
48
|
|
|
|
|
|
|
# Check each item: |
49
|
|
|
|
|
|
|
# Haineko::SMTPD::Response object or HASH reference |
50
|
1
|
50
|
|
|
|
8
|
if( ref $e eq 'Haineko::SMTPD::Response' ) { |
|
|
50
|
|
|
|
|
|
51
|
0
|
|
|
|
|
0
|
push @{ $nekos->{'response'} }, $e; |
|
0
|
|
|
|
|
0
|
|
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
} elsif( ref $e eq 'HASH' ) { |
54
|
|
|
|
|
|
|
# Create Haineko::SMTPD::Response object from the HASH reference |
55
|
1
|
|
|
|
|
2
|
push @{ $nekos->{'response'} }, Haineko::SMTPD::Response->new( %$e ); |
|
1
|
|
|
|
|
8
|
|
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
} |
60
|
15
|
|
100
|
|
|
30
|
map { $nekos->{ $_ } ||= $argvs->{ $_ } || undef } @$roaccessors; |
|
75
|
|
100
|
|
|
423
|
|
61
|
|
|
|
|
|
|
|
62
|
15
|
|
|
|
|
20
|
while(1) { |
63
|
|
|
|
|
|
|
# Create email address objects |
64
|
15
|
|
|
|
|
23
|
my $c = 'Haineko::SMTPD::Address'; |
65
|
15
|
|
|
|
|
29
|
my $r = []; |
66
|
15
|
|
100
|
|
|
80
|
my $t = $argvs->{'recipient'} || []; |
67
|
|
|
|
|
|
|
|
68
|
15
|
|
|
|
|
33
|
map { push @$r, $c->new( 'address' => $_ ) } @$t; |
|
1
|
|
|
|
|
8
|
|
69
|
15
|
100
|
|
|
|
43
|
$nekos->{'recipient'} = $r if scalar @$r; |
70
|
|
|
|
|
|
|
|
71
|
15
|
100
|
|
|
|
66
|
last unless defined $argvs->{'addresser'}; |
72
|
1
|
|
|
|
|
4
|
$nekos->{'addresser'} = $c->new( 'address' => $argvs->{'addresser'} ); |
73
|
|
|
|
|
|
|
|
74
|
1
|
|
|
|
|
3
|
last; |
75
|
|
|
|
|
|
|
} |
76
|
15
|
|
|
|
|
85
|
return bless $nekos, __PACKAGE__; |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub make_queueid { |
80
|
17
|
|
|
17
|
1
|
11924
|
my $class = shift; |
81
|
17
|
|
|
|
|
65
|
my $size1 = 16; |
82
|
17
|
|
|
|
|
150
|
my $time1 = new Time::Piece; |
83
|
17
|
|
|
|
|
2056
|
my $chars = [ '0'..'9', 'A'..'Z', 'a'..'x' ]; |
84
|
17
|
|
|
|
|
44
|
my $idstr = q(); |
85
|
17
|
|
|
|
|
127
|
my $queue = { |
86
|
|
|
|
|
|
|
'Y' => $chars->[ $time1->_year % 60 ], |
87
|
|
|
|
|
|
|
'M' => $chars->[ $time1->_mon ], |
88
|
|
|
|
|
|
|
'D' => $chars->[ $time1->mday ], |
89
|
|
|
|
|
|
|
'h' => $chars->[ $time1->hour ], |
90
|
|
|
|
|
|
|
'm' => $chars->[ $time1->min ], |
91
|
|
|
|
|
|
|
's' => $chars->[ $time1->sec ], |
92
|
|
|
|
|
|
|
'q' => $chars->[ int rand(60) ], |
93
|
|
|
|
|
|
|
'p' => sprintf( "%05d", $$ ), |
94
|
|
|
|
|
|
|
}; |
95
|
|
|
|
|
|
|
|
96
|
17
|
|
|
|
|
1136
|
$idstr .= $queue->{ $_ } for ( qw/Y M D h m s q p/ ); |
97
|
|
|
|
|
|
|
|
98
|
17
|
|
|
|
|
51
|
while(1) { |
99
|
68
|
|
|
|
|
123
|
$idstr .= $chars->[ int rand( scalar( @$chars ) ) ]; |
100
|
68
|
100
|
|
|
|
180
|
last if length $idstr == $size1; |
101
|
|
|
|
|
|
|
} |
102
|
17
|
|
|
|
|
273
|
return $idstr; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
sub done { |
106
|
28
|
|
|
28
|
0
|
480
|
my $class = shift; |
107
|
28
|
|
50
|
|
|
83
|
my $argvs = shift || return 0; # (String) SMTP Command |
108
|
28
|
|
|
|
|
146
|
my $value = { |
109
|
|
|
|
|
|
|
'ehlo' => ( 1 << 0 ), |
110
|
|
|
|
|
|
|
'auth' => ( 1 << 1 ), |
111
|
|
|
|
|
|
|
'mail' => ( 1 << 2 ), |
112
|
|
|
|
|
|
|
'rcpt' => ( 1 << 3 ), |
113
|
|
|
|
|
|
|
'data' => ( 1 << 4 ), |
114
|
|
|
|
|
|
|
'quit' => ( 1 << 5 ), |
115
|
|
|
|
|
|
|
}; |
116
|
28
|
|
50
|
|
|
160
|
return $value->{ $argvs } || 0; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
sub add_response { |
120
|
14
|
|
|
14
|
0
|
25
|
my $self = shift; |
121
|
14
|
|
50
|
|
|
52
|
my $argv = shift || return $self; |
122
|
|
|
|
|
|
|
|
123
|
14
|
50
|
|
|
|
50
|
return $self unless ref $argv eq 'Haineko::SMTPD::Response'; |
124
|
14
|
|
|
|
|
20
|
push @{ $self->{'response'} }, $argv; |
|
14
|
|
|
|
|
52
|
|
125
|
14
|
|
|
|
|
32
|
return $self; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub ehlo { |
129
|
9
|
|
|
9
|
0
|
591
|
my $self = shift; |
130
|
9
|
|
50
|
|
|
27
|
my $argv = shift || 0; # (Integer) |
131
|
9
|
|
|
|
|
61
|
my $ehlo = __PACKAGE__->done('ehlo'); |
132
|
9
|
50
|
|
|
|
36
|
$self->{'stage'} = $ehlo if $argv; |
133
|
9
|
50
|
|
|
|
42
|
return $self->{'stage'} & $ehlo ? 1 : 0; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub auth { |
137
|
1
|
|
|
1
|
0
|
652
|
my $self = shift; |
138
|
1
|
|
50
|
|
|
5
|
my $argv = shift || 0; |
139
|
1
|
|
|
|
|
5
|
my $auth = __PACKAGE__->done('auth'); |
140
|
1
|
50
|
|
|
|
5
|
$self->{'stage'} |= $auth if $argv; |
141
|
1
|
50
|
|
|
|
6
|
return $self->{'stage'} & $auth ? 1 : 0; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
sub mail { |
145
|
7
|
|
|
7
|
0
|
577
|
my $self = shift; |
146
|
7
|
|
50
|
|
|
27
|
my $argv = shift || 0; |
147
|
7
|
|
|
|
|
20
|
my $mail = __PACKAGE__->done('mail'); |
148
|
7
|
50
|
|
|
|
25
|
$self->{'stage'} |= $mail if $argv; |
149
|
7
|
50
|
|
|
|
30
|
return $self->{'stage'} & $mail ? 1 : 0; |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
sub rcpt { |
153
|
3
|
|
|
3
|
0
|
522
|
my $self = shift; |
154
|
3
|
|
50
|
|
|
13
|
my $argv = shift || 0; |
155
|
3
|
|
|
|
|
11
|
my $rcpt = __PACKAGE__->done('rcpt'); |
156
|
3
|
50
|
|
|
|
12
|
$self->{'stage'} |= $rcpt if $argv; |
157
|
3
|
50
|
|
|
|
15
|
return $self->{'stage'} & $rcpt ? 1 : 0; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
sub data { |
161
|
1
|
|
|
1
|
0
|
552
|
my $self = shift; |
162
|
1
|
|
50
|
|
|
5
|
my $argv = shift || 0; |
163
|
1
|
|
|
|
|
3
|
my $data = __PACKAGE__->done('data'); |
164
|
1
|
50
|
|
|
|
5
|
$self->{'stage'} |= $data if $argv; |
165
|
1
|
50
|
|
|
|
5
|
return $self->{'stage'} & $data ? 1 : 0; |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
sub rset { |
169
|
1
|
|
|
1
|
0
|
512
|
my $self = shift; |
170
|
1
|
|
|
|
|
5
|
$self->{'stage'} = __PACKAGE__->done('ehlo'); |
171
|
1
|
|
|
|
|
3
|
return 1; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub quit { |
175
|
1
|
|
|
1
|
0
|
537
|
my $self = shift; |
176
|
1
|
|
|
|
|
4
|
$self->{'stage'} = 0; |
177
|
1
|
|
|
|
|
3
|
return 1; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub damn { |
181
|
13
|
|
|
13
|
1
|
100
|
my $self = shift; |
182
|
13
|
|
|
|
|
25
|
my $smtp = {}; |
183
|
|
|
|
|
|
|
|
184
|
13
|
|
|
|
|
40
|
for my $e ( @$rwaccessors, @$roaccessors ) { |
185
|
|
|
|
|
|
|
|
186
|
130
|
100
|
|
|
|
506
|
next if $e =~ m/(?:response|addresser|recipient|started|stage)/; |
187
|
65
|
|
|
|
|
157
|
$smtp->{ $e } = $self->{ $e }; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
13
|
|
|
|
|
19
|
while(1) { |
191
|
13
|
50
|
|
|
|
49
|
last unless defined $self->{'addresser'}; |
192
|
0
|
0
|
|
|
|
0
|
last unless ref $self->{'addresser'}; |
193
|
0
|
0
|
|
|
|
0
|
last unless ref $self->{'addresser'} eq 'Haineko::SMTPD::Address'; |
194
|
|
|
|
|
|
|
|
195
|
0
|
|
|
|
|
0
|
$smtp->{'addresser'} = $self->{'addresser'}->address; |
196
|
0
|
|
|
|
|
0
|
last; |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
13
|
|
|
|
|
21
|
while(1) { |
200
|
13
|
50
|
|
|
|
45
|
last unless defined $self->{'recipient'}; |
201
|
0
|
0
|
|
|
|
0
|
last unless ref $self->{'recipient'} eq 'ARRAY'; |
202
|
|
|
|
|
|
|
|
203
|
0
|
|
|
|
|
0
|
$smtp->{'recipient'} = []; |
204
|
0
|
|
|
|
|
0
|
for my $e ( @{ $self->{'recipient'} } ) { |
|
0
|
|
|
|
|
0
|
|
205
|
|
|
|
|
|
|
|
206
|
0
|
0
|
|
|
|
0
|
next unless ref $e eq 'Haineko::SMTPD::Address'; |
207
|
0
|
|
|
|
|
0
|
push @{ $smtp->{'recipient'} }, $e->address; |
|
0
|
|
|
|
|
0
|
|
208
|
|
|
|
|
|
|
} |
209
|
0
|
|
|
|
|
0
|
last; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
13
|
|
|
|
|
25
|
while(1) { |
213
|
13
|
50
|
|
|
|
37
|
last unless defined $self->{'response'}; |
214
|
13
|
50
|
|
|
|
159
|
last unless ref $self->{'response'} eq 'ARRAY'; |
215
|
|
|
|
|
|
|
|
216
|
13
|
|
|
|
|
33
|
$smtp->{'response'} = []; |
217
|
13
|
|
|
|
|
23
|
for my $e ( @{ $self->{'response'} } ) { |
|
13
|
|
|
|
|
34
|
|
218
|
15
|
50
|
|
|
|
37
|
next unless ref $e eq 'Haineko::SMTPD::Response'; |
219
|
15
|
|
|
|
|
20
|
push @{ $smtp->{'response'} }, $e->damn; |
|
15
|
|
|
|
|
50
|
|
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
13
|
50
|
|
|
|
23
|
last if scalar @{ $smtp->{'response'} }; |
|
13
|
|
|
|
|
42
|
|
223
|
0
|
|
|
|
|
0
|
$smtp->{'response'} = [ Haineko::SMTPD::Response->new ]; |
224
|
0
|
|
|
|
|
0
|
last; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
13
|
|
|
|
|
655
|
$smtp->{'timestamp'} = { |
228
|
|
|
|
|
|
|
'datetime' => $self->started->cdate, |
229
|
|
|
|
|
|
|
'unixtime' => $self->started->epoch, |
230
|
|
|
|
|
|
|
}; |
231
|
13
|
|
|
|
|
921
|
return $smtp; |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
1; |
235
|
|
|
|
|
|
|
__END__ |