blib/lib/SpamcupNG.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 30 | 212 | 14.1 |
branch | 0 | 102 | 0.0 |
condition | 0 | 20 | 0.0 |
subroutine | 10 | 13 | 76.9 |
pod | 3 | 3 | 100.0 |
total | 43 | 350 | 12.2 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package SpamcupNG; | ||||||
2 | 2 | 2 | 15026 | use warnings; | |||
2 | 5 | ||||||
2 | 68 | ||||||
3 | 2 | 2 | 10 | use strict; | |||
2 | 4 | ||||||
2 | 56 | ||||||
4 | 2 | 2 | 1088 | use LWP::UserAgent 6.05; | |||
2 | 70961 | ||||||
2 | 69 | ||||||
5 | 2 | 2 | 1131 | use HTML::Form 6.03; | |||
2 | 25441 | ||||||
2 | 71 | ||||||
6 | 2 | 2 | 923 | use HTTP::Cookies 6.01; | |||
2 | 10151 | ||||||
2 | 55 | ||||||
7 | 2 | 2 | 2820 | use Getopt::Std; | |||
2 | 71 | ||||||
2 | 116 | ||||||
8 | 2 | 2 | 657 | use YAML::XS 0.62 qw(LoadFile); | |||
2 | 4181 | ||||||
2 | 100 | ||||||
9 | 2 | 2 | 13 | use File::Spec; | |||
2 | 4 | ||||||
2 | 48 | ||||||
10 | 2 | 2 | 946 | use Hash::Util qw(lock_hash); | |||
2 | 4029 | ||||||
2 | 19 | ||||||
11 | 2 | 2 | 154 | use Exporter 'import'; | |||
2 | 4 | ||||||
2 | 3177 | ||||||
12 | |||||||
13 | our @EXPORT_OK = qw(read_config main_loop get_browser %MAP); | ||||||
14 | |||||||
15 | our %MAP = ( | ||||||
16 | 'nothing' => 'n', | ||||||
17 | 'all' => 'a', | ||||||
18 | 'stupid' => 's', | ||||||
19 | 'quiet' => 'q', | ||||||
20 | 'alt_code' => 'c', | ||||||
21 | 'alt_user' => 'l', | ||||||
22 | 'info_level' => 'd', | ||||||
23 | 'debug_level' => 'D' | ||||||
24 | ); | ||||||
25 | |||||||
26 | lock_hash(%MAP); | ||||||
27 | |||||||
28 | our $VERSION = '0.4'; # VERSION | ||||||
29 | |||||||
30 | =head1 NAME | ||||||
31 | |||||||
32 | SpamcupNG - module to export functions for spamcup program | ||||||
33 | |||||||
34 | =head1 SYNOPSIS | ||||||
35 | |||||||
36 | use SpamcupNG qw(read_config get_browser); | ||||||
37 | |||||||
38 | =head1 DESCRIPTION | ||||||
39 | |||||||
40 | Spamcup NG is a Perl web crawler for finishing Spamcop.net reports automatically. This module implements the functions used by the spamcup program. | ||||||
41 | |||||||
42 | See the README.md file on this project for more details. | ||||||
43 | |||||||
44 | See the INSTALL for setup instructions. | ||||||
45 | |||||||
46 | =head1 EXPORTS | ||||||
47 | |||||||
48 | =head2 read_config | ||||||
49 | |||||||
50 | Reads a YAML file, sets the command line options and return the associated accounts. | ||||||
51 | |||||||
52 | Expects as parameter a string with the full path to the YAML file and a hash reference of the | ||||||
53 | command line options read (as returned by L |
||||||
54 | |||||||
55 | The hash reference options will set as defined in the YAML file. | ||||||
56 | Options defined in the YAML have preference of those read on the command line then. | ||||||
57 | |||||||
58 | It will also return all data configured in the C |
||||||
59 | the configuration file. | ||||||
60 | |||||||
61 | =cut | ||||||
62 | |||||||
63 | sub read_config { | ||||||
64 | 0 | 0 | 1 | my ( $cfg, $cmd_opts ) = @_; | |||
65 | 0 | my $data = LoadFile($cfg); | |||||
66 | |||||||
67 | 0 | for my $opt ( keys(%MAP) ) { | |||||
68 | |||||||
69 | 0 | 0 | 0 | if ( exists( $data->{ExecutionOptions}->{$opt} ) | |||
70 | and ( $data->{ExecutionOptions}->{$opt} eq 'y' ) ) | ||||||
71 | { | ||||||
72 | 0 | $cmd_opts->{$opt} = 1; | |||||
73 | } | ||||||
74 | else { | ||||||
75 | 0 | $cmd_opts->{$opt} = 0; | |||||
76 | } | ||||||
77 | |||||||
78 | } | ||||||
79 | |||||||
80 | 0 | return $data->{Accounts}; | |||||
81 | } | ||||||
82 | |||||||
83 | =pod | ||||||
84 | |||||||
85 | =head2 get_browser | ||||||
86 | |||||||
87 | Creates a instance of L |
||||||
88 | |||||||
89 | Expects two string as parameters: one with the name to associated with the user | ||||||
90 | agent and the another as version of it. | ||||||
91 | |||||||
92 | =cut | ||||||
93 | |||||||
94 | # :TODO:23/04/2017 17:21:28:ARFREITAS: Add options to configure nice things | ||||||
95 | # like HTTP proxy | ||||||
96 | |||||||
97 | sub get_browser { | ||||||
98 | 0 | 0 | 1 | my ( $name, $version ) = @_; | |||
99 | 0 | my $ua = LWP::UserAgent->new(); | |||||
100 | 0 | $ua->agent("$name/$version"); | |||||
101 | 0 | $ua->cookie_jar( HTTP::Cookies->new() ); | |||||
102 | 0 | return $ua; | |||||
103 | } | ||||||
104 | |||||||
105 | =pod | ||||||
106 | |||||||
107 | =head2 main_loop | ||||||
108 | |||||||
109 | Processes all the pending spam reports in a loop until finished. | ||||||
110 | |||||||
111 | Expects as parameter (in this sequence): | ||||||
112 | |||||||
113 | =over | ||||||
114 | |||||||
115 | =item * | ||||||
116 | |||||||
117 | a L |
||||||
118 | |||||||
119 | =item * | ||||||
120 | |||||||
121 | A hash reference with the following key/values: | ||||||
122 | |||||||
123 | =over | ||||||
124 | |||||||
125 | =item * | ||||||
126 | |||||||
127 | ident => The identity to Spamcop | ||||||
128 | |||||||
129 | =item * | ||||||
130 | |||||||
131 | pass => The password to Spamcop | ||||||
132 | |||||||
133 | =item * | ||||||
134 | |||||||
135 | debug => true (1) or false (0) to enable/disable debug information | ||||||
136 | |||||||
137 | =item * | ||||||
138 | |||||||
139 | delay => time in seconds to wait for next iteration with Spamcop website | ||||||
140 | |||||||
141 | =item * | ||||||
142 | |||||||
143 | quiet => true (1) or false (0) to enable/disable messages | ||||||
144 | |||||||
145 | As confusing as it seems, current implementation may accept debug messages | ||||||
146 | B |
||||||
147 | |||||||
148 | =item * | ||||||
149 | |||||||
150 | check_only => true (1) or false (0) to only check for unreported SPAM, but not reporting them | ||||||
151 | |||||||
152 | =back | ||||||
153 | |||||||
154 | =back | ||||||
155 | |||||||
156 | Returns true if everything went right, or C |
||||||
157 | |||||||
158 | =cut | ||||||
159 | |||||||
160 | # :TODO:23/04/2017 16:04:17:ARFREITAS: probably this sub is too large | ||||||
161 | # It should be refactored to at least separate the parsing from HTML content recover | ||||||
162 | sub main_loop { | ||||||
163 | 0 | 0 | 1 | my ( $ua, $opts_ref ) = @_; | |||
164 | |||||||
165 | # last seen SPAM id | ||||||
166 | 0 | my $last_seen; | |||||
167 | |||||||
168 | # Get first page that contains link to next one... | ||||||
169 | |||||||
170 | # :TODO:23/04/2017 17:06:59:ARFREITAS: replace all this debugging checks with Log::Log4perl | ||||||
171 | 0 | 0 | if ( $opts_ref->{debug} ) { | ||||
172 | 0 | 0 | if ( $opts_ref->{pass} ) { | ||||
173 | print 'D: GET http://', $opts_ref->{ident}, | ||||||
174 | 0 | ':******@members.spamcop.net/', "\n"; | |||||
175 | } | ||||||
176 | else { | ||||||
177 | print 'D: GET http://www.spamcop.net/?code=', $opts_ref->{ident}, | ||||||
178 | 0 | "\n"; | |||||
179 | } | ||||||
180 | } | ||||||
181 | |||||||
182 | 0 | 0 | if ( $opts_ref->{debug} ) { | ||||
183 | 0 | print 'D: sleeping for ', $opts_ref->{delay}, " seconds.\n"; | |||||
184 | } | ||||||
185 | |||||||
186 | 0 | sleep $opts_ref->{delay}; | |||||
187 | |||||||
188 | 0 | my $req; | |||||
189 | |||||||
190 | 0 | 0 | if ( $opts_ref->{pass} ) { | ||||
191 | 0 | $req = HTTP::Request->new( GET => 'http://members.spamcop.net/' ); | |||||
192 | 0 | $req->authorization_basic( $opts_ref->{ident}, $opts_ref->{pass} ); | |||||
193 | } | ||||||
194 | else { | ||||||
195 | $req = | ||||||
196 | HTTP::Request->new( | ||||||
197 | 0 | GET => 'http://www.spamcop.net/?code=' . $opts_ref->{ident} ); | |||||
198 | } | ||||||
199 | |||||||
200 | 0 | my $res = $ua->request($req); | |||||
201 | |||||||
202 | # verify response | ||||||
203 | 0 | 0 | if ( $res->is_success ) { | ||||
204 | 0 | 0 | if ( $opts_ref->{debug} ) { | ||||
205 | 0 | print "D: Got HTTP response\n"; | |||||
206 | } | ||||||
207 | } | ||||||
208 | else { | ||||||
209 | 0 | my $response = $res->status_line(); | |||||
210 | 0 | 0 | if ( $response =~ /500/ ) { | ||||
211 | 0 | die "E: Can\'t connect to server: " . $response; | |||||
212 | } | ||||||
213 | else { | ||||||
214 | 0 | warn $response; | |||||
215 | 0 | die | |||||
216 | "E: Can\'t connect to server or invalid credentials. Please verify your username and password and try again.\n"; | ||||||
217 | } | ||||||
218 | } | ||||||
219 | |||||||
220 | 0 | 0 | if ( $opts_ref->{debug} ) { | ||||
221 | 0 | ||||||
222 | "\n--------------------------------------------------------------------------\n"; | ||||||
223 | 0 | print $res->content; | |||||
224 | 0 | ||||||
225 | "--------------------------------------------------------------------------\n\n"; | ||||||
226 | } | ||||||
227 | |||||||
228 | # Parse id for link | ||||||
229 | 0 | 0 | if ( $res->content =~ /\>No userid found\ | ||||
230 | 0 | die | |||||
231 | "E: No userid found. Please check that you have entered correct code. Also consider obtaining a password to Spamcop.net instead of using the old-style authorization token.\n"; | ||||||
232 | } | ||||||
233 | |||||||
234 | 0 | my $fullname; | |||||
235 | |||||||
236 | 0 | 0 | if ( $res->content =~ /(Welcome, .*?)\./ ) { | ||||
237 | |||||||
238 | # found full name, print out the greeting string | ||||||
239 | 0 | print "* $1\n"; | |||||
240 | } | ||||||
241 | |||||||
242 | 0 | my $nextid; | |||||
243 | |||||||
244 | 0 | 0 | if ( $res->content =~ /sc\?id\=(.*?)\"\>/gi ) { # this is easy to parse | ||||
245 | # userid ok, new spam available | ||||||
246 | 0 | $nextid = $1; | |||||
247 | } | ||||||
248 | else { | ||||||
249 | # userid ok, no new spam | ||||||
250 | 0 | 0 | unless ( $opts_ref->{quiet} ) { | ||||
251 | 0 | print "* No unreported spam found. Quitting.\n"; | |||||
252 | } | ||||||
253 | 0 | return -1; # quit | |||||
254 | } | ||||||
255 | |||||||
256 | 0 | 0 | if ( $opts_ref->{quiet} ) { | ||||
257 | 0 | print "* ID of the next spam is '$nextid'.\n"; | |||||
258 | } | ||||||
259 | |||||||
260 | # avoid loops | ||||||
261 | 0 | 0 | 0 | if ( ($last_seen) and ( $nextid eq $last_seen ) ) { | |||
262 | 0 | die | |||||
263 | "E: I have seen this ID earlier. We don't want to report it again. This usually happens because of a bug in Spamcup. Make sure you use latest version! You may also want to go check from Spamcop what's happening: http://www.spamcop.net/sc?id=$nextid\n"; | ||||||
264 | } | ||||||
265 | |||||||
266 | 0 | $last_seen = $nextid; # store for comparison | |||||
267 | |||||||
268 | 0 | $req = undef; | |||||
269 | 0 | $res = undef; | |||||
270 | |||||||
271 | # Fetch the spam report form | ||||||
272 | |||||||
273 | 0 | 0 | if ( $opts_ref->{debug} ) { | ||||
274 | 0 | print "D: GET http://www.spamcop.net/sc?id=$nextid\n"; | |||||
275 | 0 | print 'D: Sleeping for ', $opts_ref->{delay}, " seconds.\n"; | |||||
276 | } | ||||||
277 | |||||||
278 | 0 | sleep $opts_ref->{delay}; | |||||
279 | |||||||
280 | 0 | $req = | |||||
281 | HTTP::Request->new( GET => 'http://www.spamcop.net/sc?id=' . $nextid ); | ||||||
282 | 0 | $res = $ua->request($req); | |||||
283 | |||||||
284 | 0 | 0 | if ( $res->is_success ) { | ||||
285 | 0 | 0 | if ( $opts_ref->{debug} ) { | ||||
286 | 0 | print "D: Got HTTP response\n"; | |||||
287 | |||||||
288 | # print "D: Headers follow:\n". $res->headers->as_string ."\n\n"; | ||||||
289 | } | ||||||
290 | |||||||
291 | } | ||||||
292 | else { | ||||||
293 | 0 | die "E: Can't connect to server. Try again later.\n\n"; | |||||
294 | } | ||||||
295 | |||||||
296 | 0 | 0 | if ( $opts_ref->{debug} ) { | ||||
297 | 0 | ||||||
298 | "\n--------------------------------------------------------------------------\n"; | ||||||
299 | 0 | print $res->content; | |||||
300 | 0 | ||||||
301 | "--------------------------------------------------------------------------\n\n"; | ||||||
302 | } | ||||||
303 | |||||||
304 | # parse the spam | ||||||
305 | |||||||
306 | 0 | my $_cancel = 0; | |||||
307 | |||||||
308 | 0 | my $base_uri = $res->base(); | |||||
309 | 0 | 0 | if ( !$base_uri ) { | ||||
310 | 0 | print "E: No base uri found. Internal error? Please report this.\n"; | |||||
311 | 0 | exit; | |||||
312 | } | ||||||
313 | |||||||
314 | $res->content =~ | ||||||
315 | 0 | /(\ | |||||
316 | 0 | my $formdata = "$1"; | |||||
317 | 0 | my $form = HTML::Form->parse( $formdata, $base_uri ); | |||||
318 | |||||||
319 | # print the header of the spam | ||||||
320 | |||||||
321 | 0 | my $spamhead; | |||||
322 | 0 | 0 | if ( $res->content =~ | ||||
0 | |||||||
0 | |||||||
0 | |||||||
0 | |||||||
323 | /Please make sure this email IS spam.*?size=2\>\n(.*?)\ | ||||||
324 | ) | ||||||
325 | { # this is also quite easy... | ||||||
326 | # this is the normal case | ||||||
327 | |||||||
328 | 0 | $spamhead = $1; | |||||
329 | 0 | 0 | unless ( $opts_ref->{quiet} ) { | ||||
330 | 0 | print "* Head of the spam follows >>>\n"; | |||||
331 | 0 | $spamhead =~ s/\n/\t/igs; # prepend a tab to each line | |||||
332 | 0 | $spamhead =~ s/ /\n/gsi; # simplify a bit |
|||||
333 | 0 | print "\t$spamhead\n"; | |||||
334 | 0 | print "<<<\n"; | |||||
335 | } | ||||||
336 | |||||||
337 | # parse form fields | ||||||
338 | # verify form | ||||||
339 | 0 | 0 | unless ($form) { | ||||
340 | 0 | 0 | if ( $opts_ref->{debug} ) { | ||||
341 | 0 | ||||||
342 | "D: Spamcop returned invalid HTML form. Usually temporary error.\n"; | ||||||
343 | } | ||||||
344 | 0 | die "E: Temporary Spamcop.net error. Try again later! Quitting.\n"; | |||||
345 | } | ||||||
346 | else { | ||||||
347 | 0 | 0 | if ( $opts_ref->{debug} ) { | ||||
348 | 0 | print "D: Form data follows:\n" . $form->dump . "\n\n"; | |||||
349 | } | ||||||
350 | |||||||
351 | # how many recepients for reports | ||||||
352 | 0 | my $max = $form->value("max"); | |||||
353 | |||||||
354 | 0 | my $willsend; | |||||
355 | my $wontsend; | ||||||
356 | |||||||
357 | # iterate targets | ||||||
358 | 0 | for ( my $i = 1 ; $i <= $max ; $i++ ) { | |||||
359 | 0 | my $send = $form->value("send$i"); | |||||
360 | 0 | my $type = $form->value("type$i"); | |||||
361 | 0 | my $master = $form->value("master$i"); | |||||
362 | 0 | my $info = $form->value("info$i"); | |||||
363 | |||||||
364 | # convert %2E -style stuff back to text, if any | ||||||
365 | 0 | 0 | if ( $info =~ /%([A-Fa-f\d]{2})/g ) { | ||||
366 | 0 | $info =~ s/%([A-Fa-f\d]{2})/chr hex $1/eg; | |||||
0 | |||||||
367 | } | ||||||
368 | |||||||
369 | 0 | 0 | 0 | if ( | |||
0 | |||||||
370 | $send | ||||||
371 | and ( ( $send eq 'on' ) | ||||||
372 | or ( $type =~ /^mole/ and $send == 1 ) ) | ||||||
373 | ) | ||||||
374 | { | ||||||
375 | 0 | $willsend .= "\t$master \t($info)\n"; | |||||
376 | } | ||||||
377 | else { | ||||||
378 | 0 | $wontsend .= "\t$master \t($info)\n"; | |||||
379 | } | ||||||
380 | } | ||||||
381 | |||||||
382 | 0 | ||||||
383 | "Would send the report to the following addresses: (Reason in parenthesis)\n"; | ||||||
384 | 0 | 0 | if ($willsend) { | ||||
385 | 0 | print $willsend; | |||||
386 | } | ||||||
387 | else { | ||||||
388 | 0 | print "\t--none--\n"; | |||||
389 | } | ||||||
390 | |||||||
391 | 0 | print "Following addresses would not be used:\n"; | |||||
392 | 0 | 0 | if ($wontsend) { | ||||
393 | 0 | print $wontsend; | |||||
394 | } | ||||||
395 | else { | ||||||
396 | 0 | print "\t--none--\n"; | |||||
397 | } | ||||||
398 | |||||||
399 | } | ||||||
400 | |||||||
401 | # Run without confirming each spam? Stupid. :) | ||||||
402 | 0 | 0 | unless ( $opts_ref->{stupid} ) { | ||||
403 | 0 | print "* Are you sure this is spam? [y/N] "; | |||||
404 | |||||||
405 | 0 | my $reply = <>; # this should be done differently! | |||||
406 | 0 | 0 | 0 | if ( $reply && $reply !~ /^y/i ) { | |||
0 | |||||||
407 | 0 | print "* Cancelled.\n"; | |||||
408 | 0 | $_cancel = 1; # mark to be cancelled | |||||
409 | } | ||||||
410 | elsif ( !$reply ) { | ||||||
411 | 0 | print "* Accepted.\n"; | |||||
412 | } | ||||||
413 | else { | ||||||
414 | 0 | print "* Accepted.\n"; | |||||
415 | } | ||||||
416 | } | ||||||
417 | else { | ||||||
418 | # little delay for automatic processing | ||||||
419 | 0 | sleep $opts_ref->{delay}; | |||||
420 | } | ||||||
421 | 0 | print "...\n"; | |||||
422 | |||||||
423 | } | ||||||
424 | elsif ( $res->content =~ /Send Spam Report\(S\) Now/gi ) { | ||||||
425 | |||||||
426 | # this happens rarely, but I've seen this; spamcop does not show preview headers for some reason | ||||||
427 | 0 | 0 | unless ( $opts_ref->{stupid} ) { | ||||
428 | 0 | ||||||
429 | "* Preview headers not available, but you can still report this. Are you sure this is spam? [y/N] "; | ||||||
430 | |||||||
431 | 0 | my $reply = <>; | |||||
432 | 0 | 0 | 0 | if ( $reply && $reply !~ /^y/i ) { | |||
433 | |||||||
434 | # not Y | ||||||
435 | 0 | print "* Cancelled.\n"; | |||||
436 | 0 | $_cancel = 1; # mark to be cancelled | |||||
437 | } | ||||||
438 | else { | ||||||
439 | # Y | ||||||
440 | 0 | print "* Accepted.\n"; | |||||
441 | } | ||||||
442 | } | ||||||
443 | |||||||
444 | } | ||||||
445 | elsif ( $res->content =~ | ||||||
446 | /Sorry, this email is too old.*This mail was received on (.*?)\<\/.*\>/gsi | ||||||
447 | ) | ||||||
448 | { | ||||||
449 | # perhaps it's too old then | ||||||
450 | 0 | my $ondate = $1; | |||||
451 | 0 | 0 | unless ( $opts_ref->{quiet} ) { | ||||
452 | 0 | ||||||
453 | "W: This spam is too old. You must report spam within 3 days of receipt. This mail was received on $ondate. Deleted.\n"; | ||||||
454 | } | ||||||
455 | 0 | return 0; | |||||
456 | |||||||
457 | } | ||||||
458 | elsif ( $res->content =~ | ||||||
459 | /click reload if this page does not refresh automatically in \n(\d+) seconds/gs | ||||||
460 | ) | ||||||
461 | { | ||||||
462 | 0 | my $delay = $1; | |||||
463 | 0 | ||||||
464 | "W: Spamcop seems to be currently overloaded. Trying again in $delay seconds. Wait...\n"; | ||||||
465 | 0 | sleep $opts_ref->{delay}; | |||||
466 | |||||||
467 | # fool it to avoid duplicate detector | ||||||
468 | 0 | $last_seen = 0; | |||||
469 | |||||||
470 | # fake that everything is ok | ||||||
471 | 0 | return 1; | |||||
472 | } | ||||||
473 | elsif ( $res->content =~ | ||||||
474 | /No source IP address found, cannot proceed. Not full header/gs ) | ||||||
475 | { | ||||||
476 | 0 | ||||||
477 | "W: No source IP address found. Your report might be missing headers. Skipping.\n"; | ||||||
478 | 0 | return 0; | |||||
479 | } | ||||||
480 | |||||||
481 | else { | ||||||
482 | # Shit happens. If you know it should be parseable, please report a bug! | ||||||
483 | 0 | ||||||
484 | "W: Can't parse Spamcop.net's HTML. If this does not happen very often you can ignore this warning. Otherwise check if there's new version available. Skipping.\n"; | ||||||
485 | 0 | return 0; | |||||
486 | } | ||||||
487 | |||||||
488 | 0 | 0 | if ( $opts_ref->{check_only} ) { | ||||
489 | 0 | ||||||
490 | "* You gave option -n, so we'll stop here. The spam was NOT reported.\n"; | ||||||
491 | 0 | exit; | |||||
492 | } | ||||||
493 | |||||||
494 | 0 | 0 | if ( $opts_ref->{debug} ) { | ||||
495 | 0 | print "\n\nD: Starting the parse phase...\n"; | |||||
496 | } | ||||||
497 | |||||||
498 | 0 | undef $req; | |||||
499 | 0 | undef $res; | |||||
500 | |||||||
501 | # Submit the form to Spamcop OR cancel report | ||||||
502 | |||||||
503 | 0 | 0 | if ( !$_cancel ) { # SUBMIT spam | ||||
504 | |||||||
505 | 0 | 0 | if ( $opts_ref->{debug} ) { | ||||
506 | 0 | print "D: Submitting form. We will use the default recipients.\n"; | |||||
507 | 0 | print "D: GET http://www.spamcop.net/sc?id=$nextid\n"; | |||||
508 | 0 | print 'D: Sleeping for ', $opts_ref->{delay}, " seconds.\n"; | |||||
509 | } | ||||||
510 | 0 | sleep $opts_ref->{delay}; | |||||
511 | 0 | $res = LWP::UserAgent->new->request( $form->click() ) | |||||
512 | ; # click default button, submit | ||||||
513 | } | ||||||
514 | else { # CANCEL SPAM | ||||||
515 | 0 | 0 | if ( $opts_ref->{debug} ) { | ||||
516 | 0 | print "D: About to cancel report.\n"; | |||||
517 | } | ||||||
518 | 0 | $res = LWP::UserAgent->new->request( $form->click('cancel') ) | |||||
519 | ; # click cancel button | ||||||
520 | } | ||||||
521 | |||||||
522 | # Check the outcome of the response | ||||||
523 | 0 | 0 | if ( $res->is_success ) { | ||||
524 | 0 | 0 | if ( $opts_ref->{debug} ) { | ||||
525 | 0 | print "D: Got HTTP response\n"; | |||||
526 | 0 | print "D: -- content follows -------------------------\n"; | |||||
527 | 0 | print $res->content; | |||||
528 | 0 | print "D: -- content ended -------------------------\n\n"; | |||||
529 | } | ||||||
530 | |||||||
531 | } | ||||||
532 | else { | ||||||
533 | 0 | die "E: Can't connect to server. Try again later. Quitting.\n"; | |||||
534 | } | ||||||
535 | |||||||
536 | 0 | 0 | if ($_cancel) { | ||||
537 | 0 | return 1; # user decided this mail is not spam | |||||
538 | } | ||||||
539 | |||||||
540 | # parse respond | ||||||
541 | 0 | my $report; | |||||
542 | 0 | 0 | if ( $res->content =~ /(Spam report id .*?)\ /gsi ) { |
||||
0 | |||||||
543 | 0 | 0 | $report = $1 || "-none-\n"; | ||||
544 | 0 | $report =~ s/\ //gi; |
|||||
545 | } | ||||||
546 | elsif ( $res->content =~ /report for mole\@devnull.spamcop.net/ ) { | ||||||
547 | 0 | $report = 'Mole report(s)'; | |||||
548 | } | ||||||
549 | else { | ||||||
550 | 0 | ||||||
551 | "W: Spamcop.net returned unexpected content. If this does not happen very often you can ignore this. Otherwise check if there new version available. Continuing.\n"; | ||||||
552 | } | ||||||
553 | |||||||
554 | # print the report | ||||||
555 | |||||||
556 | 0 | 0 | unless ( $opts_ref->{quiet} ) { | ||||
557 | 0 | print "Spamcop.net sent following spam reports:\n"; | |||||
558 | 0 | 0 | print "$report\n" if $report; | ||||
559 | 0 | print "* Finished processing.\n"; | |||||
560 | } | ||||||
561 | |||||||
562 | 0 | return 1; | |||||
563 | |||||||
564 | # END OF THE LOOP | ||||||
565 | } | ||||||
566 | |||||||
567 | =head1 AUTHOR | ||||||
568 | |||||||
569 | Alceu Rodrigues de Freitas Junior, E |
||||||
570 | |||||||
571 | =head1 COPYRIGHT AND LICENSE | ||||||
572 | |||||||
573 | This software is copyright (c) 2015 of Alceu Rodrigues de Freitas Junior, E |
||||||
574 | |||||||
575 | This file is part of spamcupNG distribution. | ||||||
576 | |||||||
577 | spamcupNG is free software: you can redistribute it and/or modify | ||||||
578 | it under the terms of the GNU General Public License as published by | ||||||
579 | the Free Software Foundation, either version 3 of the License, or | ||||||
580 | (at your option) any later version. | ||||||
581 | |||||||
582 | spamcupNG is distributed in the hope that it will be useful, | ||||||
583 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
584 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
585 | GNU General Public License for more details. | ||||||
586 | |||||||
587 | You should have received a copy of the GNU General Public License | ||||||
588 | along with spamcupNG. If not, see |
||||||
589 | |||||||
590 | =cut | ||||||
591 | |||||||
592 | 1; |