1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62:
63: class Horde_Imap_Client_Socket_Pop3 extends Horde_Imap_Client_Base
64: {
65: 66: 67: 68: 69:
70: protected $_deleted = array();
71:
72: 73: 74: 75: 76:
77: protected $_fetchDataClass = 'Horde_Imap_Client_Data_Fetch_Pop3';
78:
79: 80: 81: 82: 83:
84: protected $_stream = null;
85:
86: 87:
88: protected $_utilsClass = 'Horde_Imap_Client_Utils_Pop3';
89:
90: 91:
92: public function __construct(array $params = array())
93: {
94: if (empty($params['port'])) {
95: $params['port'] = (isset($params['secure']) && ($params['secure'] == 'ssl'))
96: ? 995
97: : 110;
98: }
99:
100: parent::__construct($params);
101: }
102:
103: 104:
105: protected function _initCache($current = false)
106: {
107: return parent::_initCache($current) &&
108: $this->queryCapability('UIDL');
109: }
110:
111: 112:
113: public function getIdsOb($ids = null, $sequence = false)
114: {
115: return new Horde_Imap_Client_Ids_Pop3($ids, $sequence);
116: }
117:
118: 119:
120: protected function _capability()
121: {
122: $this->_connect();
123:
124: $capability = array();
125:
126: try {
127: $this->_sendLine('CAPA');
128:
129: foreach ($this->_getMultiline(true) as $val) {
130: $prefix = explode(' ', $val);
131:
132: $capability[strtoupper($prefix[0])] = (count($prefix) > 1)
133: ? array_slice($prefix, 1)
134: : true;
135: }
136: } catch (Horde_Imap_Client_Exception $e) {
137: 138:
139: $capability = array('USER', 'SASL');
140:
141: try {
142: $this->_sendLine('UIDL');
143: fclose($this->_getMultiline());
144: $capability[] = 'UIDL';
145: } catch (Horde_Imap_Client_Exception $e) {}
146:
147: try {
148: $this->_sendLine('TOP 1 0');
149: fclose($this->_getMultiline());
150: $capability[] = 'TOP';
151: } catch (Horde_Imap_Client_Exception $e) {}
152: }
153:
154: $this->_setInit('capability', $capability);
155:
156: return $this->_init['capability'];
157: }
158:
159: 160:
161: protected function _noop()
162: {
163: $this->_sendLine('NOOP');
164: }
165:
166: 167:
168: protected function _getNamespaces()
169: {
170: $this->_exception('IMAP namespaces not supported on POP3 servers.', 'NO_SUPPORT');
171: }
172:
173: 174:
175: public function alerts()
176: {
177: return array();
178: }
179:
180: 181:
182: protected function _login()
183: {
184: $this->_connect();
185:
186:
187: if (!$this->_isSecure &&
188: ($this->_params['secure'] == 'tls')) {
189:
190: if (!$this->queryCapability('STLS')) {
191: $this->_exception(Horde_Imap_Client_Translation::t("Could not open secure connection to the POP3 server.") . ' ' . Horde_Imap_Client_Translation::t("Server does not support secure connections."), 'LOGIN_TLSFAILURE');
192: }
193:
194: $this->_sendLine('STLS');
195:
196: $res = @stream_socket_enable_crypto($this->_stream, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
197:
198: if (!$res) {
199: $this->logout();
200: $this->_exception(Horde_Imap_Client_Translation::t("Could not open secure connection to the POP3 server."), 'LOGIN_TLSFAILURE');
201: }
202:
203:
204: $this->_setInit('capability');
205:
206: $this->_isSecure = true;
207: }
208:
209: if (empty($this->_init['authmethod'])) {
210: $auth_mech = ($sasl = $this->queryCapability('SASL'))
211: ? $sasl
212: : array();
213:
214: if (isset($this->_temp['pop3timestamp'])) {
215: $auth_mech[] = 'APOP';
216: }
217:
218: $auth_mech[] = 'USER';
219: } else {
220: $auth_mech = array($this->_init['authmethod']);
221: }
222:
223: foreach ($auth_mech as $method) {
224: try {
225: $this->_tryLogin($method);
226: $this->_setInit('authmethod', $method);
227: return true;
228: } catch (Horde_Imap_Client_Exception $e) {
229: if (!empty($this->_init['authmethod'])) {
230: $this->_setInit();
231: return $this->login();
232: }
233: }
234: }
235:
236: $this->_exception(Horde_Imap_Client_Translation::t("POP3 server denied authentication."), $e->getCode() ? $e->getCode() : 'LOGIN_AUTHENTICATIONFAILED');
237: }
238:
239: 240: 241: 242: 243:
244: protected function _connect()
245: {
246: if (!is_null($this->_stream)) {
247: return;
248: }
249:
250: if (!empty($this->_params['secure']) && !extension_loaded('openssl')) {
251: new InvalidArgumentException('Secure connections require the PHP openssl extension.');
252: }
253:
254: switch ($this->_params['secure']) {
255: case 'ssl':
256: case 'sslv2':
257: case 'sslv3':
258: $conn = $this->_params['secure'] . '://';
259: $this->_isSecure = true;
260: break;
261:
262: case 'tls':
263: default:
264: $conn = 'tcp://';
265: break;
266: }
267:
268: $this->_stream = @stream_socket_client($conn . $this->_params['hostspec'] . ':' . $this->_params['port'], $error_number, $error_string, $this->_params['timeout']);
269:
270: if ($this->_stream === false) {
271: $this->_stream = null;
272: $this->_isSecure = false;
273: $this->_exception(array(
274: Horde_Imap_Client_Translation::t("Error connecting to POP3 server."),
275: sprintf("[%u] %s.", $error_number, $error_string)
276: ), 'SERVER_CONNECT');
277: }
278:
279: stream_set_timeout($this->_stream, $this->_params['timeout']);
280:
281: $line = $this->_getLine();
282:
283:
284: if (preg_match('/<.+@.+>/U', $line['line'], $matches)) {
285: $this->_temp['pop3timestamp'] = $matches[0];
286: }
287: }
288:
289: 290: 291: 292: 293: 294: 295:
296: protected function _tryLogin($method)
297: {
298: switch ($method) {
299: case 'CRAM-MD5':
300: case 'CRAM-SHA1':
301: case 'CRAM-SHA256':
302:
303:
304: $challenge = $this->_sendLine('AUTH ' . $method);
305: $response = base64_encode($this->_params['username'] . ' ' . hash_hmac(strtolower(substr($method, 5)), base64_decode(substr($challenge['line'], 2)), $this->getParam('password'), true));
306: $this->_sendLine($response, array(
307: 'debug' => '[' . $method . ' Response]'
308: ));
309: break;
310:
311: case 'DIGEST-MD5':
312:
313: $challenge = $this->_sendLine('AUTH DIGEST-MD5');
314: $response = base64_encode(new Horde_Imap_Client_Auth_DigestMD5(
315: $this->_params['username'],
316: $this->getParam('password'),
317: base64_decode(substr($challenge['line'], 2)),
318: $this->_params['hostspec'],
319: 'pop3'
320: ));
321: $sresponse = $this->_sendLine($response, array(
322: 'debug' => '[DIGEST-MD5 Response]'
323: ));
324: if (stripos(base64_decode(substr($sresponse['line'], 2)), 'rspauth=') === false) {
325: $this->_exception(Horde_Imap_Client_Translation::t("Unexpected response from server when authenticating."), 'SERVER_CONNECT');
326: }
327:
328:
329: $this->_sendLine('');
330: break;
331:
332: case 'LOGIN':
333:
334: $this->_sendLine('AUTH LOGIN');
335: $this->_sendLine(base64_encode($this->_params['username']));
336: $this->_sendLine(base64_encode($this->getParam('password')), array(
337: 'debug' => '[AUTH LOGIN Command - password]'
338: ));
339: break;
340:
341: case 'PLAIN':
342:
343: $this->_sendLine('AUTH PLAIN ' . base64_encode(chr(0) . $this->_params['username'] . chr(0) . $this->getParam('password')), array(
344: 'debug' => sprintf('[AUTH PLAIN Command - username: %s]', $this->_params['username'])
345: ));
346: break;
347:
348: case 'APOP':
349:
350: $this->_sendLine('APOP ' . $this->_params['username'] . ' ' . hash('md5', $this->_temp['pop3timestamp'] . $this->_params['password']));
351: break;
352:
353: case 'USER':
354:
355: $this->_sendLine('USER ' . $this->_params['username']);
356: $this->_sendLine('PASS ' . $this->getParam('password'), array(
357: 'debug' => '[USER Command - password]'
358: ));
359: break;
360:
361: default:
362: $this->_exception(sprintf(Horde_Imap_Client_Translation::t("Unknown authentication method: %s"), $method), 'SERVER_CONNECT');
363: }
364: }
365:
366: 367:
368: protected function _logout()
369: {
370: if (!is_null($this->_stream)) {
371: try {
372: $this->_sendLine('QUIT');
373: } catch (Horde_Imap_Client_Exception $e) {}
374: fclose($this->_stream);
375: $this->_stream = null;
376: $this->_deleted = array();
377: }
378: }
379:
380: 381:
382: protected function _sendID($info)
383: {
384: $this->_exception('IMAP ID command not supported on POP3 servers.', 'NO_SUPPORT');
385: }
386:
387: 388: 389:
390: protected function _getID()
391: {
392: $id = $this->queryCapability('IMPLEMENTATION');
393: return empty($id)
394: ? array()
395: : array('implementation' => $id);
396: }
397:
398: 399:
400: protected function _setLanguage($langs)
401: {
402: $this->_exception('IMAP LANGUAGE extension not supported on POP3 servers.', 'NO_SUPPORT');
403: }
404:
405: 406:
407: protected function _getLanguage($list)
408: {
409: $this->_exception('IMAP LANGUAGE extension not supported on POP3 servers.', 'NO_SUPPORT');
410: }
411:
412: 413:
414: protected function _openMailbox(Horde_Imap_Client_Mailbox $mailbox, $mode)
415: {
416: if (strcasecmp($mailbox, 'INBOX') !== 0) {
417: $this->_exception('Mailboxes other than INBOX not supported on POP3 servers.', 'NO_SUPPORT');
418: }
419: }
420:
421: 422:
423: protected function _createMailbox(Horde_Imap_Client_Mailbox $mailbox, $opts)
424: {
425: $this->_exception('Creating mailboxes not supported on POP3 servers.', 'NO_SUPPORT');
426: }
427:
428: 429:
430: protected function _deleteMailbox(Horde_Imap_Client_Mailbox $mailbox)
431: {
432: $this->_exception('Deleting mailboxes not supported on POP3 servers.', 'NO_SUPPORT');
433: }
434:
435: 436:
437: protected function _renameMailbox(Horde_Imap_Client_Mailbox $old,
438: Horde_Imap_Client_Mailbox $new)
439: {
440: $this->_exception('Renaming mailboxes not supported on POP3 servers.', 'NO_SUPPORT');
441: }
442:
443: 444:
445: protected function _subscribeMailbox(Horde_Imap_Client_Mailbox $mailbox,
446: $subscribe)
447: {
448: $this->_exception('Mailboxes other than INBOX not supported on POP3 servers.', 'NO_SUPPORT');
449: }
450:
451: 452:
453: protected function _listMailboxes($pattern, $mode, $options)
454: {
455: $tmp = array(
456: 'mailbox' => Horde_Imap_Client_Mailbox::get('INBOX')
457: );
458:
459: if (!empty($options['attributes'])) {
460: $tmp['attributes'] = array();
461: }
462: if (!empty($options['delimiter'])) {
463: $tmp['delimiter'] = '';
464: }
465:
466: return array('INBOX' => $tmp);
467: }
468:
469: 470: 471: 472:
473: protected function _status(Horde_Imap_Client_Mailbox $mailbox, $flags)
474: {
475: $this->openMailbox($mailbox);
476:
477:
478: if (($flags & Horde_Imap_Client::STATUS_FIRSTUNSEEN) ||
479: ($flags & Horde_Imap_Client::STATUS_FLAGS) ||
480: ($flags & Horde_Imap_Client::STATUS_PERMFLAGS) ||
481: ($flags & Horde_Imap_Client::STATUS_HIGHESTMODSEQ) ||
482: ($flags & Horde_Imap_Client::STATUS_UIDNOTSTICKY)) {
483: $this->_exception('Improper status request on POP3 server.', 'NO_SUPPORT');
484: }
485:
486: $ret = array();
487:
488: if ($flags & Horde_Imap_Client::STATUS_MESSAGES) {
489: $res = $this->_pop3Cache('stat');
490: $ret['messages'] = $res['msgs'];
491: }
492:
493: if ($flags & Horde_Imap_Client::STATUS_RECENT) {
494: $res = $this->_pop3Cache('stat');
495: $ret['recent'] = $res['msgs'];
496: }
497:
498: if ($flags & Horde_Imap_Client::STATUS_UIDNEXT) {
499: $res = $this->_pop3Cache('stat');
500: $ret['uidnext'] = $res['msgs'] + 1;
501: }
502:
503: if ($flags & Horde_Imap_Client::STATUS_UIDVALIDITY) {
504: $ret['uidvalidity'] = $this->queryCapability('UIDL')
505: ? 1
506: : microtime(true);
507: }
508:
509: if ($flags & Horde_Imap_Client::STATUS_UNSEEN) {
510: $ret['unseen'] = 0;
511: }
512:
513: return $ret;
514: }
515:
516: 517:
518: protected function _append(Horde_Imap_Client_Mailbox $mailbox, $data,
519: $options)
520: {
521: $this->_exception('Appending messages not supported on POP3 servers.', 'NO_SUPPORT');
522: }
523:
524: 525:
526: protected function _check()
527: {
528: $this->noop();
529: }
530:
531: 532:
533: protected function _close($options)
534: {
535: if (!empty($options['expunge'])) {
536: $this->logout();
537: }
538: }
539:
540: 541: 542: 543:
544: protected function _expunge($options)
545: {
546: $msg_list = $this->_deleted;
547: $this->logout();
548: return empty($options['list'])
549: ? null
550: : $msg_list;
551: }
552:
553: 554:
555: protected function _search($query, $options)
556: {
557: $sort = empty($options['sort'])
558: ? null
559: : reset($options['sort']);
560:
561:
562: if ((reset($options['_query']['query']) != 'ALL') ||
563: ($sort &&
564: ((count($options['sort']) > 1) ||
565: ($sort != Horde_Imap_Client::SORT_SEQUENCE)))) {
566: $this->_exception('Server search not supported on POP3 server.', 'NO_SUPPORT');
567: }
568:
569: $status = $this->status($this->_selected, Horde_Imap_Client::STATUS_MESSAGES);
570: $res = range(1, $status['messages']);
571:
572: if (empty($options['sequence'])) {
573: $tmp = array();
574: $uidllist = $this->_pop3Cache('uidl');
575: foreach ($res as $val) {
576: $tmp[] = $uidllist[$val];
577: }
578: $res = $tmp;
579: }
580:
581: $ret = array();
582: foreach ($options['results'] as $val) {
583: switch ($val) {
584: case Horde_Imap_Client::SEARCH_RESULTS_COUNT:
585: $ret['count'] = count($res);
586: break;
587:
588: case Horde_Imap_Client::SEARCH_RESULTS_MATCH:
589: $ret['match'] = $this->getIdsOb($res);
590: break;
591:
592: case Horde_Imap_Client::SEARCH_RESULTS_MAX:
593: $ret['max'] = empty($res) ? null : max($res);
594: break;
595:
596: case Horde_Imap_Client::SEARCH_RESULTS_MIN:
597: $ret['min'] = empty($res) ? null : min($res);
598: break;
599: }
600: }
601:
602: return $ret;
603: }
604:
605: 606:
607: protected function _setComparator($comparator)
608: {
609: $this->_exception('Search comparators not supported on POP3 server.', 'NO_SUPPORT');
610: }
611:
612: 613:
614: protected function _getComparator()
615: {
616: $this->_exception('Search comparators not supported on POP3 server.', 'NO_SUPPORT');
617: }
618:
619: 620:
621: protected function _thread($options)
622: {
623: $this->_exception('Server threading not supported on POP3 server.', 'NO_SUPPORT');
624: }
625:
626: 627:
628: protected function _fetch($query, $results, $options)
629: {
630:
631: if (!empty($options['changedsince']) ||
632: !empty($options['vanished'])) {
633: $this->_exception('Fetch options not supported on POP3 server.', 'NO_SUPPORT');
634: }
635:
636:
637:
638: $seq_ids = $this->_getSeqIds($options['ids']);
639: if (empty($seq_ids)) {
640: return $results;
641: }
642:
643: $lookup = $options['ids']->sequence
644: ? array_combine($seq_ids, $seq_ids)
645: : $this->_pop3Cache('uidl');
646:
647: foreach ($query as $type => $c_val) {
648: switch ($type) {
649: case Horde_Imap_Client::FETCH_FULLMSG:
650: foreach ($seq_ids as $id) {
651: $tmp = $this->_pop3Cache('msg', $id);
652:
653: if (empty($c_val['start']) && empty($c_val['length'])) {
654: $tmp2 = fopen('php://temp', 'r+');
655: stream_copy_to_stream($tmp, $tmp2, empty($c_val['length']) ? -1 : $c_val['length'], empty($c_val['start']) ? 0 : $c_val['start']);
656: $results[$lookup[$id]]->setFullMsg($tmp2);
657: } else {
658: $results[$lookup[$id]]->setFullMsg($tmp);
659: }
660: }
661: break;
662:
663: case Horde_Imap_Client::FETCH_HEADERTEXT:
664:
665: foreach ($c_val as $key => $val) {
666: foreach ($seq_ids as $id) {
667: 668:
669: try {
670: $tmp = ($key == 0)
671: ? $this->_pop3Cache('hdr', $id)
672: : Horde_Mime_Part::getRawPartText(stream_get_contents($this->_pop3Cache('msg', $id)), 'header', $key);
673: $results[$lookup[$id]]->setHeaderText($key, $this->_processString($tmp, $c_val));
674: } catch (Horde_Mime_Exception $e) {}
675: }
676: }
677: break;
678:
679: case Horde_Imap_Client::FETCH_BODYTEXT:
680:
681: foreach ($c_val as $key => $val) {
682: foreach ($seq_ids as $id) {
683: try {
684: $results[$lookup[$id]]->setBodyText($key, $this->_processString(Horde_Mime_Part::getRawPartText(stream_get_contents($this->_pop3Cache('msg', $id)), 'body', $key), $val));
685: } catch (Horde_Mime_Exception $e) {}
686: }
687: }
688: break;
689:
690: case Horde_Imap_Client::FETCH_MIMEHEADER:
691:
692: foreach ($c_val as $key => $val) {
693: foreach ($seq_ids as $id) {
694: try {
695: $results[$lookup[$id]]->setMimeHeader($key, $this->_processString(Horde_Mime_Part::getRawPartText(stream_get_contents($this->_pop3Cache('msg', $id)), 'header', $key), $val));
696: } catch (Horde_Mime_Exception $e) {}
697: }
698: }
699: break;
700:
701: case Horde_Imap_Client::FETCH_BODYPART:
702:
703: foreach ($c_val as $key => $val) {
704: foreach ($seq_ids as $id) {
705: try {
706: $results[$lookup[$id]]->setBodyPart($key, $this->_processString(Horde_Mime_Part::getRawPartText(stream_get_contents($this->_pop3Cache('msg', $id)), 'body', $key), $val));
707: } catch (Horde_Mime_Exception $e) {}
708: }
709: }
710: break;
711:
712: case Horde_Imap_Client::FETCH_HEADERS:
713:
714: foreach ($seq_ids as $id) {
715: $ob = $this->_pop3Cache('hdrob', $id);
716: foreach ($c_val as $key => $val) {
717: $tmp = $ob;
718:
719: if (empty($val['notsearch'])) {
720: $tmp2 = $tmp->toArray(array('nowrap' => true));
721: foreach (array_keys($tmp2) as $hdr) {
722: if (!in_array($hdr, $val['headers'])) {
723: $tmp->removeHeader($hdr);
724: }
725: }
726: } else {
727: foreach ($val['headers'] as $hdr) {
728: $tmp->removeHeader($hdr);
729: }
730: }
731:
732: $results[$lookup[$id]]->setHeaders($key, $tmp);
733: }
734: }
735: break;
736:
737: case Horde_Imap_Client::FETCH_STRUCTURE:
738: foreach ($seq_ids as $id) {
739: if ($ptr = $this->_pop3Cache('msg', $id)) {
740: try {
741: $results[$lookup[$id]]->setStructure(Horde_Mime_Part::parseMessage(stream_get_contents($ptr)));
742: } catch (Horde_Exception $e) {}
743: }
744: }
745: break;
746:
747: case Horde_Imap_Client::FETCH_ENVELOPE:
748: $rfc822 = new Horde_Mail_Rfc822();
749: foreach ($seq_ids as $id) {
750: $tmp = $this->_pop3Cache('hdrob', $id);
751: $results[$lookup[$id]]->setEnvelope(array(
752: 'date' => $tmp->getValue('date'),
753: 'subject' => $tmp->getValue('subject'),
754: 'from' => $tmp->getOb('from'),
755: 'sender' => $tmp->getOb('sender'),
756: 'reply_to' => $tmp->getOb('reply-to'),
757: 'to' => $rfc822->parseAddressList(Horde_Mime_Address::addrArray2String($tmp->getOb('to'))),
758: 'cc' => $rfc822->parseAddressList(Horde_Mime_Address::addrArray2String($tmp->getOb('cc'))),
759: 'bcc' => $rfc822->parseAddressList(Horde_Mime_Address::addrArray2String($tmp->getOb('bcc'))),
760: 'in_reply_to' => $tmp->getValue('in-reply-to'),
761: 'message_id' => $tmp->getValue('message-id')
762: ));
763: }
764: break;
765:
766: case Horde_Imap_Client::FETCH_IMAPDATE:
767: foreach ($seq_ids as $id) {
768: $tmp = $this->_pop3Cache('hdrob', $id);
769: $results[$lookup[$id]]->setImapDate($tmp->getValue('date'));
770: }
771: break;
772:
773: case Horde_Imap_Client::FETCH_SIZE:
774: $sizelist = $this->_pop3Cache('size');
775: foreach ($seq_ids as $id) {
776: $results[$lookup[$id]]->setSize($sizelist[$id]);
777: }
778: break;
779:
780: case Horde_Imap_Client::FETCH_SEQ:
781: foreach ($seq_ids as $id) {
782: $results[$lookup[$id]]->setSeq($id);
783: }
784: break;
785:
786: case Horde_Imap_Client::FETCH_UID:
787: $uidllist = $this->_pop3Cache('uidl');
788: foreach ($seq_ids as $id) {
789: if (isset($uidllist[$id])) {
790: $results[$lookup[$id]]->setUid($uidllist[$id]);
791: }
792: }
793: break;
794: }
795: }
796:
797: $this->_updateCache($results, array(
798: 'seq' => $options['ids']->sequence
799: ));
800:
801: return $results;
802: }
803:
804: 805: 806: 807: 808: 809: 810: 811: 812: 813: 814: 815: 816:
817: protected function _pop3Cache($type, $index = null, $data = null)
818: {
819: if (isset($this->_temp['pop3cache'][$index][$type])) {
820: if ($type == 'msg') {
821: rewind($this->_temp['pop3cache'][$index][$type]);
822: }
823: return $this->_temp['pop3cache'][$index][$type];
824: }
825:
826: switch ($type) {
827: case 'hdr':
828: $data = null;
829: if ($this->queryCapability('TOP')) {
830: try {
831: $resp = $this->_sendLine('TOP ' . $index . ' 0');
832: $ptr = $this->_getMultiline();
833: rewind($ptr);
834: $data = stream_get_contents($ptr);
835: fclose($ptr);
836: } catch (Horde_Imap_Client_Exception $e) {}
837: }
838:
839: if (is_null($data)) {
840: $data = Horde_Mime_Part::getRawPartText(stream_get_contents($this->_pop3Cache('msg', $index)), 'header', 0);
841: }
842: break;
843:
844: case 'hdrob':
845: $data = Horde_Mime_Headers::parseHeaders($this->_pop3Cache('hdr', $index));
846: break;
847:
848: case 'msg':
849: $resp = $this->_sendLine('RETR ' . $index);
850: $data = $this->_getMultiline();
851: rewind($data);
852: break;
853:
854: case 'size':
855: case 'uidl':
856: $data = array();
857: try {
858: $this->_sendLine(($type == 'size') ? 'LIST' : 'UIDL');
859: foreach ($this->_getMultiline(true) as $val) {
860: $resp_data = explode(' ', $val, 2);
861: $data[$resp_data[0]] = $resp_data[1];
862: }
863: } catch (Horde_Imap_Client_Exception $e) {}
864: break;
865:
866: case 'stat':
867: $resp = $this->_sendLine('STAT');
868: $resp_data = explode(' ', $resp['line'], 2);
869: $data = array('msgs' => $resp_data[0], 'size' => $resp_data[1]);
870: break;
871: }
872:
873: $this->_temp['pop3cache'][$index][$type] = $data;
874:
875: return $data;
876: }
877:
878: 879: 880: 881: 882: 883: 884: 885:
886: protected function _processString($str, $opts)
887: {
888: if (!empty($opts['length'])) {
889: return substr($str, empty($opts['start']) ? 0 : $opts['start'], $opts['length']);
890: } elseif (!empty($opts['start'])) {
891: return substr($str, $opts['start']);
892: }
893:
894: return $str;
895: }
896:
897: 898: 899: 900:
901: protected function _store($options)
902: {
903: $delete = $reset = false;
904:
905:
906: if (isset($options['replace'])) {
907: $delete = (bool)(count(array_intersect($options['replace'], array(
908: Horde_Imap_Client::FLAG_DELETED
909: ))));
910: $reset = !$delete;
911: } else {
912: if (!empty($options['add'])) {
913: $delete = (bool)(count(array_intersect($options['add'], array(
914: Horde_Imap_Client::FLAG_DELETED
915: ))));
916: }
917:
918: if (!empty($options['remove'])) {
919: $reset = !(bool)(count(array_intersect($options['remove'], array(
920: Horde_Imap_Client::FLAG_DELETED
921: ))));
922: }
923: }
924:
925: if ($reset) {
926: $this->_sendLine('RSET');
927: } elseif ($delete) {
928: foreach ($this->_getSeqIds($options['ids']) as $id) {
929: try {
930: $this->_sendLine('DELE ' . $id);
931: } catch (Horde_Imap_Client_Exception $e) {}
932: }
933: }
934:
935: return $this->getIdsOb();
936: }
937:
938: 939:
940: protected function _copy(Horde_Imap_Client_Mailbox $dest, $options)
941: {
942: $this->_exception('Copying messages not supported on POP3 servers.', 'NO_SUPPORT');
943: }
944:
945: 946:
947: protected function _setQuota(Horde_Imap_Client_Mailbox $root, $options)
948: {
949: $this->_exception('IMAP quotas not supported on POP3 servers.', 'NO_SUPPORT');
950: }
951:
952: 953:
954: protected function _getQuota(Horde_Imap_Client_Mailbox $root)
955: {
956: $this->_exception('IMAP quotas not supported on POP3 servers.', 'NO_SUPPORT');
957: }
958:
959: 960:
961: protected function _getQuotaRoot(Horde_Imap_Client_Mailbox $mailbox)
962: {
963: $this->_exception('IMAP quotas not supported on POP3 servers.', 'NO_SUPPORT');
964: }
965:
966: 967:
968: protected function _setACL(Horde_Imap_Client_Mailbox $mailbox, $identifier,
969: $options)
970: {
971: $this->_exception('IMAP ACLs not supported on POP3 servers.', 'NO_SUPPORT');
972: }
973:
974: 975:
976: protected function _getACL(Horde_Imap_Client_Mailbox $mailbox)
977: {
978: $this->_exception('IMAP ACLs not supported on POP3 servers.', 'NO_SUPPORT');
979: }
980:
981: 982:
983: protected function _listACLRights(Horde_Imap_Client_Mailbox $mailbox,
984: $identifier)
985: {
986: $this->_exception('IMAP ACLs not supported on POP3 servers.', 'NO_SUPPORT');
987: }
988:
989: 990:
991: protected function _getMyACLRights(Horde_Imap_Client_Mailbox $mailbox)
992: {
993: $this->_exception('IMAP ACLs not supported on POP3 servers.', 'NO_SUPPORT');
994: }
995:
996: 997:
998: protected function _getMetadata(Horde_Imap_Client_Mailbox $mailbox,
999: $entries, $options)
1000: {
1001: $this->_exception('IMAP metadata not supported on POP3 servers.', 'NO_SUPPORT');
1002: }
1003:
1004: 1005:
1006: protected function _setMetadata(Horde_Imap_Client_Mailbox $mailbox, $data)
1007: {
1008: $this->_exception('IMAP metadata not supported on POP3 servers.', 'NO_SUPPORT');
1009: }
1010:
1011: 1012:
1013: protected function _getSearchCache($type, $mailbox, $options)
1014: {
1015:
1016: return null;
1017: }
1018:
1019:
1020:
1021: 1022: 1023: 1024: 1025: 1026: 1027: 1028: 1029: 1030:
1031: protected function _sendLine($query, $options = array())
1032: {
1033: $this->writeDebug((empty($options['debug']) ? $query : $options['debug']) . "\n", Horde_Imap_Client::DEBUG_CLIENT);
1034:
1035: fwrite($this->_stream, $query . "\r\n");
1036:
1037: return $this->_getLine();
1038: }
1039:
1040: 1041: 1042: 1043: 1044: 1045: 1046: 1047: 1048:
1049: protected function _getLine()
1050: {
1051: $ob = array('line' => '', 'response' => '');
1052:
1053: if (feof($this->_stream)) {
1054: $this->logout();
1055: $this->_exception(Horde_Imap_Client_Translation::t("POP3 Server closed the connection unexpectedly."), 'DISCONNECT');
1056: }
1057:
1058: $read = rtrim(fgets($this->_stream));
1059: if (empty($read)) {
1060: return;
1061: }
1062:
1063: $this->writeDebug($read . "\n", Horde_Imap_Client::DEBUG_SERVER);
1064:
1065: $orig_read = $read;
1066: $read = explode(' ', $read, 2);
1067:
1068: switch ($read[0]) {
1069: case '+OK':
1070: $ob['response'] = 'OK';
1071: if (isset($read[1])) {
1072: $response = $this->_parseResponseText($read[1]);
1073: $ob['line'] = $response->text;
1074: }
1075: break;
1076:
1077: case '-ERR':
1078: $errcode = 0;
1079: if (isset($read[1])) {
1080: $response = $this->_parseResponseText($read[1]);
1081: $errtext = $response->text;
1082: if (isset($response->code)) {
1083: switch ($response->code) {
1084:
1085: case 'IN-USE':
1086:
1087: case 'LOGIN-DELAY':
1088: $errcode = 'LOGIN_UNAVAILABLE';
1089: break;
1090:
1091:
1092: case 'SYS/TEMP':
1093: $errcode = 'POP3_TEMP_ERROR';
1094: break;
1095:
1096:
1097: case 'SYS/PERM':
1098: $errcode = 'POP3_PERM_ERROR';
1099: break;
1100:
1101:
1102: case 'AUTH':
1103: $errcode = 'LOGIN_AUTHENTICATIONFAILED';
1104: break;
1105: }
1106: }
1107: } else {
1108: $errtext = '[No error message provided by server]';
1109: }
1110:
1111: $this->_exception(array(
1112: Horde_Imap_Client_Translation::t("POP3 error reported by server."),
1113: $errtext
1114: ), $errcode);
1115:
1116: case '.':
1117: $ob['response'] = 'END';
1118: break;
1119:
1120: case '+':
1121: $ob['response'] = '+';
1122: break;
1123:
1124: default:
1125: $ob['line'] = $orig_read;
1126: break;
1127: }
1128:
1129: return $ob;
1130: }
1131:
1132: 1133: 1134: 1135: 1136: 1137: 1138: 1139: 1140: 1141:
1142: protected function _getMultiline($retarray = false)
1143: {
1144: $data = $retarray
1145: ? array()
1146: : fopen('php://temp', 'r+');
1147:
1148: do {
1149: $line = $this->_getLine();
1150: if (empty($line['response'])) {
1151: if (substr($line['line'], 0, 2) == '..') {
1152: $line['line'] = substr($line['line'], 1);
1153: }
1154:
1155: if ($retarray) {
1156: $data[] = $line['line'];
1157: } else {
1158: fwrite($data, $line['line'] . "\r\n");
1159: }
1160: }
1161: } while ($line['response'] != 'END');
1162:
1163: return $data;
1164: }
1165:
1166: 1167: 1168: 1169: 1170: 1171: 1172:
1173: protected function _getSeqIds(Horde_Imap_Client_Ids $ids)
1174: {
1175: if (!count($ids)) {
1176: $status = $this->status($this->_selected, Horde_Imap_Client::STATUS_MESSAGES);
1177: return range(1, $status['messages']);
1178: } elseif ($ids->sequence) {
1179: return $ids->ids;
1180: }
1181:
1182: return array_keys(array_intersect($this->_pop3Cache('uidl'), $ids->ids));
1183: }
1184:
1185: }
1186: