| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Net::SPOCP::Protocol; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
19
|
use 5.006; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
36
|
|
|
4
|
1
|
|
|
1
|
|
4
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
22
|
|
|
5
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
33
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
@Net::SPOCP::Protocol::ISA = qw(Net::SPOCP); |
|
8
|
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
4
|
use Carp; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
47
|
|
|
10
|
1
|
|
|
1
|
|
755
|
use IO::Socket::INET; |
|
|
1
|
|
|
|
|
23831
|
|
|
|
1
|
|
|
|
|
8
|
|
|
11
|
1
|
|
|
1
|
|
1749
|
use IO::Socket::SSL; |
|
|
1
|
|
|
|
|
59809
|
|
|
|
1
|
|
|
|
|
9
|
|
|
12
|
1
|
|
|
1
|
|
878
|
use Authen::SASL; |
|
|
1
|
|
|
|
|
1304
|
|
|
|
1
|
|
|
|
|
6
|
|
|
13
|
1
|
|
|
1
|
|
730
|
use MIME::Base64; |
|
|
1
|
|
|
|
|
751
|
|
|
|
1
|
|
|
|
|
1663
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub init |
|
16
|
|
|
|
|
|
|
{ |
|
17
|
1
|
|
|
1
|
0
|
10
|
$_[0]->connect(); |
|
18
|
|
|
|
|
|
|
} |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub connect |
|
21
|
|
|
|
|
|
|
{ |
|
22
|
1
|
|
|
1
|
0
|
2
|
my $self = shift; |
|
23
|
|
|
|
|
|
|
|
|
24
|
1
|
50
|
|
|
|
10
|
$self->disconnect() if ref $self->{_sock}; |
|
25
|
1
|
|
50
|
|
|
29
|
$self->{_sock} = IO::Socket::INET->new(PeerAddr=>$self->{server}, |
|
26
|
|
|
|
|
|
|
Proto=>'tcp', |
|
27
|
|
|
|
|
|
|
Timeout=>$self->{timeout} || 300); |
|
28
|
|
|
|
|
|
|
|
|
29
|
1
|
50
|
33
|
|
|
1072545
|
croak "Net::SPOCP::connect failed: $!\n" |
|
30
|
|
|
|
|
|
|
unless $self->{_sock} && $self->{_sock}->connected; |
|
31
|
|
|
|
|
|
|
} |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
sub DESTROY |
|
34
|
|
|
|
|
|
|
{ |
|
35
|
1
|
|
|
1
|
|
91
|
my $self = shift; |
|
36
|
1
|
50
|
33
|
|
|
17
|
$self->disconnect() if $self->{_sock} && $self->{_sock}->connected; |
|
37
|
|
|
|
|
|
|
} |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub disconnect |
|
40
|
|
|
|
|
|
|
{ |
|
41
|
1
|
|
|
1
|
0
|
32
|
my $self = shift; |
|
42
|
|
|
|
|
|
|
eval |
|
43
|
1
|
|
|
|
|
3
|
{ |
|
44
|
1
|
|
|
|
|
10
|
$self->logout(); |
|
45
|
1
|
50
|
|
|
|
6
|
$self->{_sock}->close(SSL_no_shutdown=>1) if $self->{_tls}; |
|
46
|
1
|
|
|
|
|
88
|
$self->{_sock}->shutdown(2); |
|
47
|
|
|
|
|
|
|
}; |
|
48
|
1
|
50
|
|
|
|
3712
|
if ($@) { carp "Net::SPOCP::disconnect: $@\n"; } |
|
|
0
|
|
|
|
|
0
|
|
|
49
|
1
|
|
|
|
|
310
|
$self->{_sock} = undef; |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub starttls |
|
53
|
|
|
|
|
|
|
{ |
|
54
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
55
|
0
|
|
|
|
|
0
|
my $res = $self->send(Net::SPOCP::Request::Starttls->new())->recv; |
|
56
|
0
|
0
|
|
|
|
0
|
if($res->code() == 205) |
|
57
|
|
|
|
|
|
|
{ |
|
58
|
0
|
|
|
|
|
0
|
$self->{_sock} = IO::Socket::SSL->start_SSL($self->{_sock}, |
|
59
|
|
|
|
|
|
|
SSL_verify_mode => 0x01, |
|
60
|
|
|
|
|
|
|
SSL_ca_file => $self->{ssl_ca_file}); |
|
61
|
|
|
|
|
|
|
} |
|
62
|
0
|
0
|
|
|
|
0
|
if($res->code() != 205) |
|
63
|
|
|
|
|
|
|
{ |
|
64
|
0
|
|
|
|
|
0
|
croak("Net::SPOCP: Failed starting tls, probably forbidden by server.") |
|
65
|
|
|
|
|
|
|
} |
|
66
|
0
|
|
|
|
|
0
|
$res; |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
sub query |
|
70
|
|
|
|
|
|
|
{ |
|
71
|
1
|
|
|
1
|
0
|
143
|
my $self = shift; |
|
72
|
|
|
|
|
|
|
|
|
73
|
1
|
|
|
|
|
3
|
my $rule = $_[0]; |
|
74
|
1
|
50
|
|
|
|
12
|
unless (UNIVERSAL::isa('Net::SPOCP::SExpr',$_[0])) |
|
75
|
|
|
|
|
|
|
{ |
|
76
|
1
|
|
|
|
|
11
|
$rule = Net::SPOCP::SExpr->new($_[0]); |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
|
|
79
|
1
|
|
|
|
|
21
|
$self->send(Net::SPOCP::Request::Query->new(rule=>$rule,path=>'/'))->recv(); |
|
80
|
|
|
|
|
|
|
} |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub capa |
|
83
|
|
|
|
|
|
|
{ |
|
84
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
85
|
0
|
|
|
|
|
0
|
$self->send(Net::SPOCP::Request::Capa->new())->recv(); |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub auth |
|
89
|
|
|
|
|
|
|
{ |
|
90
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
91
|
0
|
|
|
|
|
0
|
my $mech = shift; |
|
92
|
0
|
|
|
|
|
0
|
my $callbacks = shift; |
|
93
|
0
|
|
|
|
|
0
|
my $res; |
|
94
|
|
|
|
|
|
|
|
|
95
|
0
|
|
|
|
|
0
|
$mech =~ m/(\w+):(\w+)/; |
|
96
|
|
|
|
|
|
|
|
|
97
|
0
|
0
|
|
|
|
0
|
$callbacks = "" unless $callbacks; |
|
98
|
|
|
|
|
|
|
|
|
99
|
0
|
|
|
|
|
0
|
my $sasl = Authen::SASL->new( |
|
100
|
|
|
|
|
|
|
mechanism => "$2", |
|
101
|
|
|
|
|
|
|
callback => "$callbacks", |
|
102
|
|
|
|
|
|
|
); |
|
103
|
|
|
|
|
|
|
|
|
104
|
0
|
|
|
|
|
0
|
$self->{server} =~ m/([\w\d\.-]+):(\d+)/; |
|
105
|
0
|
|
|
|
|
0
|
my $server = $1; |
|
106
|
|
|
|
|
|
|
|
|
107
|
0
|
|
|
|
|
0
|
my $conn = $sasl->client_new("spocp", "$server"); |
|
108
|
0
|
0
|
|
|
|
0
|
die($conn->code()) if $conn->code() < 0; |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
{ |
|
111
|
0
|
|
|
|
|
0
|
my $data = encode_base64($conn->client_start(), ''); |
|
|
0
|
|
|
|
|
0
|
|
|
112
|
|
|
|
|
|
|
|
|
113
|
0
|
|
|
|
|
0
|
$res = $self->send(Net::SPOCP::Request::Auth->new( |
|
114
|
|
|
|
|
|
|
mech => $mech, |
|
115
|
|
|
|
|
|
|
data => $data))->recv(); |
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
|
|
118
|
0
|
|
|
|
|
0
|
while($res->code == 301) |
|
119
|
|
|
|
|
|
|
{ |
|
120
|
0
|
|
|
|
|
0
|
my $dec_data = decode_base64($res->[0]->data); |
|
121
|
0
|
|
|
|
|
0
|
my $raw_data = $conn->client_step($dec_data); |
|
122
|
0
|
0
|
|
|
|
0
|
my $data = encode_base64($raw_data, '') if $raw_data; |
|
123
|
0
|
0
|
|
|
|
0
|
$data = "" unless $data; |
|
124
|
0
|
|
|
|
|
0
|
$res = $self->send(Net::SPOCP::Request::Auth->new( |
|
125
|
|
|
|
|
|
|
data => $data))->recv(); |
|
126
|
|
|
|
|
|
|
} |
|
127
|
0
|
0
|
|
|
|
0
|
if($res->code == 200) |
|
128
|
|
|
|
|
|
|
{ |
|
129
|
0
|
|
|
|
|
0
|
$self->{sasl} = $conn; |
|
130
|
|
|
|
|
|
|
} |
|
131
|
|
|
|
|
|
|
else |
|
132
|
|
|
|
|
|
|
{ |
|
133
|
0
|
|
|
|
|
0
|
croak("Net::SPOCP: Sasl auth failed.") |
|
134
|
|
|
|
|
|
|
} |
|
135
|
0
|
|
|
|
|
0
|
$res; |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub logout |
|
139
|
|
|
|
|
|
|
{ |
|
140
|
1
|
|
|
1
|
0
|
3
|
my $self = shift; |
|
141
|
1
|
|
|
|
|
14
|
my $res = $self->send(Net::SPOCP::Request::Logout->new())->recv(); |
|
142
|
1
|
|
|
|
|
27
|
$self->{sasl} = undef; |
|
143
|
1
|
|
|
|
|
4
|
$self->{rest_buf} = undef; |
|
144
|
1
|
|
|
|
|
5
|
$res; |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
sub noop |
|
148
|
|
|
|
|
|
|
{ |
|
149
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
150
|
0
|
|
|
|
|
0
|
$self->send(Net::SPOCP::Request::Noop->new())->recv(); |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub send |
|
154
|
|
|
|
|
|
|
{ |
|
155
|
2
|
|
|
2
|
0
|
5
|
my $self = shift; |
|
156
|
2
|
|
|
|
|
5
|
my $msg = shift; |
|
157
|
2
|
|
|
|
|
5
|
my $tosend; |
|
158
|
|
|
|
|
|
|
|
|
159
|
2
|
50
|
33
|
|
|
21
|
carp "Net::SPOCP::send disconnected\n" unless |
|
160
|
|
|
|
|
|
|
$self->{_sock} && $self->{_sock}->connected; |
|
161
|
|
|
|
|
|
|
|
|
162
|
2
|
50
|
|
|
|
31
|
if($self->{sasl}) |
|
163
|
|
|
|
|
|
|
{ |
|
164
|
0
|
|
|
|
|
0
|
$tosend = $self->{sasl}->encode($msg->toString()); |
|
165
|
|
|
|
|
|
|
} |
|
166
|
|
|
|
|
|
|
else |
|
167
|
|
|
|
|
|
|
{ |
|
168
|
2
|
|
|
|
|
15
|
$tosend = $msg->toString(); |
|
169
|
|
|
|
|
|
|
} |
|
170
|
2
|
|
|
|
|
28
|
$self->{_sock}->print($tosend); |
|
171
|
2
|
|
|
|
|
270
|
$self; |
|
172
|
|
|
|
|
|
|
} |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub read |
|
176
|
|
|
|
|
|
|
{ |
|
177
|
2
|
|
|
2
|
0
|
5
|
my $self = shift; |
|
178
|
|
|
|
|
|
|
|
|
179
|
2
|
50
|
33
|
|
|
16
|
carp "Net::SPOCP::send disconnected\n" unless |
|
180
|
|
|
|
|
|
|
$self->{_sock} && $self->{_sock}->connected; |
|
181
|
|
|
|
|
|
|
|
|
182
|
2
|
|
|
|
|
25
|
my $buf = ''; |
|
183
|
|
|
|
|
|
|
|
|
184
|
2
|
50
|
|
|
|
8
|
if(!$self->{rest_buf}) |
|
185
|
|
|
|
|
|
|
{ |
|
186
|
2
|
|
|
|
|
3
|
my $nread = 0; |
|
187
|
2
|
|
|
|
|
6
|
my $tbuf = ''; |
|
188
|
2
|
|
|
|
|
4
|
my $maxread = 1024; |
|
189
|
2
|
|
|
|
|
256970
|
while($nread = sysread($self->{_sock}, $tbuf, $maxread)) |
|
190
|
|
|
|
|
|
|
{ |
|
191
|
2
|
50
|
|
|
|
15
|
last if $nread == 0; # EOF |
|
192
|
2
|
|
|
|
|
15
|
$buf .= $tbuf; |
|
193
|
2
|
50
|
|
|
|
15
|
last if ($maxread - $nread) != 0; |
|
194
|
|
|
|
|
|
|
} |
|
195
|
2
|
50
|
|
|
|
19
|
croak "Net::SPOCP::recv read error: $!\n" unless defined $nread; |
|
196
|
|
|
|
|
|
|
|
|
197
|
2
|
50
|
|
|
|
21
|
if($self->{sasl}) |
|
198
|
|
|
|
|
|
|
{ |
|
199
|
0
|
|
|
|
|
0
|
$buf = $self->{sasl}->decode($buf); |
|
200
|
|
|
|
|
|
|
} |
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
else |
|
203
|
|
|
|
|
|
|
{ |
|
204
|
0
|
|
|
|
|
0
|
$buf = $self->{rest_buf}; |
|
205
|
|
|
|
|
|
|
} |
|
206
|
|
|
|
|
|
|
|
|
207
|
2
|
|
|
|
|
40
|
$buf =~ m/^(\d+):/; |
|
208
|
2
|
50
|
|
|
|
19
|
my $len = $1 if $1; |
|
209
|
2
|
50
|
|
|
|
9
|
carp("couldn't get len in buf at Net::SPOCP::recv read") unless $len; |
|
210
|
2
|
|
|
|
|
134
|
$buf =~ m/^(\d+):(.{$len})(.*)$/; |
|
211
|
2
|
50
|
|
|
|
16
|
$buf = $2 if $2; |
|
212
|
2
|
50
|
|
|
|
6
|
carp("couldn't get buf in of $len at Net::SPOCP::recv read") unless $buf; |
|
213
|
|
|
|
|
|
|
# there is a second message after the first one. we store this in |
|
214
|
|
|
|
|
|
|
# $self->{rest_buf} and take it out on the next read. |
|
215
|
2
|
|
|
|
|
9
|
$self->{rest_buf} = $3; |
|
216
|
2
|
|
|
|
|
26
|
$buf; |
|
217
|
|
|
|
|
|
|
} |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
sub recv |
|
220
|
|
|
|
|
|
|
{ |
|
221
|
2
|
|
|
2
|
0
|
6
|
my $self = shift; |
|
222
|
|
|
|
|
|
|
|
|
223
|
2
|
|
|
|
|
60
|
my $res = Net::SPOCP::Response->new(); |
|
224
|
2
|
|
|
|
|
4
|
my $r; |
|
225
|
|
|
|
|
|
|
do |
|
226
|
2
|
|
33
|
|
|
3
|
{ |
|
227
|
2
|
|
|
|
|
11
|
$r = Net::SPOCP::Reply->parse($self->read()); |
|
228
|
2
|
|
|
|
|
12
|
$res->add_reply($r); |
|
229
|
|
|
|
|
|
|
} while ($r->code == 201 || $r->code == 301); |
|
230
|
|
|
|
|
|
|
|
|
231
|
2
|
|
|
|
|
11
|
$res; |
|
232
|
|
|
|
|
|
|
} |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
package Net::SPOCP::Client; |
|
235
|
|
|
|
|
|
|
@Net::SPOCP::Client::ISA = qw(Net::SPOCP::Protocol); |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
package Net::SPOCP::Request; |
|
238
|
|
|
|
|
|
|
@Net::SPOCP::Request::ISA = qw(Net::SPOCP); |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
sub toString |
|
241
|
|
|
|
|
|
|
{ |
|
242
|
2
|
|
|
2
|
|
10
|
$_[0]->l_encode($_[0]->l_encode($_[0]->type).$_[0]->encode()); |
|
243
|
|
|
|
|
|
|
} |
|
244
|
|
|
|
|
|
|
|
|
245
|
2
|
|
|
2
|
|
6
|
sub init { } |
|
246
|
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
sub type { |
|
248
|
0
|
|
|
0
|
|
0
|
die "Implementation error calling type: ".join(',',caller())."\n"; |
|
249
|
|
|
|
|
|
|
} |
|
250
|
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
sub encode |
|
252
|
|
|
|
|
|
|
{ |
|
253
|
0
|
|
|
0
|
|
0
|
die $_[0]->type . " not implemented yet" |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
package Net::SPOCP::Request::Query; |
|
257
|
|
|
|
|
|
|
@Net::SPOCP::Request::Query::ISA = qw(Net::SPOCP::Request); |
|
258
|
|
|
|
|
|
|
|
|
259
|
1
|
|
|
1
|
|
9
|
sub type { 'QUERY' } |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
sub encode |
|
262
|
|
|
|
|
|
|
{ |
|
263
|
1
|
|
|
1
|
|
22
|
$_[0]->l_encode($_[0]->{path}).$_[0]->l_encode($_[0]->{rule}->toString()).$_[0]->l_encode($_[0]->{data}); |
|
264
|
|
|
|
|
|
|
} |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
package Net::SPOCP::Request::List; |
|
267
|
|
|
|
|
|
|
@Net::SPOCP::Request::List::ISA = qw(Net::SPOCP::Request); |
|
268
|
|
|
|
|
|
|
|
|
269
|
0
|
|
|
0
|
|
0
|
sub type { 'LIST' } |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
package Net::SPOCP::Request::BSearch; |
|
272
|
|
|
|
|
|
|
@Net::SPOCP::Request::BSearch::ISA = qw(Net::SPOCP::Request); |
|
273
|
|
|
|
|
|
|
|
|
274
|
0
|
|
|
0
|
|
0
|
sub type { 'BSEARCH' } |
|
275
|
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
package Net::SPOCP::Request::Add; |
|
277
|
|
|
|
|
|
|
@Net::SPOCP::Request::Add::ISA = qw(Net::SPOCP::Request); |
|
278
|
|
|
|
|
|
|
|
|
279
|
0
|
|
|
0
|
|
0
|
sub type { 'ADD' } |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
package Net::SPOCP::Request::Capa; |
|
282
|
|
|
|
|
|
|
@Net::SPOCP::Request::Capa::ISA = qw(Net::SPOCP::Request); |
|
283
|
|
|
|
|
|
|
|
|
284
|
0
|
|
|
0
|
|
0
|
sub type { 'CAPA' } |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
sub encode |
|
287
|
|
|
|
|
|
|
{ |
|
288
|
0
|
|
|
0
|
|
0
|
return("") |
|
289
|
|
|
|
|
|
|
} |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
package Net::SPOCP::Request::Auth; |
|
292
|
|
|
|
|
|
|
@Net::SPOCP::Request::Auth::ISA = qw(Net::SPOCP::Request); |
|
293
|
|
|
|
|
|
|
|
|
294
|
0
|
|
|
0
|
|
0
|
sub type { 'AUTH' } |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
sub encode |
|
297
|
|
|
|
|
|
|
{ |
|
298
|
0
|
|
|
0
|
|
0
|
my $mech = ""; |
|
299
|
0
|
0
|
|
|
|
0
|
$mech = $_[0]->l_encode($_[0]->{mech}) if $_[0]->{mech}; |
|
300
|
0
|
|
|
|
|
0
|
$mech.$_[0]->l_encode($_[0]->{data}); |
|
301
|
|
|
|
|
|
|
} |
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
package Net::SPOCP::Request::Logout; |
|
304
|
|
|
|
|
|
|
@Net::SPOCP::Request::Logout::ISA = qw(Net::SPOCP::Request); |
|
305
|
|
|
|
|
|
|
|
|
306
|
1
|
|
|
1
|
|
11
|
sub type { 'LOGOUT' } |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
sub encode |
|
309
|
|
|
|
|
|
|
{ |
|
310
|
1
|
|
|
1
|
|
15
|
return(""); |
|
311
|
|
|
|
|
|
|
} |
|
312
|
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
package Net::SPOCP::Request::Noop; |
|
314
|
|
|
|
|
|
|
@Net::SPOCP::Request::Noop::ISA = qw(Net::SPOCP::Request); |
|
315
|
|
|
|
|
|
|
|
|
316
|
0
|
|
|
0
|
|
0
|
sub type { 'NOOP' } |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
sub encode |
|
319
|
|
|
|
|
|
|
{ |
|
320
|
0
|
|
|
0
|
|
0
|
return(""); |
|
321
|
|
|
|
|
|
|
} |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
package Net::SPOCP::Request::Starttls; |
|
324
|
|
|
|
|
|
|
@Net::SPOCP::Request::Starttls::ISA = qw(Net::SPOCP::Request); |
|
325
|
|
|
|
|
|
|
|
|
326
|
0
|
|
|
0
|
|
0
|
sub type { 'STARTTLS' } |
|
327
|
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
sub encode |
|
329
|
|
|
|
|
|
|
{ |
|
330
|
0
|
|
|
0
|
|
0
|
return(""); |
|
331
|
|
|
|
|
|
|
} |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
package Net::SPOCP::Response; |
|
334
|
|
|
|
|
|
|
@Net::SPOCP::Response::ISA = qw(Net::SPOCP); |
|
335
|
|
|
|
|
|
|
|
|
336
|
1
|
|
|
1
|
|
8
|
use Carp; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
216
|
|
|
337
|
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
sub new |
|
339
|
|
|
|
|
|
|
{ |
|
340
|
2
|
|
|
2
|
|
5
|
my $class = shift; |
|
341
|
|
|
|
|
|
|
|
|
342
|
2
|
|
|
|
|
10
|
bless \@_,$class; |
|
343
|
|
|
|
|
|
|
} |
|
344
|
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
sub add_reply |
|
346
|
|
|
|
|
|
|
{ |
|
347
|
2
|
|
|
2
|
|
3
|
push(@{$_[0]},$_[1]); |
|
|
2
|
|
|
|
|
27
|
|
|
348
|
|
|
|
|
|
|
} |
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
sub replies |
|
351
|
|
|
|
|
|
|
{ |
|
352
|
0
|
|
|
0
|
|
0
|
@{$_[0]}; |
|
|
0
|
|
|
|
|
0
|
|
|
353
|
|
|
|
|
|
|
} |
|
354
|
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
sub reply |
|
356
|
|
|
|
|
|
|
{ |
|
357
|
2
|
|
|
2
|
|
11
|
$_[0]->[$_[1]]; |
|
358
|
|
|
|
|
|
|
} |
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
sub is_error |
|
361
|
|
|
|
|
|
|
{ |
|
362
|
0
|
|
|
0
|
|
0
|
my $code = $_[0]->reply(0)->code; |
|
363
|
|
|
|
|
|
|
# multi-part, ok, authdata, auth ok |
|
364
|
0
|
0
|
0
|
|
|
0
|
$code != 201 && $code != 200 && $code != 301 && $code != 300 |
|
|
|
|
0
|
|
|
|
|
|
365
|
|
|
|
|
|
|
} |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
sub error |
|
368
|
|
|
|
|
|
|
{ |
|
369
|
1
|
|
|
1
|
|
180
|
$_[0]->reply(0)->error; |
|
370
|
|
|
|
|
|
|
} |
|
371
|
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
sub code |
|
373
|
|
|
|
|
|
|
{ |
|
374
|
1
|
|
|
1
|
|
9
|
$_[0]->reply(0)->code; |
|
375
|
|
|
|
|
|
|
} |
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
package Net::SPOCP::Reply; |
|
378
|
|
|
|
|
|
|
@Net::SPOCP::Reply::ISA = qw(Net::SPOCP); |
|
379
|
|
|
|
|
|
|
|
|
380
|
2
|
|
|
2
|
|
5
|
sub init {} |
|
381
|
|
|
|
|
|
|
|
|
382
|
1
|
|
|
1
|
|
4
|
use Carp; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
300
|
|
|
383
|
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
my %CODE = ( |
|
385
|
|
|
|
|
|
|
200 => 'Ok', |
|
386
|
|
|
|
|
|
|
201 => 'Multiline', |
|
387
|
|
|
|
|
|
|
202 => 'Denied', |
|
388
|
|
|
|
|
|
|
203 => 'Bye', |
|
389
|
|
|
|
|
|
|
204 => 'Transaction complete', |
|
390
|
|
|
|
|
|
|
205 => 'Ready to start TLS', |
|
391
|
|
|
|
|
|
|
300 => 'Authentication in progress', |
|
392
|
|
|
|
|
|
|
301 => 'Authentication Data', |
|
393
|
|
|
|
|
|
|
401 => 'Service not available', |
|
394
|
|
|
|
|
|
|
402 => 'Information unavailable', |
|
395
|
|
|
|
|
|
|
500 => 'Syntax error', |
|
396
|
|
|
|
|
|
|
501 => 'Operations error', |
|
397
|
|
|
|
|
|
|
502 => 'Not supported', |
|
398
|
|
|
|
|
|
|
503 => 'Already in operation', |
|
399
|
|
|
|
|
|
|
504 => 'Line too long', |
|
400
|
|
|
|
|
|
|
505 => 'Unknown ID', |
|
401
|
|
|
|
|
|
|
506 => 'Already exists', |
|
402
|
|
|
|
|
|
|
507 => 'Line too long', |
|
403
|
|
|
|
|
|
|
508 => 'Unknown command', |
|
404
|
|
|
|
|
|
|
509 => 'Access denied', |
|
405
|
|
|
|
|
|
|
510 => 'Argument error', |
|
406
|
|
|
|
|
|
|
511 => 'Already active', |
|
407
|
|
|
|
|
|
|
512 => 'Internal error', |
|
408
|
|
|
|
|
|
|
513 => 'Input error', |
|
409
|
|
|
|
|
|
|
514 => 'Timelimit exceeded', |
|
410
|
|
|
|
|
|
|
515 => 'Sizelimit exceeded', |
|
411
|
|
|
|
|
|
|
516 => 'Other' |
|
412
|
|
|
|
|
|
|
); |
|
413
|
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
sub parse |
|
415
|
|
|
|
|
|
|
{ |
|
416
|
2
|
|
|
2
|
|
6
|
my $self = shift; |
|
417
|
2
|
|
|
|
|
4
|
my $str = shift; |
|
418
|
|
|
|
|
|
|
|
|
419
|
2
|
|
|
|
|
27
|
my $me = Net::SPOCP::Reply->new(); |
|
420
|
|
|
|
|
|
|
|
|
421
|
2
|
50
|
|
|
|
35
|
carp "Net::SPOCP::Reply::parse format error: missing error code\n" unless |
|
422
|
|
|
|
|
|
|
$str =~ s/^3:([0-9]{3})//o; |
|
423
|
|
|
|
|
|
|
|
|
424
|
2
|
|
|
|
|
22
|
$me->{code} = $1; |
|
425
|
|
|
|
|
|
|
|
|
426
|
2
|
50
|
|
|
|
17
|
carp "Net::SPOCP::Reply::parse format error: format error\n" unless |
|
427
|
|
|
|
|
|
|
$str =~ s/^([0-9]+):(.*)//o; |
|
428
|
|
|
|
|
|
|
|
|
429
|
2
|
|
|
|
|
7
|
$me->{length} = $1; |
|
430
|
2
|
|
|
|
|
8
|
$me->{data} = $2; |
|
431
|
|
|
|
|
|
|
|
|
432
|
2
|
|
|
|
|
5
|
$me; |
|
433
|
|
|
|
|
|
|
} |
|
434
|
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
sub code |
|
436
|
|
|
|
|
|
|
{ |
|
437
|
5
|
|
|
5
|
|
96
|
$_[0]->{code}; |
|
438
|
|
|
|
|
|
|
} |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
sub length |
|
441
|
|
|
|
|
|
|
{ |
|
442
|
0
|
|
|
0
|
|
0
|
$_[0]->{length}; |
|
443
|
|
|
|
|
|
|
} |
|
444
|
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
sub data |
|
446
|
|
|
|
|
|
|
{ |
|
447
|
0
|
|
|
0
|
|
0
|
$_[0]->{data}; |
|
448
|
|
|
|
|
|
|
} |
|
449
|
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
sub error |
|
451
|
|
|
|
|
|
|
{ |
|
452
|
1
|
|
|
1
|
|
4
|
my $code = $_[0]->{code}; |
|
453
|
|
|
|
|
|
|
|
|
454
|
1
|
50
|
|
|
|
7
|
return "Unknown error" unless exists $CODE{$code}; |
|
455
|
1
|
|
|
|
|
124
|
$CODE{$code}; |
|
456
|
|
|
|
|
|
|
} |
|
457
|
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
package Net::SPOCP; |
|
459
|
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
1; |