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