This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Synch with CPAN distribution libnet-3.12
[perl5.git] / cpan / libnet / lib / Net / POP3.pm
1 # Net::POP3.pm
2 #
3 # Copyright (C) 1995-2004 Graham Barr.  All rights reserved.
4 # Copyright (C) 2013-2016, 2020 Steve Hay.  All rights reserved.
5 # This module is free software; you can redistribute it and/or modify it under
6 # the same terms as Perl itself, i.e. under the terms of either the GNU General
7 # Public License or the Artistic License, as specified in the F<LICENCE> file.
8
9 package Net::POP3;
10
11 use 5.008001;
12
13 use strict;
14 use warnings;
15
16 use Carp;
17 use IO::Socket;
18 use Net::Cmd;
19 use Net::Config;
20
21 our $VERSION = "3.12";
22
23 # Code for detecting if we can use SSL
24 my $ssl_class = eval {
25   require IO::Socket::SSL;
26   # first version with default CA on most platforms
27   no warnings 'numeric';
28   IO::Socket::SSL->VERSION(2.007);
29 } && 'IO::Socket::SSL';
30
31 my $nossl_warn = !$ssl_class &&
32   'To use SSL please install IO::Socket::SSL with version>=2.007';
33
34 # Code for detecting if we can use IPv6
35 my $family_key = 'Domain';
36 my $inet6_class = eval {
37   require IO::Socket::IP;
38   no warnings 'numeric';
39   IO::Socket::IP->VERSION(0.25) || die;
40   $family_key = 'Family';
41 } && 'IO::Socket::IP' || eval {
42   require IO::Socket::INET6;
43   no warnings 'numeric';
44   IO::Socket::INET6->VERSION(2.62);
45 } && 'IO::Socket::INET6';
46
47
48 sub can_ssl   { $ssl_class };
49 sub can_inet6 { $inet6_class };
50
51 our @ISA = ('Net::Cmd', $inet6_class || 'IO::Socket::INET');
52
53 sub new {
54   my $self = shift;
55   my $type = ref($self) || $self;
56   my ($host, %arg);
57   if (@_ % 2) {
58     $host = shift;
59     %arg  = @_;
60   }
61   else {
62     %arg  = @_;
63     $host = delete $arg{Host};
64   }
65   my $hosts = defined $host ? [$host] : $NetConfig{pop3_hosts};
66   my $obj;
67
68   if ($arg{SSL}) {
69     # SSL from start
70     die $nossl_warn if !$ssl_class;
71     $arg{Port} ||= 995;
72   }
73
74   $arg{Timeout} = 120 if ! defined $arg{Timeout};
75
76   foreach my $h (@{$hosts}) {
77     $obj = $type->SUPER::new(
78       PeerAddr => ($host = $h),
79       PeerPort => $arg{Port} || 'pop3(110)',
80       Proto => 'tcp',
81       $family_key => $arg{Domain} || $arg{Family},
82       LocalAddr => $arg{LocalAddr},
83       LocalPort => exists($arg{ResvPort}) ? $arg{ResvPort} : $arg{LocalPort},
84       Timeout => $arg{Timeout},
85       )
86       and last;
87   }
88
89   return
90     unless defined $obj;
91
92   ${*$obj}{'net_pop3_arg'} = \%arg;
93   ${*$obj}{'net_pop3_host'} = $host;
94   if ($arg{SSL}) {
95     Net::POP3::_SSL->start_SSL($obj,%arg) or return;
96   }
97
98   $obj->autoflush(1);
99   $obj->debug(exists $arg{Debug} ? $arg{Debug} : undef);
100
101   unless ($obj->response() == CMD_OK) {
102     $obj->close();
103     return;
104   }
105
106   ${*$obj}{'net_pop3_banner'} = $obj->message;
107
108   $obj;
109 }
110
111
112 sub host {
113   my $me = shift;
114   ${*$me}{'net_pop3_host'};
115 }
116
117 ##
118 ## We don't want people sending me their passwords when they report problems
119 ## now do we :-)
120 ##
121
122
123 sub debug_text { $_[2] =~ /^(pass|rpop)/i ? "$1 ....\n" : $_[2]; }
124
125
126 sub login {
127   @_ >= 1 && @_ <= 3 or croak 'usage: $pop3->login([$user[, $pass]])';
128   my ($me, $user, $pass) = @_;
129
130   if (@_ <= 2) {
131     ($user, $pass) = $me->_lookup_credentials($user);
132   }
133
134   $me->user($user)
135     and $me->pass($pass);
136 }
137
138 sub starttls {
139   my $self = shift;
140   $ssl_class or die $nossl_warn;
141   $self->_STLS or return;
142   Net::POP3::_SSL->start_SSL($self,
143     %{ ${*$self}{'net_pop3_arg'} }, # (ssl) args given in new
144     @_   # more (ssl) args
145   ) or return;
146   return 1;
147 }
148
149 sub apop {
150   @_ >= 1 && @_ <= 3 or croak 'usage: $pop3->apop([$user[, $pass]])';
151   my ($me, $user, $pass) = @_;
152   my $banner;
153   my $md;
154
155   if (eval { local $SIG{__DIE__}; require Digest::MD5 }) {
156     $md = Digest::MD5->new();
157   }
158   elsif (eval { local $SIG{__DIE__}; require MD5 }) {
159     $md = MD5->new();
160   }
161   else {
162     carp "You need to install Digest::MD5 or MD5 to use the APOP command";
163     return;
164   }
165
166   return
167     unless ($banner = (${*$me}{'net_pop3_banner'} =~ /(<.*>)/)[0]);
168
169   if (@_ <= 2) {
170     ($user, $pass) = $me->_lookup_credentials($user);
171   }
172
173   $md->add($banner, $pass);
174
175   return
176     unless ($me->_APOP($user, $md->hexdigest));
177
178   $me->_get_mailbox_count();
179 }
180
181
182 sub user {
183   @_ == 2 or croak 'usage: $pop3->user($user)';
184   $_[0]->_USER($_[1]) ? 1 : undef;
185 }
186
187
188 sub pass {
189   @_ == 2 or croak 'usage: $pop3->pass($pass)';
190
191   my ($me, $pass) = @_;
192
193   return
194     unless ($me->_PASS($pass));
195
196   $me->_get_mailbox_count();
197 }
198
199
200 sub reset {
201   @_ == 1 or croak 'usage: $obj->reset()';
202
203   my $me = shift;
204
205   return 0
206     unless ($me->_RSET);
207
208   if (defined ${*$me}{'net_pop3_mail'}) {
209     local $_;
210     foreach (@{${*$me}{'net_pop3_mail'}}) {
211       delete $_->{'net_pop3_deleted'};
212     }
213   }
214 }
215
216
217 sub last {
218   @_ == 1 or croak 'usage: $obj->last()';
219
220   return
221     unless $_[0]->_LAST && $_[0]->message =~ /(\d+)/;
222
223   return $1;
224 }
225
226
227 sub top {
228   @_ == 2 || @_ == 3 or croak 'usage: $pop3->top($msgnum[, $numlines])';
229   my $me = shift;
230
231   return
232     unless $me->_TOP($_[0], $_[1] || 0);
233
234   $me->read_until_dot;
235 }
236
237
238 sub popstat {
239   @_ == 1 or croak 'usage: $pop3->popstat()';
240   my $me = shift;
241
242   return ()
243     unless $me->_STAT && $me->message =~ /(\d+)\D+(\d+)/;
244
245   ($1 || 0, $2 || 0);
246 }
247
248
249 sub list {
250   @_ == 1 || @_ == 2 or croak 'usage: $pop3->list([$msgnum])';
251   my $me = shift;
252
253   return
254     unless $me->_LIST(@_);
255
256   if (@_) {
257     $me->message =~ /\d+\D+(\d+)/;
258     return $1 || undef;
259   }
260
261   my $info = $me->read_until_dot
262     or return;
263
264   my %hash = map { (/(\d+)\D+(\d+)/) } @$info;
265
266   return \%hash;
267 }
268
269
270 sub get {
271   @_ == 2 or @_ == 3 or croak 'usage: $pop3->get($msgnum[, $fh])';
272   my $me = shift;
273
274   return
275     unless $me->_RETR(shift);
276
277   $me->read_until_dot(@_);
278 }
279
280
281 sub getfh {
282   @_ == 2 or croak 'usage: $pop3->getfh($msgnum)';
283   my $me = shift;
284
285   return unless $me->_RETR(shift);
286   return $me->tied_fh;
287 }
288
289
290 sub delete {
291   @_ == 2 or croak 'usage: $pop3->delete($msgnum)';
292   my $me = shift;
293   return 0 unless $me->_DELE(@_);
294   ${*$me}{'net_pop3_deleted'} = 1;
295 }
296
297
298 sub uidl {
299   @_ == 1 || @_ == 2 or croak 'usage: $pop3->uidl([$msgnum])';
300   my $me = shift;
301   my $uidl;
302
303   $me->_UIDL(@_)
304     or return;
305   if (@_) {
306     $uidl = ($me->message =~ /\d+\s+([\041-\176]+)/)[0];
307   }
308   else {
309     my $ref = $me->read_until_dot
310       or return;
311     $uidl = {};
312     foreach my $ln (@$ref) {
313       my ($msg, $uid) = $ln =~ /^\s*(\d+)\s+([\041-\176]+)/;
314       $uidl->{$msg} = $uid;
315     }
316   }
317   return $uidl;
318 }
319
320
321 sub ping {
322   @_ == 2 or croak 'usage: $pop3->ping($user)';
323   my $me = shift;
324
325   return () unless $me->_PING(@_) && $me->message =~ /(\d+)\D+(\d+)/;
326
327   ($1 || 0, $2 || 0);
328 }
329
330
331 sub _lookup_credentials {
332   my ($me, $user) = @_;
333
334   require Net::Netrc;
335
336        $user ||= eval { local $SIG{__DIE__}; (getpwuid($>))[0] }
337     || $ENV{NAME}
338     || $ENV{USER}
339     || $ENV{LOGNAME};
340
341   my $m = Net::Netrc->lookup(${*$me}{'net_pop3_host'}, $user);
342   $m ||= Net::Netrc->lookup(${*$me}{'net_pop3_host'});
343
344   my $pass = $m
345     ? $m->password || ""
346     : "";
347
348   ($user, $pass);
349 }
350
351
352 sub _get_mailbox_count {
353   my ($me) = @_;
354   my $ret = ${*$me}{'net_pop3_count'} =
355     ($me->message =~ /(\d+)\s+message/io) ? $1 : ($me->popstat)[0];
356
357   $ret ? $ret : "0E0";
358 }
359
360
361 sub _STAT { shift->command('STAT'       )->response() == CMD_OK }
362 sub _LIST { shift->command('LIST',    @_)->response() == CMD_OK }
363 sub _RETR { shift->command('RETR', $_[0])->response() == CMD_OK }
364 sub _DELE { shift->command('DELE', $_[0])->response() == CMD_OK }
365 sub _NOOP { shift->command('NOOP'       )->response() == CMD_OK }
366 sub _RSET { shift->command('RSET'       )->response() == CMD_OK }
367 sub _QUIT { shift->command('QUIT'       )->response() == CMD_OK }
368 sub _TOP  { shift->command( 'TOP',    @_)->response() == CMD_OK }
369 sub _UIDL { shift->command('UIDL',    @_)->response() == CMD_OK }
370 sub _USER { shift->command('USER', $_[0])->response() == CMD_OK }
371 sub _PASS { shift->command('PASS', $_[0])->response() == CMD_OK }
372 sub _APOP { shift->command('APOP',    @_)->response() == CMD_OK }
373 sub _PING { shift->command('PING', $_[0])->response() == CMD_OK }
374 sub _RPOP { shift->command('RPOP', $_[0])->response() == CMD_OK }
375 sub _LAST { shift->command('LAST'       )->response() == CMD_OK }
376 sub _CAPA { shift->command('CAPA'       )->response() == CMD_OK }
377 sub _STLS { shift->command("STLS",     )->response() == CMD_OK }
378
379
380 sub quit {
381   my $me = shift;
382
383   $me->_QUIT;
384   $me->close;
385 }
386
387
388 sub DESTROY {
389   my $me = shift;
390
391   if (defined fileno($me) and ${*$me}{'net_pop3_deleted'}) {
392     $me->reset;
393     $me->quit;
394   }
395 }
396
397 ##
398 ## POP3 has weird responses, so we emulate them to look the same :-)
399 ##
400
401
402 sub response {
403   my $cmd  = shift;
404   my $str  = $cmd->getline() or return;
405   my $code = "500";
406
407   $cmd->debug_print(0, $str)
408     if ($cmd->debug);
409
410   if ($str =~ s/^\+OK\s*//io) {
411     $code = "200";
412   }
413   elsif ($str =~ s/^\+\s*//io) {
414     $code = "300";
415   }
416   else {
417     $str =~ s/^-ERR\s*//io;
418   }
419
420   ${*$cmd}{'net_cmd_resp'} = [$str];
421   ${*$cmd}{'net_cmd_code'} = $code;
422
423   substr($code, 0, 1);
424 }
425
426
427 sub capa {
428   my $this = shift;
429   my ($capa, %capabilities);
430
431   # Fake a capability here
432   $capabilities{APOP} = '' if ($this->banner() =~ /<.*>/);
433
434   if ($this->_CAPA()) {
435     $capabilities{CAPA} = 1;
436     $capa = $this->read_until_dot();
437     %capabilities = (%capabilities, map {/^\s*(\S+)\s*(.*)/} @$capa);
438   }
439   else {
440
441     # Check AUTH for SASL capabilities
442     if ($this->command('AUTH')->response() == CMD_OK) {
443       my $mechanism = $this->read_until_dot();
444       $capabilities{SASL} = join " ", map {m/([A-Z0-9_-]+)/} @{$mechanism};
445     }
446   }
447
448   return ${*$this}{'net_pop3e_capabilities'} = \%capabilities;
449 }
450
451
452 sub capabilities {
453   my $this = shift;
454
455   ${*$this}{'net_pop3e_capabilities'} || $this->capa;
456 }
457
458
459 sub auth {
460   my ($self, $username, $password) = @_;
461
462   eval {
463     require MIME::Base64;
464     require Authen::SASL;
465   } or $self->set_status(500, ["Need MIME::Base64 and Authen::SASL todo auth"]), return 0;
466
467   my $capa       = $self->capa;
468   my $mechanisms = $capa->{SASL} || 'CRAM-MD5';
469
470   my $sasl;
471
472   if (ref($username) and UNIVERSAL::isa($username, 'Authen::SASL')) {
473     $sasl = $username;
474     my $user_mech = $sasl->mechanism || '';
475     my @user_mech = split(/\s+/, $user_mech);
476     my %user_mech;
477     @user_mech{@user_mech} = ();
478
479     my @server_mech = split(/\s+/, $mechanisms);
480     my @mech = @user_mech
481       ? grep { exists $user_mech{$_} } @server_mech
482       : @server_mech;
483     unless (@mech) {
484       $self->set_status(
485         500,
486         [ 'Client SASL mechanisms (',
487           join(', ', @user_mech),
488           ') do not match the SASL mechnism the server announces (',
489           join(', ', @server_mech), ')',
490         ]
491       );
492       return 0;
493     }
494
495     $sasl->mechanism(join(" ", @mech));
496   }
497   else {
498     die "auth(username, password)" if not length $username;
499     $sasl = Authen::SASL->new(
500       mechanism => $mechanisms,
501       callback  => {
502         user     => $username,
503         pass     => $password,
504         authname => $username,
505       }
506     );
507   }
508
509   # We should probably allow the user to pass the host, but I don't
510   # currently know and SASL mechanisms that are used by smtp that need it
511   my ($hostname) = split /:/, ${*$self}{'net_pop3_host'};
512   my $client = eval { $sasl->client_new('pop', $hostname, 0) };
513
514   unless ($client) {
515     my $mech = $sasl->mechanism;
516     $self->set_status(
517       500,
518       [ " Authen::SASL failure: $@",
519         '(please check if your local Authen::SASL installation',
520         "supports mechanism '$mech'"
521       ]
522     );
523     return 0;
524   }
525
526   my ($token) = $client->client_start
527     or do {
528     my $mech = $client->mechanism;
529     $self->set_status(
530       500,
531       [ ' Authen::SASL failure:  $client->client_start ',
532         "mechanism '$mech' hostname #$hostname#",
533         $client->error
534       ]
535     );
536     return 0;
537     };
538
539   # We don't support sasl mechanisms that encrypt the socket traffic.
540   # todo that we would really need to change the ISA hierarchy
541   # so we don't inherit from IO::Socket, but instead hold it in an attribute
542
543   my @cmd = ("AUTH", $client->mechanism);
544   my $code;
545
546   push @cmd, MIME::Base64::encode_base64($token, '')
547     if defined $token and length $token;
548
549   while (($code = $self->command(@cmd)->response()) == CMD_MORE) {
550
551     my ($token) = $client->client_step(MIME::Base64::decode_base64(($self->message)[0])) or do {
552       $self->set_status(
553         500,
554         [ ' Authen::SASL failure:  $client->client_step ',
555           "mechanism '", $client->mechanism, " hostname #$hostname#, ",
556           $client->error
557         ]
558       );
559       return 0;
560     };
561
562     @cmd = (MIME::Base64::encode_base64(defined $token ? $token : '', ''));
563   }
564
565   $code == CMD_OK;
566 }
567
568
569 sub banner {
570   my $this = shift;
571
572   return ${*$this}{'net_pop3_banner'};
573 }
574
575 {
576   package Net::POP3::_SSL;
577   our @ISA = ( $ssl_class ? ($ssl_class):(), 'Net::POP3' );
578   sub starttls { die "POP3 connection is already in SSL mode" }
579   sub start_SSL {
580     my ($class,$pop3,%arg) = @_;
581     delete @arg{ grep { !m{^SSL_} } keys %arg };
582     ( $arg{SSL_verifycn_name} ||= $pop3->host )
583         =~s{(?<!:):[\w()]+$}{}; # strip port
584     $arg{SSL_hostname} = $arg{SSL_verifycn_name}
585         if ! defined $arg{SSL_hostname} && $class->can_client_sni;
586     $arg{SSL_verifycn_scheme} ||= 'pop3';
587     my $ok = $class->SUPER::start_SSL($pop3,%arg);
588     $@ = $ssl_class->errstr if !$ok;
589     return $ok;
590   }
591 }
592
593
594
595 1;
596
597 __END__
598
599 =head1 NAME
600
601 Net::POP3 - Post Office Protocol 3 Client class (RFC1939)
602
603 =head1 SYNOPSIS
604
605     use Net::POP3;
606
607     # Constructors
608     $pop = Net::POP3->new('pop3host');
609     $pop = Net::POP3->new('pop3host', Timeout => 60);
610     $pop = Net::POP3->new('pop3host', SSL => 1, Timeout => 60);
611
612     if ($pop->login($username, $password) > 0) {
613       my $msgnums = $pop->list; # hashref of msgnum => size
614       foreach my $msgnum (keys %$msgnums) {
615         my $msg = $pop->get($msgnum);
616         print @$msg;
617         $pop->delete($msgnum);
618       }
619     }
620
621     $pop->quit;
622
623 =head1 DESCRIPTION
624
625 This module implements a client interface to the POP3 protocol, enabling
626 a perl5 application to talk to POP3 servers. This documentation assumes
627 that you are familiar with the POP3 protocol described in RFC1939.
628 With L<IO::Socket::SSL> installed it also provides support for implicit and
629 explicit TLS encryption, i.e. POP3S or POP3+STARTTLS.
630
631 A new Net::POP3 object must be created with the I<new> method. Once
632 this has been done, all POP3 commands are accessed via method calls
633 on the object.
634
635 The Net::POP3 class is a subclass of Net::Cmd and (depending on avaibility) of
636 IO::Socket::IP, IO::Socket::INET6 or IO::Socket::INET.
637
638 =head2 Class Methods
639
640 =over 4
641
642 =item C<new([$host][, %options])>
643
644 This is the constructor for a new Net::POP3 object. C<$host> is the
645 name of the remote host to which an POP3 connection is required.
646
647 C<$host> is optional. If C<$host> is not given then it may instead be
648 passed as the C<Host> option described below. If neither is given then
649 the C<POP3_Hosts> specified in C<Net::Config> will be used.
650
651 C<%options> are passed in a hash like fashion, using key and value pairs.
652 Possible options are:
653
654 B<Host> - POP3 host to connect to. It may be a single scalar, as defined for
655 the C<PeerAddr> option in L<IO::Socket::INET>, or a reference to
656 an array with hosts to try in turn. The L</host> method will return the value
657 which was used to connect to the host.
658
659 B<Port> - port to connect to.
660 Default - 110 for plain POP3 and 995 for POP3s (direct SSL).
661
662 B<SSL> - If the connection should be done from start with SSL, contrary to later
663 upgrade with C<starttls>.
664 You can use SSL arguments as documented in L<IO::Socket::SSL>, but it will
665 usually use the right arguments already.
666
667 B<LocalAddr> and B<LocalPort> - These parameters are passed directly
668 to IO::Socket to allow binding the socket to a specific local address and port.
669 For compatibility with older versions B<ResvPort> can be used instead of
670 B<LocalPort>.
671
672 B<Domain> - This parameter is passed directly to IO::Socket and makes it
673 possible to enforce IPv4 connections even if L<IO::Socket::IP> is used as super
674 class. Alternatively B<Family> can be used.
675
676 B<Timeout> - Maximum time, in seconds, to wait for a response from the
677 POP3 server (default: 120)
678
679 B<Debug> - Enable debugging information
680
681 =back
682
683 =head2 Object Methods
684
685 Unless otherwise stated all methods return either a I<true> or I<false>
686 value, with I<true> meaning that the operation was a success. When a method
687 states that it returns a value, failure will be returned as I<undef> or an
688 empty list.
689
690 C<Net::POP3> inherits from C<Net::Cmd> so methods defined in C<Net::Cmd> may
691 be used to send commands to the remote POP3 server in addition to the methods
692 documented here.
693
694 =over 4
695
696 =item C<host()>
697
698 Returns the value used by the constructor, and passed to IO::Socket::INET,
699 to connect to the host.
700
701 =item C<auth($username, $password)>
702
703 Attempt SASL authentication.
704
705 =item C<user($user)>
706
707 Send the USER command.
708
709 =item C<pass($pass)>
710
711 Send the PASS command. Returns the number of messages in the mailbox.
712
713 =item C<login([$user[, $pass]])>
714
715 Send both the USER and PASS commands. If C<$pass> is not given the
716 C<Net::POP3> uses C<Net::Netrc> to lookup the password using the host
717 and username. If the username is not specified then the current user name
718 will be used.
719
720 Returns the number of messages in the mailbox. However if there are no
721 messages on the server the string C<"0E0"> will be returned. This is
722 will give a true value in a boolean context, but zero in a numeric context.
723
724 If there was an error authenticating the user then I<undef> will be returned.
725
726 =item C<starttls(%sslargs)>
727
728 Upgrade existing plain connection to SSL.
729 You can use SSL arguments as documented in L<IO::Socket::SSL>, but it will
730 usually use the right arguments already.
731
732 =item C<apop([$user[, $pass]])>
733
734 Authenticate with the server identifying as C<$user> with password C<$pass>.
735 Similar to L</login>, but the password is not sent in clear text.
736
737 To use this method you must have the Digest::MD5 or the MD5 module installed,
738 otherwise this method will return I<undef>.
739
740 =item C<banner()>
741
742 Return the sever's connection banner
743
744 =item C<capa()>
745
746 Return a reference to a hash of the capabilities of the server.  APOP
747 is added as a pseudo capability.  Note that I've been unable to
748 find a list of the standard capability values, and some appear to
749 be multi-word and some are not.  We make an attempt at intelligently
750 parsing them, but it may not be correct.
751
752 =item C<capabilities()>
753
754 Just like capa, but only uses a cache from the last time we asked
755 the server, so as to avoid asking more than once.
756
757 =item C<top($msgnum[, $numlines])>
758
759 Get the header and the first C<$numlines> of the body for the message
760 C<$msgnum>. Returns a reference to an array which contains the lines of text
761 read from the server.
762
763 =item C<list([$msgnum])>
764
765 If called with an argument the C<list> returns the size of the message
766 in octets.
767
768 If called without arguments a reference to a hash is returned. The
769 keys will be the C<$msgnum>'s of all undeleted messages and the values will
770 be their size in octets.
771
772 =item C<get($msgnum[, $fh])>
773
774 Get the message C<$msgnum> from the remote mailbox. If C<$fh> is not given
775 then get returns a reference to an array which contains the lines of
776 text read from the server. If C<$fh> is given then the lines returned
777 from the server are printed to the filehandle C<$fh>.
778
779 =item C<getfh($msgnum)>
780
781 As per get(), but returns a tied filehandle.  Reading from this
782 filehandle returns the requested message.  The filehandle will return
783 EOF at the end of the message and should not be reused.
784
785 =item C<last()>
786
787 Returns the highest C<$msgnum> of all the messages accessed.
788
789 =item C<popstat()>
790
791 Returns a list of two elements. These are the number of undeleted
792 elements and the size of the mbox in octets.
793
794 =item C<ping($user)>
795
796 Returns a list of two elements. These are the number of new messages
797 and the total number of messages for C<$user>.
798
799 =item C<uidl([$msgnum])>
800
801 Returns a unique identifier for C<$msgnum> if given. If C<$msgnum> is not
802 given C<uidl> returns a reference to a hash where the keys are the
803 message numbers and the values are the unique identifiers.
804
805 =item C<delete($msgnum)>
806
807 Mark message C<$msgnum> to be deleted from the remote mailbox. All messages
808 that are marked to be deleted will be removed from the remote mailbox
809 when the server connection closed.
810
811 =item C<reset()>
812
813 Reset the status of the remote POP3 server. This includes resetting the
814 status of all messages to not be deleted.
815
816 =item C<quit()>
817
818 Quit and close the connection to the remote POP3 server. Any messages marked
819 as deleted will be deleted from the remote mailbox.
820
821 =item C<can_inet6()>
822
823 Returns whether we can use IPv6.
824
825 =item C<can_ssl()>
826
827 Returns whether we can use SSL.
828
829 =back
830
831 =head2 Notes
832
833 If a C<Net::POP3> object goes out of scope before C<quit> method is called
834 then the C<reset> method will called before the connection is closed. This
835 means that any messages marked to be deleted will not be.
836
837 =head1 EXPORTS
838
839 I<None>.
840
841 =head1 KNOWN BUGS
842
843 See L<https://rt.cpan.org/Dist/Display.html?Status=Active&Queue=libnet>.
844
845 =head1 SEE ALSO
846
847 L<Net::Netrc>,
848 L<Net::Cmd>,
849 L<IO::Socket::SSL>.
850
851 =head1 AUTHOR
852
853 Graham Barr E<lt>L<gbarr@pobox.com|mailto:gbarr@pobox.com>E<gt>.
854
855 Steve Hay E<lt>L<shay@cpan.org|mailto:shay@cpan.org>E<gt> is now maintaining
856 libnet as of version 1.22_02.
857
858 =head1 COPYRIGHT
859
860 Copyright (C) 1995-2004 Graham Barr.  All rights reserved.
861
862 Copyright (C) 2013-2016, 2020 Steve Hay.  All rights reserved.
863
864 =head1 LICENCE
865
866 This module is free software; you can redistribute it and/or modify it under the
867 same terms as Perl itself, i.e. under the terms of either the GNU General Public
868 License or the Artistic License, as specified in the F<LICENCE> file.
869
870 =head1 VERSION
871
872 Version 3.12
873
874 =head1 DATE
875
876 09 Dec 2020
877
878 =head1 HISTORY
879
880 See the F<Changes> file.
881
882 =cut