PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 1.3.1
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v1.3.1
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / libs / Zend / Mail / Protocol / Imap.php
matomo / app / libs / Zend / Mail / Protocol Last commit date
Smtp 6 years ago Abstract.php 6 years ago Exception.php 6 years ago Imap.php 6 years ago Pop3.php 6 years ago Smtp.php 6 years ago
Imap.php
839 lines
1 <?php
2 /**
3 * Zend Framework
4 *
5 * LICENSE
6 *
7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
14 *
15 * @category Zend
16 * @package Zend_Mail
17 * @subpackage Protocol
18 * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
19 * @license http://framework.zend.com/license/new-bsd New BSD License
20 * @version $Id: Imap.php 23775 2011-03-01 17:25:24Z ralph $
21 */
22
23
24 /**
25 * @category Zend
26 * @package Zend_Mail
27 * @subpackage Protocol
28 * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
29 * @license http://framework.zend.com/license/new-bsd New BSD License
30 */
31 class Zend_Mail_Protocol_Imap
32 {
33 /**
34 * Default timeout in seconds for initiating session
35 */
36 const TIMEOUT_CONNECTION = 30;
37
38 /**
39 * socket to imap server
40 * @var resource|null
41 */
42 protected $_socket;
43
44 /**
45 * counter for request tag
46 * @var int
47 */
48 protected $_tagCount = 0;
49
50 /**
51 * Public constructor
52 *
53 * @param string $host hostname or IP address of IMAP server, if given connect() is called
54 * @param int|null $port port of IMAP server, null for default (143 or 993 for ssl)
55 * @param bool $ssl use ssl? 'SSL', 'TLS' or false
56 * @throws Zend_Mail_Protocol_Exception
57 */
58 function __construct($host = '', $port = null, $ssl = false)
59 {
60 if ($host) {
61 $this->connect($host, $port, $ssl);
62 }
63 }
64
65 /**
66 * Public destructor
67 */
68 public function __destruct()
69 {
70 $this->logout();
71 }
72
73 /**
74 * Open connection to IMAP server
75 *
76 * @param string $host hostname or IP address of IMAP server
77 * @param int|null $port of IMAP server, default is 143 (993 for ssl)
78 * @param string|bool $ssl use 'SSL', 'TLS' or false
79 * @return string welcome message
80 * @throws Zend_Mail_Protocol_Exception
81 */
82 public function connect($host, $port = null, $ssl = false)
83 {
84 if ($ssl == 'SSL') {
85 $host = 'ssl://' . $host;
86 }
87
88 if ($port === null) {
89 $port = $ssl === 'SSL' ? 993 : 143;
90 }
91
92 $errno = 0;
93 $errstr = '';
94 $this->_socket = @fsockopen($host, $port, $errno, $errstr, self::TIMEOUT_CONNECTION);
95 if (!$this->_socket) {
96 /**
97 * @see Zend_Mail_Protocol_Exception
98 */
99 // require_once 'Zend/Mail/Protocol/Exception.php';
100 throw new Zend_Mail_Protocol_Exception('cannot connect to host; error = ' . $errstr .
101 ' (errno = ' . $errno . ' )');
102 }
103
104 if (!$this->_assumedNextLine('* OK')) {
105 /**
106 * @see Zend_Mail_Protocol_Exception
107 */
108 // require_once 'Zend/Mail/Protocol/Exception.php';
109 throw new Zend_Mail_Protocol_Exception('host doesn\'t allow connection');
110 }
111
112 if ($ssl === 'TLS') {
113 $result = $this->requestAndResponse('STARTTLS');
114 $result = $result && stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
115 if (!$result) {
116 /**
117 * @see Zend_Mail_Protocol_Exception
118 */
119 // require_once 'Zend/Mail/Protocol/Exception.php';
120 throw new Zend_Mail_Protocol_Exception('cannot enable TLS');
121 }
122 }
123 }
124
125 /**
126 * get the next line from socket with error checking, but nothing else
127 *
128 * @return string next line
129 * @throws Zend_Mail_Protocol_Exception
130 */
131 protected function _nextLine()
132 {
133 $line = @fgets($this->_socket);
134 if ($line === false) {
135 /**
136 * @see Zend_Mail_Protocol_Exception
137 */
138 // require_once 'Zend/Mail/Protocol/Exception.php';
139 throw new Zend_Mail_Protocol_Exception('cannot read - connection closed?');
140 }
141
142 return $line;
143 }
144
145 /**
146 * get next line and assume it starts with $start. some requests give a simple
147 * feedback so we can quickly check if we can go on.
148 *
149 * @param string $start the first bytes we assume to be in the next line
150 * @return bool line starts with $start
151 * @throws Zend_Mail_Protocol_Exception
152 */
153 protected function _assumedNextLine($start)
154 {
155 $line = $this->_nextLine();
156 return strpos($line, $start) === 0;
157 }
158
159 /**
160 * get next line and split the tag. that's the normal case for a response line
161 *
162 * @param string $tag tag of line is returned by reference
163 * @return string next line
164 * @throws Zend_Mail_Protocol_Exception
165 */
166 protected function _nextTaggedLine(&$tag)
167 {
168 $line = $this->_nextLine();
169
170 // seperate tag from line
171 list($tag, $line) = explode(' ', $line, 2);
172
173 return $line;
174 }
175
176 /**
177 * split a given line in tokens. a token is literal of any form or a list
178 *
179 * @param string $line line to decode
180 * @return array tokens, literals are returned as string, lists as array
181 * @throws Zend_Mail_Protocol_Exception
182 */
183 protected function _decodeLine($line)
184 {
185 $tokens = array();
186 $stack = array();
187
188 /*
189 We start to decode the response here. The unterstood tokens are:
190 literal
191 "literal" or also "lit\\er\"al"
192 {bytes}<NL>literal
193 (literals*)
194 All tokens are returned in an array. Literals in braces (the last unterstood
195 token in the list) are returned as an array of tokens. I.e. the following response:
196 "foo" baz {3}<NL>bar ("f\\\"oo" bar)
197 would be returned as:
198 array('foo', 'baz', 'bar', array('f\\\"oo', 'bar'));
199
200 // TODO: add handling of '[' and ']' to parser for easier handling of response text
201 */
202 // replace any trailling <NL> including spaces with a single space
203 $line = rtrim($line) . ' ';
204 while (($pos = strpos($line, ' ')) !== false) {
205 $token = substr($line, 0, $pos);
206 while ($token[0] == '(') {
207 array_push($stack, $tokens);
208 $tokens = array();
209 $token = substr($token, 1);
210 }
211 if ($token[0] == '"') {
212 if (preg_match('%^\(*"((.|\\\\|\\")*?)" *%', $line, $matches)) {
213 $tokens[] = $matches[1];
214 $line = substr($line, strlen($matches[0]));
215 continue;
216 }
217 }
218 if ($token[0] == '{') {
219 $endPos = strpos($token, '}');
220 $chars = substr($token, 1, $endPos - 1);
221 if (is_numeric($chars)) {
222 $token = '';
223 while (strlen($token) < $chars) {
224 $token .= $this->_nextLine();
225 }
226 $line = '';
227 if (strlen($token) > $chars) {
228 $line = substr($token, $chars);
229 $token = substr($token, 0, $chars);
230 } else {
231 $line .= $this->_nextLine();
232 }
233 $tokens[] = $token;
234 $line = trim($line) . ' ';
235 continue;
236 }
237 }
238 if ($stack && $token[strlen($token) - 1] == ')') {
239 // closing braces are not seperated by spaces, so we need to count them
240 $braces = strlen($token);
241 $token = rtrim($token, ')');
242 // only count braces if more than one
243 $braces -= strlen($token) + 1;
244 // only add if token had more than just closing braces
245 if (rtrim($token) != '') {
246 $tokens[] = rtrim($token);
247 }
248 $token = $tokens;
249 $tokens = array_pop($stack);
250 // special handline if more than one closing brace
251 while ($braces-- > 0) {
252 $tokens[] = $token;
253 $token = $tokens;
254 $tokens = array_pop($stack);
255 }
256 }
257 $tokens[] = $token;
258 $line = substr($line, $pos + 1);
259 }
260
261 // maybe the server forgot to send some closing braces
262 while ($stack) {
263 $child = $tokens;
264 $tokens = array_pop($stack);
265 $tokens[] = $child;
266 }
267
268 return $tokens;
269 }
270
271 /**
272 * read a response "line" (could also be more than one real line if response has {..}<NL>)
273 * and do a simple decode
274 *
275 * @param array|string $tokens decoded tokens are returned by reference, if $dontParse
276 * is true the unparsed line is returned here
277 * @param string $wantedTag check for this tag for response code. Default '*' is
278 * continuation tag.
279 * @param bool $dontParse if true only the unparsed line is returned $tokens
280 * @return bool if returned tag matches wanted tag
281 * @throws Zend_Mail_Protocol_Exception
282 */
283 public function readLine(&$tokens = array(), $wantedTag = '*', $dontParse = false)
284 {
285 $line = $this->_nextTaggedLine($tag);
286 if (!$dontParse) {
287 $tokens = $this->_decodeLine($line);
288 } else {
289 $tokens = $line;
290 }
291
292 // if tag is wanted tag we might be at the end of a multiline response
293 return $tag == $wantedTag;
294 }
295
296 /**
297 * read all lines of response until given tag is found (last line of response)
298 *
299 * @param string $tag the tag of your request
300 * @param string|array $filter you can filter the response so you get only the
301 * given response lines
302 * @param bool $dontParse if true every line is returned unparsed instead of
303 * the decoded tokens
304 * @return null|bool|array tokens if success, false if error, null if bad request
305 * @throws Zend_Mail_Protocol_Exception
306 */
307 public function readResponse($tag, $dontParse = false)
308 {
309 $lines = array();
310 while (!$this->readLine($tokens, $tag, $dontParse)) {
311 $lines[] = $tokens;
312 }
313
314 if ($dontParse) {
315 // last to chars are still needed for response code
316 $tokens = array(substr($tokens, 0, 2));
317 }
318 // last line has response code
319 if ($tokens[0] == 'OK') {
320 return $lines ? $lines : true;
321 } else if ($tokens[0] == 'NO'){
322 return false;
323 }
324 return null;
325 }
326
327 /**
328 * send a request
329 *
330 * @param string $command your request command
331 * @param array $tokens additional parameters to command, use escapeString() to prepare
332 * @param string $tag provide a tag otherwise an autogenerated is returned
333 * @return null
334 * @throws Zend_Mail_Protocol_Exception
335 */
336 public function sendRequest($command, $tokens = array(), &$tag = null)
337 {
338 if (!$tag) {
339 ++$this->_tagCount;
340 $tag = 'TAG' . $this->_tagCount;
341 }
342
343 $line = $tag . ' ' . $command;
344
345 foreach ($tokens as $token) {
346 if (is_array($token)) {
347 if (@fputs($this->_socket, $line . ' ' . $token[0] . "\r\n") === false) {
348 /**
349 * @see Zend_Mail_Protocol_Exception
350 */
351 // require_once 'Zend/Mail/Protocol/Exception.php';
352 throw new Zend_Mail_Protocol_Exception('cannot write - connection closed?');
353 }
354 if (!$this->_assumedNextLine('+ ')) {
355 /**
356 * @see Zend_Mail_Protocol_Exception
357 */
358 // require_once 'Zend/Mail/Protocol/Exception.php';
359 throw new Zend_Mail_Protocol_Exception('cannot send literal string');
360 }
361 $line = $token[1];
362 } else {
363 $line .= ' ' . $token;
364 }
365 }
366
367 if (@fputs($this->_socket, $line . "\r\n") === false) {
368 /**
369 * @see Zend_Mail_Protocol_Exception
370 */
371 // require_once 'Zend/Mail/Protocol/Exception.php';
372 throw new Zend_Mail_Protocol_Exception('cannot write - connection closed?');
373 }
374 }
375
376 /**
377 * send a request and get response at once
378 *
379 * @param string $command command as in sendRequest()
380 * @param array $tokens parameters as in sendRequest()
381 * @param bool $dontParse if true unparsed lines are returned instead of tokens
382 * @return mixed response as in readResponse()
383 * @throws Zend_Mail_Protocol_Exception
384 */
385 public function requestAndResponse($command, $tokens = array(), $dontParse = false)
386 {
387 $this->sendRequest($command, $tokens, $tag);
388 $response = $this->readResponse($tag, $dontParse);
389
390 return $response;
391 }
392
393 /**
394 * escape one or more literals i.e. for sendRequest
395 *
396 * @param string|array $string the literal/-s
397 * @return string|array escape literals, literals with newline ar returned
398 * as array('{size}', 'string');
399 */
400 public function escapeString($string)
401 {
402 if (func_num_args() < 2) {
403 if (strpos($string, "\n") !== false) {
404 return array('{' . strlen($string) . '}', $string);
405 } else {
406 return '"' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $string) . '"';
407 }
408 }
409 $result = array();
410 foreach (func_get_args() as $string) {
411 $result[] = $this->escapeString($string);
412 }
413 return $result;
414 }
415
416 /**
417 * escape a list with literals or lists
418 *
419 * @param array $list list with literals or lists as PHP array
420 * @return string escaped list for imap
421 */
422 public function escapeList($list)
423 {
424 $result = array();
425 foreach ($list as $k => $v) {
426 if (!is_array($v)) {
427 // $result[] = $this->escapeString($v);
428 $result[] = $v;
429 continue;
430 }
431 $result[] = $this->escapeList($v);
432 }
433 return '(' . implode(' ', $result) . ')';
434 }
435
436 /**
437 * Login to IMAP server.
438 *
439 * @param string $user username
440 * @param string $password password
441 * @return bool success
442 * @throws Zend_Mail_Protocol_Exception
443 */
444 public function login($user, $password)
445 {
446 return $this->requestAndResponse('LOGIN', $this->escapeString($user, $password), true);
447 }
448
449 /**
450 * logout of imap server
451 *
452 * @return bool success
453 */
454 public function logout()
455 {
456 $result = false;
457 if ($this->_socket) {
458 try {
459 $result = $this->requestAndResponse('LOGOUT', array(), true);
460 } catch (Zend_Mail_Protocol_Exception $e) {
461 // ignoring exception
462 }
463 fclose($this->_socket);
464 $this->_socket = null;
465 }
466 return $result;
467 }
468
469
470 /**
471 * Get capabilities from IMAP server
472 *
473 * @return array list of capabilities
474 * @throws Zend_Mail_Protocol_Exception
475 */
476 public function capability()
477 {
478 $response = $this->requestAndResponse('CAPABILITY');
479
480 if (!$response) {
481 return $response;
482 }
483
484 $capabilities = array();
485 foreach ($response as $line) {
486 $capabilities = array_merge($capabilities, $line);
487 }
488 return $capabilities;
489 }
490
491 /**
492 * Examine and select have the same response. The common code for both
493 * is in this method
494 *
495 * @param string $command can be 'EXAMINE' or 'SELECT' and this is used as command
496 * @param string $box which folder to change to or examine
497 * @return bool|array false if error, array with returned information
498 * otherwise (flags, exists, recent, uidvalidity)
499 * @throws Zend_Mail_Protocol_Exception
500 */
501 public function examineOrSelect($command = 'EXAMINE', $box = 'INBOX')
502 {
503 $this->sendRequest($command, array($this->escapeString($box)), $tag);
504
505 $result = array();
506 while (!$this->readLine($tokens, $tag)) {
507 if ($tokens[0] == 'FLAGS') {
508 array_shift($tokens);
509 $result['flags'] = $tokens;
510 continue;
511 }
512 switch ($tokens[1]) {
513 case 'EXISTS':
514 case 'RECENT':
515 $result[strtolower($tokens[1])] = $tokens[0];
516 break;
517 case '[UIDVALIDITY':
518 $result['uidvalidity'] = (int)$tokens[2];
519 break;
520 default:
521 // ignore
522 }
523 }
524
525 if ($tokens[0] != 'OK') {
526 return false;
527 }
528 return $result;
529 }
530
531 /**
532 * change folder
533 *
534 * @param string $box change to this folder
535 * @return bool|array see examineOrselect()
536 * @throws Zend_Mail_Protocol_Exception
537 */
538 public function select($box = 'INBOX')
539 {
540 return $this->examineOrSelect('SELECT', $box);
541 }
542
543 /**
544 * examine folder
545 *
546 * @param string $box examine this folder
547 * @return bool|array see examineOrselect()
548 * @throws Zend_Mail_Protocol_Exception
549 */
550 public function examine($box = 'INBOX')
551 {
552 return $this->examineOrSelect('EXAMINE', $box);
553 }
554
555 /**
556 * fetch one or more items of one or more messages
557 *
558 * @param string|array $items items to fetch from message(s) as string (if only one item)
559 * or array of strings
560 * @param int $from message for items or start message if $to !== null
561 * @param int|null $to if null only one message ($from) is fetched, else it's the
562 * last message, INF means last message avaible
563 * @return string|array if only one item of one message is fetched it's returned as string
564 * if items of one message are fetched it's returned as (name => value)
565 * if one items of messages are fetched it's returned as (msgno => value)
566 * if items of messages are fetchted it's returned as (msgno => (name => value))
567 * @throws Zend_Mail_Protocol_Exception
568 */
569 public function fetch($items, $from, $to = null)
570 {
571 if (is_array($from)) {
572 $set = implode(',', $from);
573 } else if ($to === null) {
574 $set = (int)$from;
575 } else if ($to === INF) {
576 $set = (int)$from . ':*';
577 } else {
578 $set = (int)$from . ':' . (int)$to;
579 }
580
581 $items = (array)$items;
582 $itemList = $this->escapeList($items);
583
584 $this->sendRequest('FETCH', array($set, $itemList), $tag);
585
586 $result = array();
587 while (!$this->readLine($tokens, $tag)) {
588 // ignore other responses
589 if ($tokens[1] != 'FETCH') {
590 continue;
591 }
592 // ignore other messages
593 if ($to === null && !is_array($from) && $tokens[0] != $from) {
594 continue;
595 }
596 // if we only want one item we return that one directly
597 if (count($items) == 1) {
598 if ($tokens[2][0] == $items[0]) {
599 $data = $tokens[2][1];
600 } else {
601 // maybe the server send an other field we didn't wanted
602 $count = count($tokens[2]);
603 // we start with 2, because 0 was already checked
604 for ($i = 2; $i < $count; $i += 2) {
605 if ($tokens[2][$i] != $items[0]) {
606 continue;
607 }
608 $data = $tokens[2][$i + 1];
609 break;
610 }
611 }
612 } else {
613 $data = array();
614 while (key($tokens[2]) !== null) {
615 $data[current($tokens[2])] = next($tokens[2]);
616 next($tokens[2]);
617 }
618 }
619 // if we want only one message we can ignore everything else and just return
620 if ($to === null && !is_array($from) && $tokens[0] == $from) {
621 // we still need to read all lines
622 while (!$this->readLine($tokens, $tag));
623 return $data;
624 }
625 $result[$tokens[0]] = $data;
626 }
627
628 if ($to === null && !is_array($from)) {
629 /**
630 * @see Zend_Mail_Protocol_Exception
631 */
632 // require_once 'Zend/Mail/Protocol/Exception.php';
633 throw new Zend_Mail_Protocol_Exception('the single id was not found in response');
634 }
635
636 return $result;
637 }
638
639 /**
640 * get mailbox list
641 *
642 * this method can't be named after the IMAP command 'LIST', as list is a reserved keyword
643 *
644 * @param string $reference mailbox reference for list
645 * @param string $mailbox mailbox name match with wildcards
646 * @return array mailboxes that matched $mailbox as array(globalName => array('delim' => .., 'flags' => ..))
647 * @throws Zend_Mail_Protocol_Exception
648 */
649 public function listMailbox($reference = '', $mailbox = '*')
650 {
651 $result = array();
652 $list = $this->requestAndResponse('LIST', $this->escapeString($reference, $mailbox));
653 if (!$list || $list === true) {
654 return $result;
655 }
656
657 foreach ($list as $item) {
658 if (count($item) != 4 || $item[0] != 'LIST') {
659 continue;
660 }
661 $result[$item[3]] = array('delim' => $item[2], 'flags' => $item[1]);
662 }
663
664 return $result;
665 }
666
667 /**
668 * set flags
669 *
670 * @param array $flags flags to set, add or remove - see $mode
671 * @param int $from message for items or start message if $to !== null
672 * @param int|null $to if null only one message ($from) is fetched, else it's the
673 * last message, INF means last message avaible
674 * @param string|null $mode '+' to add flags, '-' to remove flags, everything else sets the flags as given
675 * @param bool $silent if false the return values are the new flags for the wanted messages
676 * @return bool|array new flags if $silent is false, else true or false depending on success
677 * @throws Zend_Mail_Protocol_Exception
678 */
679 public function store(array $flags, $from, $to = null, $mode = null, $silent = true)
680 {
681 $item = 'FLAGS';
682 if ($mode == '+' || $mode == '-') {
683 $item = $mode . $item;
684 }
685 if ($silent) {
686 $item .= '.SILENT';
687 }
688
689 $flags = $this->escapeList($flags);
690 $set = (int)$from;
691 if ($to != null) {
692 $set .= ':' . ($to == INF ? '*' : (int)$to);
693 }
694
695 $result = $this->requestAndResponse('STORE', array($set, $item, $flags), $silent);
696
697 if ($silent) {
698 return $result ? true : false;
699 }
700
701 $tokens = $result;
702 $result = array();
703 foreach ($tokens as $token) {
704 if ($token[1] != 'FETCH' || $token[2][0] != 'FLAGS') {
705 continue;
706 }
707 $result[$token[0]] = $token[2][1];
708 }
709
710 return $result;
711 }
712
713 /**
714 * append a new message to given folder
715 *
716 * @param string $folder name of target folder
717 * @param string $message full message content
718 * @param array $flags flags for new message
719 * @param string $date date for new message
720 * @return bool success
721 * @throws Zend_Mail_Protocol_Exception
722 */
723 public function append($folder, $message, $flags = null, $date = null)
724 {
725 $tokens = array();
726 $tokens[] = $this->escapeString($folder);
727 if ($flags !== null) {
728 $tokens[] = $this->escapeList($flags);
729 }
730 if ($date !== null) {
731 $tokens[] = $this->escapeString($date);
732 }
733 $tokens[] = $this->escapeString($message);
734
735 return $this->requestAndResponse('APPEND', $tokens, true);
736 }
737
738 /**
739 * copy message set from current folder to other folder
740 *
741 * @param string $folder destination folder
742 * @param int|null $to if null only one message ($from) is fetched, else it's the
743 * last message, INF means last message avaible
744 * @return bool success
745 * @throws Zend_Mail_Protocol_Exception
746 */
747 public function copy($folder, $from, $to = null)
748 {
749 $set = (int)$from;
750 if ($to != null) {
751 $set .= ':' . ($to == INF ? '*' : (int)$to);
752 }
753
754 return $this->requestAndResponse('COPY', array($set, $this->escapeString($folder)), true);
755 }
756
757 /**
758 * create a new folder (and parent folders if needed)
759 *
760 * @param string $folder folder name
761 * @return bool success
762 */
763 public function create($folder)
764 {
765 return $this->requestAndResponse('CREATE', array($this->escapeString($folder)), true);
766 }
767
768 /**
769 * rename an existing folder
770 *
771 * @param string $old old name
772 * @param string $new new name
773 * @return bool success
774 */
775 public function rename($old, $new)
776 {
777 return $this->requestAndResponse('RENAME', $this->escapeString($old, $new), true);
778 }
779
780 /**
781 * remove a folder
782 *
783 * @param string $folder folder name
784 * @return bool success
785 */
786 public function delete($folder)
787 {
788 return $this->requestAndResponse('DELETE', array($this->escapeString($folder)), true);
789 }
790
791 /**
792 * permanently remove messages
793 *
794 * @return bool success
795 */
796 public function expunge()
797 {
798 // TODO: parse response?
799 return $this->requestAndResponse('EXPUNGE');
800 }
801
802 /**
803 * send noop
804 *
805 * @return bool success
806 */
807 public function noop()
808 {
809 // TODO: parse response
810 return $this->requestAndResponse('NOOP');
811 }
812
813 /**
814 * do a search request
815 *
816 * This method is currently marked as internal as the API might change and is not
817 * safe if you don't take precautions.
818 *
819 * @internal
820 * @return array message ids
821 */
822 public function search(array $params)
823 {
824 $response = $this->requestAndResponse('SEARCH', $params);
825 if (!$response) {
826 return $response;
827 }
828
829 foreach ($response as $ids) {
830 if ($ids[0] == 'SEARCH') {
831 array_shift($ids);
832 return $ids;
833 }
834 }
835 return array();
836 }
837
838 }
839