This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Re: Make Passive mode the default for Net::FTP
[perl5.git] / lib / Net / POP3.pm
CommitLineData
406c51ee
JH
1# Net::POP3.pm
2#
f92f3fcb 3# Copyright (c) 1995-2004 Graham Barr <gbarr@pobox.com>. All rights reserved.
406c51ee
JH
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
9714c667 16$VERSION = "2.28";
406c51ee
JH
17
18@ISA = qw(Net::Cmd IO::Socket::INET);
19
20sub new
21{
22 my $self = shift;
23 my $type = ref($self) || $self;
f92f3fcb
GB
24 my ($host,%arg);
25 if (@_ % 2) {
26 $host = shift ;
27 %arg = @_;
28 } else {
29 %arg = @_;
30 $host=delete $arg{Host};
31 }
406c51ee
JH
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
f92f3fcb
GB
68sub host {
69 my $me = shift;
70 ${*$me}{'net_pop3_host'};
71}
72
406c51ee
JH
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
12df23ee
GB
85 if (@_ <= 2) {
86 ($user, $pass) = $me->_lookup_credentials($user);
87 }
406c51ee
JH
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;
12df23ee
GB
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";
406c51ee 106 return undef;
12df23ee 107 }
406c51ee
JH
108
109 return undef
110 unless ( $banner = (${*$me}{'net_pop3_banner'} =~ /(<.*>)/)[0] );
111
12df23ee
GB
112 if (@_ <= 2) {
113 ($user, $pass) = $me->_lookup_credentials($user);
114 }
406c51ee 115
406c51ee
JH
116 $md->add($banner,$pass);
117
118 return undef
119 unless($me->_APOP($user,$md->hexdigest));
120
12df23ee 121 $me->_get_mailbox_count();
406c51ee
JH
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
12df23ee 139 $me->_get_mailbox_count();
406c51ee
JH
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);
686337f3 150
406c51ee
JH
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 }
686337f3 206
406c51ee
JH
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
12df23ee
GB
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
406c51ee
JH
237sub delete
238{
239 @_ == 2 or croak 'usage: $pop3->delete( MSGNUM )';
f92f3fcb
GB
240 my $me = shift;
241 return 0 unless $me->_DELE(@_);
242 ${*$me}{'net_pop3_deleted'} = 1;
406c51ee
JH
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
12df23ee
GB
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
686337f3 308
406c51ee
JH
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
f92f3fcb
GB
326sub _CAPA { shift->command('CAPA')->response() == CMD_OK }
327
406c51ee
JH
328sub quit
329{
330 my $me = shift;
331
332 $me->_QUIT;
333 $me->close;
334}
335
336sub DESTROY
337{
338 my $me = shift;
339
f92f3fcb 340 if(defined fileno($me) and ${*$me}{'net_pop3_deleted'})
406c51ee
JH
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
f92f3fcb
GB
351sub response {
352 my $cmd = shift;
353 my $str = $cmd->getline() or return undef;
354 my $code = "500";
406c51ee 355
f92f3fcb
GB
356 $cmd->debug_print(0, $str)
357 if ($cmd->debug);
406c51ee 358
f92f3fcb
GB
359 if ($str =~ s/^\+OK\s*//io) {
360 $code = "200";
406c51ee 361 }
f92f3fcb
GB
362 elsif ($str =~ s/^\+\s*//io) {
363 $code = "300";
364 }
365 else {
366 $str =~ s/^-ERR\s*//io;
406c51ee
JH
367 }
368
f92f3fcb
GB
369 ${*$cmd}{'net_cmd_resp'} = [$str];
370 ${*$cmd}{'net_cmd_code'} = $code;
406c51ee 371
f92f3fcb
GB
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;
9714c667 404 } or $self->set_status(500,["Need MIME::Base64 and Authen::SASL todo auth"]), return 0;
f92f3fcb
GB
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'};
406c51ee
JH
456}
457
4581;
459
460__END__
461
462=head1 NAME
463
12df23ee 464Net::POP3 - Post Office Protocol 3 Client class (RFC1939)
406c51ee
JH
465
466=head1 SYNOPSIS
467
468 use Net::POP3;
686337f3 469
406c51ee
JH
470 # Constructors
471 $pop = Net::POP3->new('pop3host');
472 $pop = Net::POP3->new('pop3host', Timeout => 60);
473
dea4d7df
GB
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
406c51ee
JH
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
12df23ee 489that you are familiar with the POP3 protocol described in RFC1939.
406c51ee
JH
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
406c51ee
JH
495=head1 CONSTRUCTOR
496
497=over 4
498
f92f3fcb 499=item new ( [ HOST ] [, OPTIONS ] 0
406c51ee
JH
500
501This is the constructor for a new Net::POP3 object. C<HOST> is the
f92f3fcb 502name of the remote host to which an POP3 connection is required.
406c51ee 503
f92f3fcb
GB
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.
406c51ee
JH
507
508C<OPTIONS> are passed in a hash like fashion, using key and value pairs.
509Possible options are:
510
f92f3fcb
GB
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
406c51ee
JH
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
f92f3fcb
GB
536=item auth ( USERNAME, PASSWORD )
537
538Attempt SASL authentication.
539
406c51ee
JH
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
d1be9408 550Send both the USER and PASS commands. If C<PASS> is not given the
406c51ee
JH
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
12df23ee 561=item apop ( [ USER [, PASS ]] )
406c51ee
JH
562
563Authenticate with the server identifying as C<USER> with password C<PASS>.
12df23ee 564Similar to L</login>, but the password is not sent in clear text.
406c51ee 565
12df23ee
GB
566To use this method you must have the Digest::MD5 or the MD5 module installed,
567otherwise this method will return I<undef>.
406c51ee 568
f92f3fcb
GB
569=item banner ()
570
571Return the sever's connection banner
572
573=item capa ()
574
3c4b39be 575Return a reference to a hash of the capabilities of the server. APOP
f92f3fcb
GB
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
406c51ee
JH
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
12df23ee
GB
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
406c51ee
JH
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
3c4b39be 642Reset the status of the remote POP3 server. This includes resetting the
406c51ee
JH
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
12df23ee 660L<Net::Netrc>,
406c51ee
JH
661L<Net::Cmd>
662
663=head1 AUTHOR
664
665Graham Barr <gbarr@pobox.com>
666
667=head1 COPYRIGHT
668
f92f3fcb 669Copyright (c) 1995-2003 Graham Barr. All rights reserved.
406c51ee
JH
670This program is free software; you can redistribute it and/or modify
671it under the same terms as Perl itself.
672
673=cut