PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.0
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.0
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
← All changes | back/Libraries/Pear/Pop3.php +1225 -0 11.1.1 → 11.1.0 View file →
@@ -1,0 +1,1225 @@
1 +<?php
2 +
3 +namespace AcyMailing\Libraries\Pear;
4 +
5 +acym_cmsLoaded();
6 +
7 +// +-----------------------------------------------------------------------+
8 +// | Copyright (c) 2002, Richard Heyes |
9 +// | All rights reserved. |
10 +// | |
11 +// | Redistribution and use in source and binary forms, with or without |
12 +// | modification, are permitted provided that the following conditions |
13 +// | are met: |
14 +// | |
15 +// | o Redistributions of source code must retain the above copyright |
16 +// | notice, this list of conditions and the following disclaimer. |
17 +// | o Redistributions in binary form must reproduce the above copyright |
18 +// | notice, this list of conditions and the following disclaimer in the |
19 +// | documentation and/or other materials provided with the distribution.|
20 +// | o The names of the authors may not be used to endorse or promote |
21 +// | products derived from this software without specific prior written |
22 +// | permission. |
23 +// | |
24 +// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
25 +// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
26 +// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
27 +// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
28 +// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
29 +// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
30 +// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
31 +// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
32 +// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
33 +// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
34 +// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 +// | |
36 +// +-----------------------------------------------------------------------+
37 +// | Author: Richard Heyes <[email protected]> |
38 +// | Co-Author: Damian Fernandez Sosa <[email protected]> |
39 +// +-----------------------------------------------------------------------+
40 +//
41 +// $Id: POP3.php 295243 2010-02-18 22:05:20Z clockwerx $
42 +
43 +/**
44 + * +----------------------------- IMPORTANT ------------------------------+
45 + * | Usage of this class compared to native php extensions such as IMAP |
46 + * | is slow and may be feature deficient. If available you are STRONGLY |
47 + * | recommended to use the php extensions. |
48 + * +----------------------------------------------------------------------+
49 + *
50 + * POP3 Access Class
51 + *
52 + * For usage see the example script
53 + */
54 +
55 +define('NET_POP3_STATE_DISCONNECTED', 1);
56 +define('NET_POP3_STATE_AUTHORISATION', 2);
57 +define('NET_POP3_STATE_TRANSACTION', 4);
58 +
59 +class Pop3
60 +{
61 +
62 + /**
63 + * Some basic information about the mail drop
64 + * garnered from the STAT command
65 + *
66 + * @var array
67 + */
68 + var $_maildrop;
69 +
70 + /**
71 + * Used for APOP to store the timestamp
72 + *
73 + * @var string
74 + */
75 + var $_timestamp;
76 +
77 + /**
78 + * Timeout that is passed to the socket object
79 + *
80 + * @var integer
81 + */
82 + var $_timeout;
83 +
84 + /**
85 + * Socket object
86 + *
87 + * @var object
88 + */
89 + var $_socket;
90 +
91 + /**
92 + * Current state of the connection. Used with the
93 + * constants defined above.
94 + *
95 + * @var integer
96 + */
97 + var $_state;
98 +
99 + /**
100 + * Hostname to connect to
101 + *
102 + * @var string
103 + */
104 + var $_host;
105 +
106 + /**
107 + * Port to connect to
108 + *
109 + * @var integer
110 + */
111 + var $_port;
112 +
113 + /**
114 + * To allow class debuging
115 + * @var boolean
116 + */
117 + var $_debug = false;
118 +
119 +
120 + /**
121 + * The auth methods this class support
122 + * @var array
123 + */
124 + //var $supportedAuthMethods=array('DIGEST-MD5', 'CRAM-MD5', 'APOP' , 'PLAIN' , 'LOGIN', 'USER');
125 + //Disabling DIGEST-MD5 for now
126 + var $supportedAuthMethods = ['CRAM-MD5', 'APOP', 'PLAIN', 'LOGIN', 'USER'];
127 + //var $supportedAuthMethods=array( 'CRAM-MD5', 'PLAIN' , 'LOGIN');
128 + //var $supportedAuthMethods=array( 'PLAIN' , 'LOGIN');
129 +
130 +
131 + /**
132 + * The auth methods this class support
133 + * @var array
134 + */
135 + var $supportedSASLAuthMethods = ['DIGEST-MD5', 'CRAM-MD5'];
136 +
137 +
138 + /**
139 + * The capability response
140 + * @var array
141 + */
142 + var $_capability;
143 +
144 +
145 + /**
146 + * Constructor. Sets up the object variables, and instantiates
147 + * the socket object.
148 + *
149 + */
150 + function __construct()
151 + {
152 + $this->_timestamp = ''; // Used for APOP
153 + $this->_maildrop = [];
154 + $this->_timeout = 3;
155 + $this->_state = NET_POP3_STATE_DISCONNECTED;
156 + $this->_socket = new Socket();
157 + /*
158 + * Include the Auth_SASL package. If the package is not available,
159 + * we disable the authentication methods that depend upon it.
160 + */
161 + if (!class_exists('Auth_SASL')) {
162 + if ($this->_debug) {
163 + echo "AUTH_SASL NOT PRESENT!\n";
164 + }
165 + foreach ($this->supportedSASLAuthMethods as $SASLMethod) {
166 + $pos = array_search($SASLMethod, $this->supportedAuthMethods);
167 + if ($this->_debug) {
168 + echo "DISABLING METHOD $SASLMethod\n";
169 + }
170 + unset($this->supportedAuthMethods[$pos]);
171 + }
172 + }
173 + }
174 +
175 +
176 + /**
177 + * Handles the errors the class can find
178 + * on the server
179 + *
180 + * @access private
181 + * @return Error
182 + */
183 + function _raiseError($msg, $code = -1)
184 + {
185 + return Pear::raiseError($msg, $code);
186 + }
187 +
188 +
189 + /**
190 + * Connects to the given host on the given port.
191 + * Also looks for the timestamp in the greeting
192 + * needed for APOP authentication
193 + *
194 + * @param string $host Hostname/IP address to connect to
195 + * @param string $port Port to use to connect to on host
196 + *
197 + * @return bool Success/Failure
198 + */
199 + function connect($host = 'localhost', $port = 110)
200 + {
201 + $this->_host = $host;
202 + $this->_port = $port;
203 +
204 + $result = $this->_socket->connect($host, $port, false, $this->_timeout);
205 + if ($result === true) {
206 + $data = $this->_recvLn();
207 +
208 + if ($this->_checkResponse($data)) {
209 + // if the response begins with '+OK' ...
210 + // if (@substr(strtoupper($data), 0, 3) == '+OK') {
211 + // Check for string matching apop timestamp
212 + if (preg_match('/<.+@.+>/U', $data, $matches)) {
213 + $this->_timestamp = $matches[0];
214 + }
215 + $this->_maildrop = [];
216 + $this->_state = NET_POP3_STATE_AUTHORISATION;
217 +
218 + return true;
219 + }
220 + }
221 +
222 + $this->_socket->disconnect();
223 +
224 + return false;
225 + }
226 +
227 +
228 + /**
229 + * Disconnect function. Sends the QUIT command
230 + * and closes the socket.
231 + *
232 + * @return bool Success/Failure
233 + */
234 + function disconnect()
235 + {
236 + return $this->_cmdQuit();
237 + }
238 +
239 +
240 + /**
241 + * Performs the login procedure. If there is a timestamp
242 + * stored, APOP will be tried first, then basic USER/PASS.
243 + *
244 + * @param string $user Username to use
245 + * @param string $pass Password to use
246 + * @param mixed $apop Whether to try APOP first, if used as string you can select the auth methd to use ( $pop3->login('validlogin', 'validpass', "CRAM-MD5");
247 + * Valid methods are: 'DIGEST-MD5','CRAM-MD5','LOGIN','PLAIN','APOP','USER'
248 + *
249 + * @return mixed true on Success/ Error on error
250 + */
251 + function login($user, $pass, $apop = true)
252 + {
253 + if ($this->_state == NET_POP3_STATE_AUTHORISATION) {
254 +
255 + if (Pear::isError($ret = $this->_cmdAuthenticate($user, $pass, $apop))) {
256 + return $ret;
257 + }
258 + if (!Pear::isError($ret)) {
259 + $this->_state = NET_POP3_STATE_TRANSACTION;
260 +
261 + return true;
262 + }
263 + }
264 +
265 + return $this->_raiseError('Generic login error', 1);
266 + }
267 +
268 +
269 + /**
270 + * Parses the response from the capability command. Stores
271 + * the result in $this->_capability
272 + *
273 + * @access private
274 + */
275 + function _parseCapability()
276 + {
277 +
278 + if (!Pear::isError($data = $this->_sendCmd('CAPA'))) {
279 + $data = $this->_getMultiline();
280 + } else {
281 + // CAPA command not supported, reset data var
282 + // to avoid Notice errors of preg_split on an object
283 + $data = '';
284 + }
285 + $data = preg_split('/\r?\n/', $data, -1, PREG_SPLIT_NO_EMPTY);
286 +
287 + for ($i = 0 ; $i < count($data) ; $i++) {
288 +
289 + $capa = '';
290 + if (preg_match('/^([a-z,\-]+)( ((.*))|$)$/i', $data[$i], $matches)) {
291 +
292 + $capa = strtolower($matches[1]);
293 + switch ($capa) {
294 + case 'implementation':
295 + $this->_capability['implementation'] = $matches[3];
296 + break;
297 + case 'sasl':
298 + $this->_capability['sasl'] = preg_split('/\s+/', $matches[3]);
299 + break;
300 + default :
301 + $this->_capability[$capa] = $matches[2];
302 + break;
303 + }
304 + }
305 + }
306 + }
307 +
308 +
309 + /**
310 + * Returns the name of the best authentication method that the server
311 + * has advertised.
312 + *
313 + * @param string if !=null,authenticate with this method ($userMethod).
314 + *
315 + * @return mixed Returns a string containing the name of the best
316 + * supported authentication method or a Error object
317 + * if a failure condition is encountered.
318 + * @access private
319 + * @since 1.0
320 + */
321 + function _getBestAuthMethod($userMethod = null)
322 + {
323 + /*
324 + return 'USER';
325 + return 'APOP';
326 + return 'DIGEST-MD5';
327 + return 'CRAM-MD5';
328 + */
329 +
330 + $this->_parseCapability();
331 +
332 + //unset($this->_capability['sasl']);
333 +
334 + if (isset($this->_capability['sasl'])) {
335 + $serverMethods = $this->_capability['sasl'];
336 + } else {
337 + $serverMethods = ['USER'];
338 + // Check for timestamp before attempting APOP
339 + if ($this->_timestamp != null) {
340 + $serverMethods[] = 'APOP';
341 + }
342 + }
343 +
344 + if ($userMethod !== null && $userMethod !== true) {
345 + $methods = [];
346 + $methods[] = $userMethod;
347 +
348 + return $userMethod;
349 + } else {
350 + $methods = $this->supportedAuthMethods;
351 + }
352 +
353 + if (($methods != null) && ($serverMethods != null)) {
354 +
355 + foreach ($methods as $method) {
356 +
357 + if (in_array($method, $serverMethods)) {
358 + return $method;
359 + }
360 + }
361 + $serverMethods = implode(',', $serverMethods);
362 + $myMethods = implode(',', $this->supportedAuthMethods);
363 +
364 + return $this->_raiseError(
365 + "$method NOT supported authentication method!. This server ".
366 + "supports these methods: $serverMethods, but I support $myMethods"
367 + );
368 + } else {
369 + return $this->_raiseError("This server don't support any Auth methods");
370 + }
371 + }
372 +
373 +
374 + /**
375 + * Handles the authentication using any known method
376 + *
377 + * @param string The userid to authenticate as.
378 + * @param string The password to authenticate with.
379 + * @param string The method to use ( if $usermethod == '' then the class chooses the best method (the stronger is the best ) )
380 + *
381 + * @return mixed string or Error
382 + * @access private
383 + * @since 1.0
384 + */
385 + function _cmdAuthenticate($uid, $pwd, $userMethod = null)
386 + {
387 +
388 + if (Pear::isError($method = $this->_getBestAuthMethod($userMethod))) {
389 + return $method;
390 + }
391 +
392 + if (!in_array($userMethod, $this->supportedAuthMethods)) {
393 + return $this->_raiseError(
394 + 'Authentication method "'.$userMethod.'" is not supported.'
395 + );
396 + }
397 +
398 + switch ($method) {
399 + case 'DIGEST-MD5':
400 + $result = $this->_authDigest_MD5($uid, $pwd);
401 + break;
402 + case 'CRAM-MD5':
403 + $result = $this->_authCRAM_MD5($uid, $pwd);
404 + break;
405 + case 'LOGIN':
406 + $result = $this->_authLOGIN($uid, $pwd);
407 + break;
408 + case 'PLAIN':
409 + $result = $this->_authPLAIN($uid, $pwd);
410 + break;
411 + case 'APOP':
412 + $result = $this->_cmdApop($uid, $pwd);
413 + // if APOP fails fallback to USER auth
414 + if (Pear::isError($result)) {
415 + //echo "APOP FAILED!!!\n";
416 + $result = $this->_authUSER($uid, $pwd);
417 + }
418 + break;
419 + case 'USER':
420 + $result = $this->_authUSER($uid, $pwd);
421 + break;
422 +
423 +
424 + default :
425 + $result = $this->_raiseError("$method is not a supported authentication method");
426 + break;
427 + }
428 +
429 + return $result;
430 + }
431 +
432 +
433 + /**
434 + * Authenticates the user using the USER-PASS method.
435 + *
436 + * @param string The userid to authenticate as.
437 + * @param string The password to authenticate with.
438 + *
439 + * @return mixed true on success or Error on failure
440 + *
441 + * @access private
442 + * @since 1.0
443 + */
444 + function _authUSER($user, $pass)
445 + {
446 + if (Pear::isError($ret = $this->_cmdUser($user))) {
447 + return $ret;
448 + }
449 + if (Pear::isError($ret = $this->_cmdPass($pass))) {
450 + return $ret;
451 + }
452 +
453 + return true;
454 + }
455 +
456 +
457 + /**
458 + * Authenticates the user using the PLAIN method.
459 + *
460 + * @param string The userid to authenticate as.
461 + * @param string The password to authenticate with.
462 + *
463 + * @return array Returns an array containing the response
464 + *
465 + * @access private
466 + * @since 1.0
467 + */
468 + function _authPLAIN($user, $pass)
469 + {
470 + $cmd = sprintf('AUTH PLAIN %s', base64_encode(chr(0).$user.chr(0).$pass));
471 +
472 + if (Pear::isError($ret = $this->_send($cmd))) {
473 + return $ret;
474 + }
475 + if (Pear::isError($challenge = $this->_recvLn())) {
476 + return $challenge;
477 + }
478 + if (Pear::isError($ret = $this->_checkResponse($challenge))) {
479 + return $ret;
480 + }
481 +
482 + return true;
483 + }
484 +
485 +
486 + /**
487 + * Authenticates the user using the PLAIN method.
488 + *
489 + * @param string The userid to authenticate as.
490 + * @param string The password to authenticate with.
491 + *
492 + * @return array Returns an array containing the response
493 + *
494 + * @access private
495 + * @since 1.0
496 + */
497 + function _authLOGIN($user, $pass)
498 + {
499 + $this->_send('AUTH LOGIN');
500 +
501 + if (Pear::isError($challenge = $this->_recvLn())) {
502 + return $challenge;
503 + }
504 + if (Pear::isError($ret = $this->_checkResponse($challenge))) {
505 + return $ret;
506 + }
507 +
508 +
509 + if (Pear::isError($ret = $this->_send(sprintf('%s', base64_encode($user))))) {
510 + return $ret;
511 + }
512 +
513 + if (Pear::isError($challenge = $this->_recvLn())) {
514 + return $challenge;
515 + }
516 + if (Pear::isError($ret = $this->_checkResponse($challenge))) {
517 + return $ret;
518 + }
519 +
520 + if (Pear::isError($ret = $this->_send(sprintf('%s', base64_encode($pass))))) {
521 + return $ret;
522 + }
523 +
524 + if (Pear::isError($challenge = $this->_recvLn())) {
525 + return $challenge;
526 + }
527 +
528 + return $this->_checkResponse($challenge);
529 + }
530 +
531 +
532 + /**
533 + * Authenticates the user using the CRAM-MD5 method.
534 + *
535 + * @param string The userid to authenticate as.
536 + * @param string The password to authenticate with.
537 + *
538 + * @return array Returns an array containing the response
539 + *
540 + * @access private
541 + * @since 1.0
542 + */
543 + function _authCRAM_MD5($uid, $pwd)
544 + {
545 + if (Pear::isError($ret = $this->_send('AUTH CRAM-MD5'))) {
546 + return $ret;
547 + }
548 +
549 + if (Pear::isError($challenge = $this->_recvLn())) {
550 + return $challenge;
551 + }
552 + if (Pear::isError($ret = $this->_checkResponse($challenge))) {
553 + return $ret;
554 + }
555 +
556 + // remove '+ '
557 +
558 + $challenge = substr($challenge, 2);
559 +
560 + $challenge = base64_decode($challenge);
561 +
562 + $cram = &Auth_SASL::factory('crammd5');
563 + $auth_str = base64_encode($cram->getResponse($uid, $pwd, $challenge));
564 +
565 +
566 + if (Pear::isError($error = $this->_send($auth_str))) {
567 + return $error;
568 + }
569 + if (Pear::isError($ret = $this->_recvLn())) {
570 + return $ret;
571 + }
572 +
573 + //echo "RET:$ret\n";
574 + return $this->_checkResponse($ret);
575 + }
576 +
577 +
578 + /**
579 + * Authenticates the user using the DIGEST-MD5 method.
580 + *
581 + * @param string The userid to authenticate as.
582 + * @param string The password to authenticate with.
583 + * @param string The efective user
584 + *
585 + * @return array Returns an array containing the response
586 + *
587 + * @access private
588 + * @since 1.0
589 + */
590 + function _authDigest_MD5($uid, $pwd)
591 + {
592 + if (Pear::isError($ret = $this->_send('AUTH DIGEST-MD5'))) {
593 + return $ret;
594 + }
595 +
596 + if (Pear::isError($challenge = $this->_recvLn())) {
597 + return $challenge;
598 + }
599 + if (Pear::isError($ret = $this->_checkResponse($challenge))) {
600 + return $ret;
601 + }
602 +
603 + // remove '+ '
604 + $challenge = substr($challenge, 2);
605 +
606 + $challenge = base64_decode($challenge);
607 + $digest = &Auth_SASL::factory('digestmd5');
608 + $auth_str = base64_encode($digest->getResponse($uid, $pwd, $challenge, "localhost", "pop3"));
609 +
610 + if (Pear::isError($error = $this->_send($auth_str))) {
611 + return $error;
612 + }
613 +
614 + if (Pear::isError($challenge = $this->_recvLn())) {
615 + return $challenge;
616 + }
617 + if (Pear::isError($ret = $this->_checkResponse($challenge))) {
618 + return $ret;
619 + }
620 + /*
621 + * We don't use the protocol's third step because POP3 doesn't allow
622 + * subsequent authentication, so we just silently ignore it.
623 + */
624 +
625 + if (Pear::isError($challenge = $this->_send("\r\n"))) {
626 + return $challenge;
627 + }
628 +
629 + if (Pear::isError($challenge = $this->_recvLn())) {
630 + return $challenge;
631 + }
632 +
633 + return $this->_checkResponse($challenge);
634 + }
635 +
636 +
637 + /**
638 + * Sends the APOP command
639 + *
640 + * @param $user Username to send
641 + * @param $pass Password to send
642 + *
643 + * @return bool Success/Failure
644 + */
645 + function _cmdApop($user, $pass)
646 + {
647 + if ($this->_state == NET_POP3_STATE_AUTHORISATION) {
648 +
649 + if (!empty($this->_timestamp)) {
650 + if (Pear::isError($data = $this->_sendCmd('APOP '.$user.' '.md5($this->_timestamp.$pass)))) {
651 + return $data;
652 + }
653 + $this->_state = NET_POP3_STATE_TRANSACTION;
654 +
655 + return true;
656 + }
657 + }
658 +
659 + return $this->_raiseError('Not In NET_POP3_STATE_AUTHORISATION State1');
660 + }
661 +
662 +
663 + /**
664 + * Returns the raw headers of the specified message.
665 + *
666 + * @param integer $msg_id Message number
667 + *
668 + * @return mixed Either raw headers or false on error
669 + */
670 + function getRawHeaders($msg_id)
671 + {
672 + if ($this->_state == NET_POP3_STATE_TRANSACTION) {
673 + return $this->_cmdTop($msg_id, 0);
674 + }
675 +
676 + return false;
677 + }
678 +
679 + /**
680 + * Returns the headers of the specified message in an
681 + * associative array. Array keys are the header names, array
682 + * values are the header values. In the case of multiple headers
683 + * having the same names, eg Received:, the array value will be
684 + * an indexed array of all the header values.
685 + *
686 + * @param integer $msg_id Message number
687 + *
688 + * @return mixed Either array of headers or false on error
689 + */
690 + function getParsedHeaders($msg_id)
691 + {
692 + if ($this->_state == NET_POP3_STATE_TRANSACTION) {
693 +
694 + $raw_headers = rtrim($this->getRawHeaders($msg_id));
695 +
696 + $raw_headers = preg_replace("/\r\n[ \t]+/", ' ', $raw_headers); // Unfold headers
697 + $raw_headers = explode("\r\n", $raw_headers);
698 + foreach ($raw_headers as $value) {
699 + $name = substr($value, 0, $pos = strpos($value, ':'));
700 + $value = ltrim(substr($value, $pos + 1));
701 + if (isset($headers[$name]) and is_array($headers[$name])) {
702 + $headers[$name][] = $value;
703 + } elseif (isset($headers[$name])) {
704 + $headers[$name] = [$headers[$name], $value];
705 + } else {
706 + $headers[$name] = $value;
707 + }
708 + }
709 +
710 + return $headers;
711 + }
712 +
713 + return false;
714 + }
715 +
716 + /**
717 + * Returns the body of the message with given message number.
718 + *
719 + * @param integer $msg_id Message number
720 + *
721 + * @return mixed Either message body or false on error
722 + */
723 + function getBody($msg_id)
724 + {
725 + if ($this->_state == NET_POP3_STATE_TRANSACTION) {
726 + $msg = $this->_cmdRetr($msg_id);
727 +
728 + return substr($msg, strpos($msg, "\r\n\r\n") + 4);
729 + }
730 +
731 + return false;
732 + }
733 +
734 + /**
735 + * Returns the entire message with given message number.
736 + *
737 + * @param integer $msg_id Message number
738 + *
739 + * @return mixed Either entire message or false on error
740 + */
741 + function getMsg($msg_id)
742 + {
743 + if ($this->_state == NET_POP3_STATE_TRANSACTION) {
744 + return $this->_cmdRetr($msg_id);
745 + }
746 +
747 + return false;
748 + }
749 +
750 + /**
751 + * Returns the size of the maildrop
752 + *
753 + * @return mixed Either size of maildrop or false on error
754 + */
755 + function getSize()
756 + {
757 + if ($this->_state == NET_POP3_STATE_TRANSACTION) {
758 + if (isset($this->_maildrop['size'])) {
759 + return $this->_maildrop['size'];
760 + } else {
761 + [, $size] = $this->_cmdStat();
762 +
763 + return $size;
764 + }
765 + }
766 +
767 + return false;
768 + }
769 +
770 + /**
771 + * Returns number of messages in this maildrop
772 + *
773 + * @return mixed Either number of messages or false on error
774 + */
775 + function numMsg()
776 + {
777 + if ($this->_state == NET_POP3_STATE_TRANSACTION) {
778 + if (isset($this->_maildrop['num_msg'])) {
779 + return $this->_maildrop['num_msg'];
780 + } else {
781 + [$num_msg,] = $this->_cmdStat();
782 +
783 + return $num_msg;
784 + }
785 + }
786 +
787 + return false;
788 + }
789 +
790 + /**
791 + * Marks a message for deletion. Only will be deleted if the
792 + * disconnect() method is called.
793 + *
794 + * @param integer $msg_id Message to delete
795 + *
796 + * @return bool Success/Failure
797 + */
798 + function deleteMsg($msg_id)
799 + {
800 + if ($this->_state == NET_POP3_STATE_TRANSACTION) {
801 + return $this->_cmdDele($msg_id);
802 + }
803 +
804 + return false;
805 + }
806 +
807 + /**
808 + * Combination of LIST/UIDL commands, returns an array
809 + * of data
810 + *
811 + * @param integer $msg_id Optional message number
812 + *
813 + * @return mixed Array of data or false on error
814 + */
815 + function getListing($msg_id = null)
816 + {
817 +
818 + if ($this->_state == NET_POP3_STATE_TRANSACTION) {
819 + if (!isset($msg_id)) {
820 +
821 + $list = [];
822 + if ($list = $this->_cmdList()) {
823 + if ($uidl = $this->_cmdUidl()) {
824 + foreach ($uidl as $i => $value) {
825 + $list[$i]['uidl'] = $value['uidl'];
826 + }
827 + }
828 +
829 + return $list;
830 + } else {
831 + return [];
832 + }
833 + } else {
834 + if ($list = $this->_cmdList($msg_id) and $uidl = $this->_cmdUidl($msg_id)) {
835 + return array_merge($list, $uidl);
836 + }
837 + }
838 + }
839 +
840 + return false;
841 + }
842 +
843 +
844 + /**
845 + * Sends the USER command
846 + *
847 + * @param string $user Username to send
848 + *
849 + * @return bool Success/Failure
850 + */
851 + function _cmdUser($user)
852 + {
853 + if ($this->_state == NET_POP3_STATE_AUTHORISATION) {
854 + return $this->_sendCmd('USER '.$user);
855 + }
856 +
857 + return $this->_raiseError('Not In NET_POP3_STATE_AUTHORISATION State');
858 + }
859 +
860 +
861 + /**
862 + * Sends the PASS command
863 + *
864 + * @param string $pass Password to send
865 + *
866 + * @return bool Success/Failure
867 + */
868 + function _cmdPass($pass)
869 + {
870 + if ($this->_state == NET_POP3_STATE_AUTHORISATION) {
871 + return $this->_sendCmd('PASS '.$pass);
872 + }
873 +
874 + return $this->_raiseError('Not In NET_POP3_STATE_AUTHORISATION State');
875 + }
876 +
877 +
878 + /**
879 + * Sends the STAT command
880 + *
881 + * @return mixed Indexed array of number of messages and
882 + * maildrop size, or false on error.
883 + */
884 + function _cmdStat()
885 + {
886 + if ($this->_state == NET_POP3_STATE_TRANSACTION) {
887 + if (!Pear::isError($data = $this->_sendCmd('STAT'))) {
888 + sscanf($data, '+OK %d %d', $msg_num, $size);
889 + $this->_maildrop['num_msg'] = $msg_num;
890 + $this->_maildrop['size'] = $size;
891 +
892 + return [$msg_num, $size];
893 + }
894 + }
895 +
896 + return false;
897 + }
898 +
899 +
900 + /**
901 + * Sends the LIST command
902 + *
903 + * @param integer $msg_id Optional message number
904 + *
905 + * @return mixed Indexed array of msg_id/msg size or
906 + * false on error
907 + */
908 + function _cmdList($msg_id = null)
909 + {
910 + $return = [];
911 + if ($this->_state == NET_POP3_STATE_TRANSACTION) {
912 + if (!isset($msg_id)) {
913 + if (!Pear::isError($data = $this->_sendCmd('LIST'))) {
914 + $data = $this->_getMultiline();
915 + $data = explode("\r\n", $data);
916 + foreach ($data as $line) {
917 + if ($line != '') {
918 + sscanf($line, '%s %s', $msg_id, $size);
919 + $return[] = ['msg_id' => $msg_id, 'size' => $size];
920 + }
921 + }
922 +
923 + return $return;
924 + }
925 + } else {
926 + if (!Pear::isError($data = $this->_sendCmd('LIST '.$msg_id))) {
927 + if ($data != '') {
928 + sscanf($data, '+OK %d %d', $msg_id, $size);
929 +
930 + return ['msg_id' => $msg_id, 'size' => $size];
931 + }
932 +
933 + return [];
934 + }
935 + }
936 + }
937 +
938 +
939 + return false;
940 + }
941 +
942 +
943 + /**
944 + * Sends the RETR command
945 + *
946 + * @param integer $msg_id The message number to retrieve
947 + *
948 + * @return mixed The message or false on error
949 + */
950 + function _cmdRetr($msg_id)
951 + {
952 + if ($this->_state == NET_POP3_STATE_TRANSACTION) {
953 + if (!Pear::isError($data = $this->_sendCmd('RETR '.$msg_id))) {
954 + $data = $this->_getMultiline();
955 +
956 + return $data;
957 + }
958 + }
959 +
960 + return false;
961 + }
962 +
963 +
964 + /**
965 + * Sends the DELE command
966 + *
967 + * @param integer $msg_id Message number to mark as deleted
968 + *
969 + * @return bool Success/Failure
970 + */
971 + function _cmdDele($msg_id)
972 + {
973 + if ($this->_state == NET_POP3_STATE_TRANSACTION) {
974 + return $this->_sendCmd('DELE '.$msg_id);
975 + }
976 +
977 + return false;
978 + }
979 +
980 +
981 + /**
982 + * Sends the NOOP command
983 + *
984 + * @return bool Success/Failure
985 + */
986 + function _cmdNoop()
987 + {
988 + if ($this->_state == NET_POP3_STATE_TRANSACTION) {
989 + if (!Pear::isError($data = $this->_sendCmd('NOOP'))) {
990 + return true;
991 + }
992 + }
993 +
994 + return false;
995 + }
996 +
997 +
998 + /**
999 + * Sends the RSET command
1000 + *
1001 + * @return bool Success/Failure
1002 + */
1003 + function _cmdRset()
1004 + {
1005 + if ($this->_state == NET_POP3_STATE_TRANSACTION) {
1006 + if (!Pear::isError($data = $this->_sendCmd('RSET'))) {
1007 + return true;
1008 + }
1009 + }
1010 +
1011 + return false;
1012 + }
1013 +
1014 +
1015 + /**
1016 + * Sends the QUIT command
1017 + *
1018 + * @return bool Success/Failure
1019 + */
1020 + function _cmdQuit()
1021 + {
1022 + $data = $this->_sendCmd('QUIT');
1023 + $this->_state = NET_POP3_STATE_DISCONNECTED;
1024 + $this->_socket->disconnect();
1025 +
1026 + return (bool)$data;
1027 + }
1028 +
1029 +
1030 + /**
1031 + * Sends the TOP command
1032 + *
1033 + * @param integer $msg_id Message number
1034 + * @param integer $num_lines Number of lines to retrieve
1035 + *
1036 + * @return mixed Message data or false on error
1037 + */
1038 + function _cmdTop($msg_id, $num_lines)
1039 + {
1040 + if ($this->_state == NET_POP3_STATE_TRANSACTION) {
1041 +
1042 + if (!Pear::isError($data = $this->_sendCmd('TOP '.$msg_id.' '.$num_lines))) {
1043 + return $this->_getMultiline();
1044 + }
1045 + }
1046 +
1047 + return false;
1048 + }
1049 +
1050 +
1051 + /**
1052 + * Sends the UIDL command
1053 + *
1054 + * @param integer $msg_id Message number
1055 + *
1056 + * @return mixed indexed array of msg_id/uidl or false on error
1057 + */
1058 + function _cmdUidl($msg_id = null)
1059 + {
1060 + if ($this->_state == NET_POP3_STATE_TRANSACTION) {
1061 +
1062 + if (!isset($msg_id)) {
1063 + if (!Pear::isError($data = $this->_sendCmd('UIDL'))) {
1064 + $data = $this->_getMultiline();
1065 + $data = explode("\r\n", $data);
1066 + foreach ($data as $line) {
1067 + sscanf($line, '%d %s', $msg_id, $uidl);
1068 + $return[] = ['msg_id' => $msg_id, 'uidl' => $uidl];
1069 + }
1070 +
1071 + return $return;
1072 + }
1073 + } else {
1074 +
1075 + $data = $this->_sendCmd('UIDL '.$msg_id);
1076 + sscanf($data, '+OK %d %s', $msg_id, $uidl);
1077 +
1078 + return ['msg_id' => $msg_id, 'uidl' => $uidl];
1079 + }
1080 + }
1081 +
1082 + return false;
1083 + }
1084 +
1085 +
1086 + /**
1087 + * Sends a command, checks the reponse, and
1088 + * if good returns the reponse, other wise
1089 + * returns false.
1090 + *
1091 + * @param string $cmd Command to send (\r\n will be appended)
1092 + *
1093 + * @return mixed First line of response if successful, otherwise false
1094 + */
1095 + function _sendCmd($cmd)
1096 + {
1097 + if (Pear::isError($result = $this->_send($cmd))) {
1098 + return $result;
1099 + }
1100 +
1101 + if (Pear::isError($data = $this->_recvLn())) {
1102 + return $data;
1103 + }
1104 +
1105 + if (strtoupper(substr($data, 0, 3)) == '+OK') {
1106 + return $data;
1107 + }
1108 +
1109 +
1110 + return $this->_raiseError($data);
1111 + }
1112 +
1113 +
1114 + /**
1115 + * Reads a multiline reponse and returns the data
1116 + *
1117 + * @return string The reponse.
1118 + */
1119 + function _getMultiline()
1120 + {
1121 + $data = '';
1122 + while (!Pear::isError($tmp = $this->_recvLn())) {
1123 + if ($tmp == '.' || $tmp == "\n.") {
1124 + return substr($data, 0, -2);
1125 + }
1126 + if (substr($tmp, 0, 2) == '..') {
1127 + $tmp = substr($tmp, 1);
1128 + }
1129 + $data .= $tmp."\r\n";
1130 + }
1131 +
1132 + return substr($data, 0, -2);
1133 + }
1134 +
1135 +
1136 + /**
1137 + * Sets the bebug state
1138 + *
1139 + * @param bool $debug
1140 + *
1141 + * @access public
1142 + * @return void
1143 + */
1144 + function setDebug($debug = true)
1145 + {
1146 + $this->_debug = $debug;
1147 + }
1148 +
1149 +
1150 + /**
1151 + * Send the given string of data to the server.
1152 + *
1153 + * @param string $data The string of data to send.
1154 + *
1155 + * @return mixed True on success or a Error object on failure.
1156 + *
1157 + * @access private
1158 + * @since 1.0
1159 + */
1160 + function _send($data)
1161 + {
1162 + if ($this->_debug) {
1163 + echo "C: $data\n";
1164 + }
1165 +
1166 + if (Pear::isError($error = $this->_socket->writeLine($data))) {
1167 + return $this->_raiseError('Failed to write to socket: '.$error->getMessage());
1168 + }
1169 +
1170 + return true;
1171 + }
1172 +
1173 +
1174 + /**
1175 + * Receive the given string of data from the server.
1176 + *
1177 + * @return mixed a line of response on success or a Error object on failure.
1178 + *
1179 + * @access private
1180 + * @since 1.0
1181 + */
1182 + function _recvLn()
1183 + {
1184 + if (Pear::isError($lastline = $this->_socket->readLine(8192))) {
1185 + return $this->_raiseError('Failed to read from socket: '.$this->lastline->getMessage());
1186 + }
1187 + if ($this->_debug) {
1188 + // S: means this data was sent by the POP3 Server
1189 + echo "S:$lastline\n";
1190 + }
1191 +
1192 + return $lastline;
1193 + }
1194 +
1195 +
1196 + /**
1197 + * Checks de server Response
1198 + *
1199 + * @param string $response the response
1200 + *
1201 + * @return mixed true on success or a Error object on failure.
1202 + *
1203 + * @access private
1204 + * @since 1.3.3
1205 + */
1206 + function _checkResponse($response)
1207 + {
1208 + if (@substr(strtoupper($response), 0, 3) == '+OK') {
1209 + return true;
1210 + } else {
1211 + if (@substr(strtoupper($response), 0, 4) == '-ERR') {
1212 + return $this->_raiseError($response);
1213 + } else {
1214 + if (@substr(strtoupper($response), 0, 2) == '+ ') {
1215 + return true;
1216 + }
1217 + }
1218 + }
1219 +
1220 + return $this->_raiseError("Unknown Response ($response)");
1221 + }
1222 +
1223 +}
1224 +
1225 +?>