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