1# Net::POP3.pm 2# 3# Copyright (c) 1995-2004 Graham Barr <gbarr@pobox.com>. All rights reserved. 4# This program is free software; you can redistribute it and/or 5# modify it under the same terms as Perl itself. 6 7package Net::POP3; 8 9use strict; 10use IO::Socket; 11use vars qw(@ISA $VERSION $debug); 12use Net::Cmd; 13use Carp; 14use Net::Config; 15 16$VERSION = "2.28"; 17 18@ISA = qw(Net::Cmd IO::Socket::INET); 19 20sub new 21{ 22 my $self = shift; 23 my $type = ref($self) || $self; 24 my ($host,%arg); 25 if (@_ % 2) { 26 $host = shift ; 27 %arg = @_; 28 } else { 29 %arg = @_; 30 $host=delete $arg{Host}; 31 } 32 my $hosts = defined $host ? [ $host ] : $NetConfig{pop3_hosts}; 33 my $obj; 34 my @localport = exists $arg{ResvPort} ? ( LocalPort => $arg{ResvPort} ): (); 35 36 my $h; 37 foreach $h (@{$hosts}) 38 { 39 $obj = $type->SUPER::new(PeerAddr => ($host = $h), 40 PeerPort => $arg{Port} || 'pop3(110)', 41 Proto => 'tcp', 42 @localport, 43 Timeout => defined $arg{Timeout} 44 ? $arg{Timeout} 45 : 120 46 ) and last; 47 } 48 49 return undef 50 unless defined $obj; 51 52 ${*$obj}{'net_pop3_host'} = $host; 53 54 $obj->autoflush(1); 55 $obj->debug(exists $arg{Debug} ? $arg{Debug} : undef); 56 57 unless ($obj->response() == CMD_OK) 58 { 59 $obj->close(); 60 return undef; 61 } 62 63 ${*$obj}{'net_pop3_banner'} = $obj->message; 64 65 $obj; 66} 67 68sub host { 69 my $me = shift; 70 ${*$me}{'net_pop3_host'}; 71} 72 73## 74## We don't want people sending me their passwords when they report problems 75## now do we :-) 76## 77 78sub debug_text { $_[2] =~ /^(pass|rpop)/i ? "$1 ....\n" : $_[2]; } 79 80sub login 81{ 82 @_ >= 1 && @_ <= 3 or croak 'usage: $pop3->login( USER, PASS )'; 83 my($me,$user,$pass) = @_; 84 85 if (@_ <= 2) { 86 ($user, $pass) = $me->_lookup_credentials($user); 87 } 88 89 $me->user($user) and 90 $me->pass($pass); 91} 92 93sub apop 94{ 95 @_ >= 1 && @_ <= 3 or croak 'usage: $pop3->apop( USER, PASS )'; 96 my($me,$user,$pass) = @_; 97 my $banner; 98 my $md; 99 100 if (eval { local $SIG{__DIE__}; require Digest::MD5 }) { 101 $md = Digest::MD5->new(); 102 } elsif (eval { local $SIG{__DIE__}; require MD5 }) { 103 $md = MD5->new(); 104 } else { 105 carp "You need to install Digest::MD5 or MD5 to use the APOP command"; 106 return undef; 107 } 108 109 return undef 110 unless ( $banner = (${*$me}{'net_pop3_banner'} =~ /(<.*>)/)[0] ); 111 112 if (@_ <= 2) { 113 ($user, $pass) = $me->_lookup_credentials($user); 114 } 115 116 $md->add($banner,$pass); 117 118 return undef 119 unless($me->_APOP($user,$md->hexdigest)); 120 121 $me->_get_mailbox_count(); 122} 123 124sub user 125{ 126 @_ == 2 or croak 'usage: $pop3->user( USER )'; 127 $_[0]->_USER($_[1]) ? 1 : undef; 128} 129 130sub pass 131{ 132 @_ == 2 or croak 'usage: $pop3->pass( PASS )'; 133 134 my($me,$pass) = @_; 135 136 return undef 137 unless($me->_PASS($pass)); 138 139 $me->_get_mailbox_count(); 140} 141 142sub reset 143{ 144 @_ == 1 or croak 'usage: $obj->reset()'; 145 146 my $me = shift; 147 148 return 0 149 unless($me->_RSET); 150 151 if(defined ${*$me}{'net_pop3_mail'}) 152 { 153 local $_; 154 foreach (@{${*$me}{'net_pop3_mail'}}) 155 { 156 delete $_->{'net_pop3_deleted'}; 157 } 158 } 159} 160 161sub last 162{ 163 @_ == 1 or croak 'usage: $obj->last()'; 164 165 return undef 166 unless $_[0]->_LAST && $_[0]->message =~ /(\d+)/; 167 168 return $1; 169} 170 171sub top 172{ 173 @_ == 2 || @_ == 3 or croak 'usage: $pop3->top( MSGNUM [, NUMLINES ])'; 174 my $me = shift; 175 176 return undef 177 unless $me->_TOP($_[0], $_[1] || 0); 178 179 $me->read_until_dot; 180} 181 182sub popstat 183{ 184 @_ == 1 or croak 'usage: $pop3->popstat()'; 185 my $me = shift; 186 187 return () 188 unless $me->_STAT && $me->message =~ /(\d+)\D+(\d+)/; 189 190 ($1 || 0, $2 || 0); 191} 192 193sub list 194{ 195 @_ == 1 || @_ == 2 or croak 'usage: $pop3->list( [ MSGNUM ] )'; 196 my $me = shift; 197 198 return undef 199 unless $me->_LIST(@_); 200 201 if(@_) 202 { 203 $me->message =~ /\d+\D+(\d+)/; 204 return $1 || undef; 205 } 206 207 my $info = $me->read_until_dot 208 or return undef; 209 210 my %hash = map { (/(\d+)\D+(\d+)/) } @$info; 211 212 return \%hash; 213} 214 215sub get 216{ 217 @_ == 2 or @_ == 3 or croak 'usage: $pop3->get( MSGNUM [, FH ])'; 218 my $me = shift; 219 220 return undef 221 unless $me->_RETR(shift); 222 223 $me->read_until_dot(@_); 224} 225 226sub getfh 227{ 228 @_ == 2 or croak 'usage: $pop3->getfh( MSGNUM )'; 229 my $me = shift; 230 231 return unless $me->_RETR(shift); 232 return $me->tied_fh; 233} 234 235 236 237sub delete 238{ 239 @_ == 2 or croak 'usage: $pop3->delete( MSGNUM )'; 240 my $me = shift; 241 return 0 unless $me->_DELE(@_); 242 ${*$me}{'net_pop3_deleted'} = 1; 243} 244 245sub uidl 246{ 247 @_ == 1 || @_ == 2 or croak 'usage: $pop3->uidl( [ MSGNUM ] )'; 248 my $me = shift; 249 my $uidl; 250 251 $me->_UIDL(@_) or 252 return undef; 253 if(@_) 254 { 255 $uidl = ($me->message =~ /\d+\s+([\041-\176]+)/)[0]; 256 } 257 else 258 { 259 my $ref = $me->read_until_dot 260 or return undef; 261 my $ln; 262 $uidl = {}; 263 foreach $ln (@$ref) { 264 my($msg,$uid) = $ln =~ /^\s*(\d+)\s+([\041-\176]+)/; 265 $uidl->{$msg} = $uid; 266 } 267 } 268 return $uidl; 269} 270 271sub ping 272{ 273 @_ == 2 or croak 'usage: $pop3->ping( USER )'; 274 my $me = shift; 275 276 return () unless $me->_PING(@_) && $me->message =~ /(\d+)\D+(\d+)/; 277 278 ($1 || 0, $2 || 0); 279} 280 281sub _lookup_credentials 282{ 283 my ($me, $user) = @_; 284 285 require Net::Netrc; 286 287 $user ||= eval { local $SIG{__DIE__}; (getpwuid($>))[0] } || 288 $ENV{NAME} || $ENV{USER} || $ENV{LOGNAME}; 289 290 my $m = Net::Netrc->lookup(${*$me}{'net_pop3_host'},$user); 291 $m ||= Net::Netrc->lookup(${*$me}{'net_pop3_host'}); 292 293 my $pass = $m ? $m->password || "" 294 : ""; 295 296 ($user, $pass); 297} 298 299sub _get_mailbox_count 300{ 301 my ($me) = @_; 302 my $ret = ${*$me}{'net_pop3_count'} = ($me->message =~ /(\d+)\s+message/io) 303 ? $1 : ($me->popstat)[0]; 304 305 $ret ? $ret : "0E0"; 306} 307 308 309sub _STAT { shift->command('STAT')->response() == CMD_OK } 310sub _LIST { shift->command('LIST',@_)->response() == CMD_OK } 311sub _RETR { shift->command('RETR',$_[0])->response() == CMD_OK } 312sub _DELE { shift->command('DELE',$_[0])->response() == CMD_OK } 313sub _NOOP { shift->command('NOOP')->response() == CMD_OK } 314sub _RSET { shift->command('RSET')->response() == CMD_OK } 315sub _QUIT { shift->command('QUIT')->response() == CMD_OK } 316sub _TOP { shift->command('TOP', @_)->response() == CMD_OK } 317sub _UIDL { shift->command('UIDL',@_)->response() == CMD_OK } 318sub _USER { shift->command('USER',$_[0])->response() == CMD_OK } 319sub _PASS { shift->command('PASS',$_[0])->response() == CMD_OK } 320sub _APOP { shift->command('APOP',@_)->response() == CMD_OK } 321sub _PING { shift->command('PING',$_[0])->response() == CMD_OK } 322 323sub _RPOP { shift->command('RPOP',$_[0])->response() == CMD_OK } 324sub _LAST { shift->command('LAST')->response() == CMD_OK } 325 326sub _CAPA { shift->command('CAPA')->response() == CMD_OK } 327 328sub quit 329{ 330 my $me = shift; 331 332 $me->_QUIT; 333 $me->close; 334} 335 336sub DESTROY 337{ 338 my $me = shift; 339 340 if(defined fileno($me) and ${*$me}{'net_pop3_deleted'}) 341 { 342 $me->reset; 343 $me->quit; 344 } 345} 346 347## 348## POP3 has weird responses, so we emulate them to look the same :-) 349## 350 351sub response { 352 my $cmd = shift; 353 my $str = $cmd->getline() or return undef; 354 my $code = "500"; 355 356 $cmd->debug_print(0, $str) 357 if ($cmd->debug); 358 359 if ($str =~ s/^\+OK\s*//io) { 360 $code = "200"; 361 } 362 elsif ($str =~ s/^\+\s*//io) { 363 $code = "300"; 364 } 365 else { 366 $str =~ s/^-ERR\s*//io; 367 } 368 369 ${*$cmd}{'net_cmd_resp'} = [$str]; 370 ${*$cmd}{'net_cmd_code'} = $code; 371 372 substr($code, 0, 1); 373} 374 375 376sub capa { 377 my $this = shift; 378 my ($capa, %capabilities); 379 380 # Fake a capability here 381 $capabilities{APOP} = '' if ($this->banner() =~ /<.*>/); 382 383 return \%capabilities unless $this->_CAPA(); 384 385 $capa = $this->read_until_dot(); 386 %capabilities = map { /^\s*(\S+)\s*(.*)/ } @$capa; 387 $capabilities{APOP} = '' if ($this->banner() =~ /<.*>/); 388 389 return ${*$this}{'net_pop3e_capabilities'} = \%capabilities; 390} 391 392sub capabilities { 393 my $this = shift; 394 395 ${*$this}{'net_pop3e_capabilities'} || $this->capa; 396} 397 398sub auth { 399 my ($self, $username, $password) = @_; 400 401 eval { 402 require MIME::Base64; 403 require Authen::SASL; 404 } or $self->set_status(500,["Need MIME::Base64 and Authen::SASL todo auth"]), return 0; 405 406 my $capa = $self->capa; 407 my $mechanisms = $capa->{SASL} || 'CRAM-MD5'; 408 409 my $sasl; 410 411 if (ref($username) and UNIVERSAL::isa($username,'Authen::SASL')) { 412 $sasl = $username; 413 $sasl->mechanism($mechanisms); 414 } 415 else { 416 die "auth(username, password)" if not length $username; 417 $sasl = Authen::SASL->new(mechanism=> $mechanisms, 418 callback => { user => $username, 419 pass => $password, 420 authname => $username, 421 }); 422 } 423 424 # We should probably allow the user to pass the host, but I don't 425 # currently know and SASL mechanisms that are used by smtp that need it 426 my $client = $sasl->client_new('pop3',${*$self}{'net_pop3_host'},0); 427 my $str = $client->client_start; 428 429 # We dont support sasl mechanisms that encrypt the socket traffic. 430 # todo that we would really need to change the ISA hierarchy 431 # so we dont inherit from IO::Socket, but instead hold it in an attribute 432 433 my @cmd = ("AUTH", $client->mechanism); 434 my $code; 435 436 push @cmd, MIME::Base64::encode_base64($str,'') 437 if defined $str and length $str; 438 439 while (($code = $self->command(@cmd)->response()) == CMD_MORE) { 440 @cmd = (MIME::Base64::encode_base64( 441 $client->client_step( 442 MIME::Base64::decode_base64( 443 ($self->message)[0] 444 ) 445 ), '' 446 )); 447 } 448 449 $code == CMD_OK; 450} 451 452sub banner { 453 my $this = shift; 454 455 return ${*$this}{'net_pop3_banner'}; 456} 457 4581; 459 460__END__ 461 462=head1 NAME 463 464Net::POP3 - Post Office Protocol 3 Client class (RFC1939) 465 466=head1 SYNOPSIS 467 468 use Net::POP3; 469 470 # Constructors 471 $pop = Net::POP3->new('pop3host'); 472 $pop = Net::POP3->new('pop3host', Timeout => 60); 473 474 if ($pop->login($username, $password) > 0) { 475 my $msgnums = $pop->list; # hashref of msgnum => size 476 foreach my $msgnum (keys %$msgnums) { 477 my $msg = $pop->get($msgnum); 478 print @$msg; 479 $pop->delete($msgnum); 480 } 481 } 482 483 $pop->quit; 484 485=head1 DESCRIPTION 486 487This module implements a client interface to the POP3 protocol, enabling 488a perl5 application to talk to POP3 servers. This documentation assumes 489that you are familiar with the POP3 protocol described in RFC1939. 490 491A new Net::POP3 object must be created with the I<new> method. Once 492this has been done, all POP3 commands are accessed via method calls 493on the object. 494 495=head1 CONSTRUCTOR 496 497=over 4 498 499=item new ( [ HOST ] [, OPTIONS ] 0 500 501This is the constructor for a new Net::POP3 object. C<HOST> is the 502name of the remote host to which an POP3 connection is required. 503 504C<HOST> is optional. If C<HOST> is not given then it may instead be 505passed as the C<Host> option described below. If neither is given then 506the C<POP3_Hosts> specified in C<Net::Config> will be used. 507 508C<OPTIONS> are passed in a hash like fashion, using key and value pairs. 509Possible options are: 510 511B<Host> - POP3 host to connect to. It may be a single scalar, as defined for 512the C<PeerAddr> option in L<IO::Socket::INET>, or a reference to 513an array with hosts to try in turn. The L</host> method will return the value 514which was used to connect to the host. 515 516B<ResvPort> - If given then the socket for the C<Net::POP3> object 517will be bound to the local port given using C<bind> when the socket is 518created. 519 520B<Timeout> - Maximum time, in seconds, to wait for a response from the 521POP3 server (default: 120) 522 523B<Debug> - Enable debugging information 524 525=back 526 527=head1 METHODS 528 529Unless otherwise stated all methods return either a I<true> or I<false> 530value, with I<true> meaning that the operation was a success. When a method 531states that it returns a value, failure will be returned as I<undef> or an 532empty list. 533 534=over 4 535 536=item auth ( USERNAME, PASSWORD ) 537 538Attempt SASL authentication. 539 540=item user ( USER ) 541 542Send the USER command. 543 544=item pass ( PASS ) 545 546Send the PASS command. Returns the number of messages in the mailbox. 547 548=item login ( [ USER [, PASS ]] ) 549 550Send both the USER and PASS commands. If C<PASS> is not given the 551C<Net::POP3> uses C<Net::Netrc> to lookup the password using the host 552and username. If the username is not specified then the current user name 553will be used. 554 555Returns the number of messages in the mailbox. However if there are no 556messages on the server the string C<"0E0"> will be returned. This is 557will give a true value in a boolean context, but zero in a numeric context. 558 559If there was an error authenticating the user then I<undef> will be returned. 560 561=item apop ( [ USER [, PASS ]] ) 562 563Authenticate with the server identifying as C<USER> with password C<PASS>. 564Similar to L</login>, but the password is not sent in clear text. 565 566To use this method you must have the Digest::MD5 or the MD5 module installed, 567otherwise this method will return I<undef>. 568 569=item banner () 570 571Return the sever's connection banner 572 573=item capa () 574 575Return a reference to a hash of the capabilties of the server. APOP 576is added as a pseudo capability. Note that I've been unable to 577find a list of the standard capability values, and some appear to 578be multi-word and some are not. We make an attempt at intelligently 579parsing them, but it may not be correct. 580 581=item capabilities () 582 583Just like capa, but only uses a cache from the last time we asked 584the server, so as to avoid asking more than once. 585 586=item top ( MSGNUM [, NUMLINES ] ) 587 588Get the header and the first C<NUMLINES> of the body for the message 589C<MSGNUM>. Returns a reference to an array which contains the lines of text 590read from the server. 591 592=item list ( [ MSGNUM ] ) 593 594If called with an argument the C<list> returns the size of the message 595in octets. 596 597If called without arguments a reference to a hash is returned. The 598keys will be the C<MSGNUM>'s of all undeleted messages and the values will 599be their size in octets. 600 601=item get ( MSGNUM [, FH ] ) 602 603Get the message C<MSGNUM> from the remote mailbox. If C<FH> is not given 604then get returns a reference to an array which contains the lines of 605text read from the server. If C<FH> is given then the lines returned 606from the server are printed to the filehandle C<FH>. 607 608=item getfh ( MSGNUM ) 609 610As per get(), but returns a tied filehandle. Reading from this 611filehandle returns the requested message. The filehandle will return 612EOF at the end of the message and should not be reused. 613 614=item last () 615 616Returns the highest C<MSGNUM> of all the messages accessed. 617 618=item popstat () 619 620Returns a list of two elements. These are the number of undeleted 621elements and the size of the mbox in octets. 622 623=item ping ( USER ) 624 625Returns a list of two elements. These are the number of new messages 626and the total number of messages for C<USER>. 627 628=item uidl ( [ MSGNUM ] ) 629 630Returns a unique identifier for C<MSGNUM> if given. If C<MSGNUM> is not 631given C<uidl> returns a reference to a hash where the keys are the 632message numbers and the values are the unique identifiers. 633 634=item delete ( MSGNUM ) 635 636Mark message C<MSGNUM> to be deleted from the remote mailbox. All messages 637that are marked to be deleted will be removed from the remote mailbox 638when the server connection closed. 639 640=item reset () 641 642Reset the status of the remote POP3 server. This includes reseting the 643status of all messages to not be deleted. 644 645=item quit () 646 647Quit and close the connection to the remote POP3 server. Any messages marked 648as deleted will be deleted from the remote mailbox. 649 650=back 651 652=head1 NOTES 653 654If a C<Net::POP3> object goes out of scope before C<quit> method is called 655then the C<reset> method will called before the connection is closed. This 656means that any messages marked to be deleted will not be. 657 658=head1 SEE ALSO 659 660L<Net::Netrc>, 661L<Net::Cmd> 662 663=head1 AUTHOR 664 665Graham Barr <gbarr@pobox.com> 666 667=head1 COPYRIGHT 668 669Copyright (c) 1995-2003 Graham Barr. All rights reserved. 670This program is free software; you can redistribute it and/or modify 671it under the same terms as Perl itself. 672 673=cut 674