PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/linkedfs/usr/lib/perl5/5.8.6/Net/POP3.pm

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