[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/se3-unattended/var/se3/unattended/install/linuxaux/opt/perl/lib/5.10.0/Net/ -> POP3.pm (source)

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


Generated: Tue Mar 17 22:47:18 2015 Cross-referenced by PHPXref 0.7.1