File indexing completed on 2025-03-02 05:29:34
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Mail 0017 * @subpackage Protocol 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 0024 /** 0025 * @category Zend 0026 * @package Zend_Mail 0027 * @subpackage Protocol 0028 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0029 * @license http://framework.zend.com/license/new-bsd New BSD License 0030 */ 0031 class Zend_Mail_Protocol_Imap 0032 { 0033 /** 0034 * Default timeout in seconds for initiating session 0035 */ 0036 const TIMEOUT_CONNECTION = 30; 0037 0038 /** 0039 * socket to imap server 0040 * @var resource|null 0041 */ 0042 protected $_socket; 0043 0044 /** 0045 * counter for request tag 0046 * @var int 0047 */ 0048 protected $_tagCount = 0; 0049 0050 /** 0051 * Public constructor 0052 * 0053 * @param string $host hostname or IP address of IMAP server, if given connect() is called 0054 * @param int|null $port port of IMAP server, null for default (143 or 993 for ssl) 0055 * @param bool $ssl use ssl? 'SSL', 'TLS' or false 0056 * @throws Zend_Mail_Protocol_Exception 0057 */ 0058 function __construct($host = '', $port = null, $ssl = false) 0059 { 0060 if ($host) { 0061 $this->connect($host, $port, $ssl); 0062 } 0063 } 0064 0065 /** 0066 * Public destructor 0067 */ 0068 public function __destruct() 0069 { 0070 $this->logout(); 0071 } 0072 0073 /** 0074 * Open connection to IMAP server 0075 * 0076 * @param string $host hostname or IP address of IMAP server 0077 * @param int|null $port of IMAP server, default is 143 (993 for ssl) 0078 * @param string|bool $ssl use 'SSL', 'TLS' or false 0079 * @return string welcome message 0080 * @throws Zend_Mail_Protocol_Exception 0081 */ 0082 public function connect($host, $port = null, $ssl = false) 0083 { 0084 if ($ssl == 'SSL') { 0085 $host = 'ssl://' . $host; 0086 } 0087 0088 if ($port === null) { 0089 $port = $ssl === 'SSL' ? 993 : 143; 0090 } 0091 0092 $errno = 0; 0093 $errstr = ''; 0094 $this->_socket = @fsockopen($host, $port, $errno, $errstr, self::TIMEOUT_CONNECTION); 0095 if (!$this->_socket) { 0096 /** 0097 * @see Zend_Mail_Protocol_Exception 0098 */ 0099 // require_once 'Zend/Mail/Protocol/Exception.php'; 0100 throw new Zend_Mail_Protocol_Exception('cannot connect to host; error = ' . $errstr . 0101 ' (errno = ' . $errno . ' )'); 0102 } 0103 0104 if (!$this->_assumedNextLine('* OK')) { 0105 /** 0106 * @see Zend_Mail_Protocol_Exception 0107 */ 0108 // require_once 'Zend/Mail/Protocol/Exception.php'; 0109 throw new Zend_Mail_Protocol_Exception('host doesn\'t allow connection'); 0110 } 0111 0112 if ($ssl === 'TLS') { 0113 $result = $this->requestAndResponse('STARTTLS'); 0114 $result = $result && stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT); 0115 if (!$result) { 0116 /** 0117 * @see Zend_Mail_Protocol_Exception 0118 */ 0119 // require_once 'Zend/Mail/Protocol/Exception.php'; 0120 throw new Zend_Mail_Protocol_Exception('cannot enable TLS'); 0121 } 0122 } 0123 } 0124 0125 /** 0126 * get the next line from socket with error checking, but nothing else 0127 * 0128 * @return string next line 0129 * @throws Zend_Mail_Protocol_Exception 0130 */ 0131 protected function _nextLine() 0132 { 0133 $line = @fgets($this->_socket); 0134 if ($line === false) { 0135 /** 0136 * @see Zend_Mail_Protocol_Exception 0137 */ 0138 // require_once 'Zend/Mail/Protocol/Exception.php'; 0139 throw new Zend_Mail_Protocol_Exception('cannot read - connection closed?'); 0140 } 0141 0142 return $line; 0143 } 0144 0145 /** 0146 * get next line and assume it starts with $start. some requests give a simple 0147 * feedback so we can quickly check if we can go on. 0148 * 0149 * @param string $start the first bytes we assume to be in the next line 0150 * @return bool line starts with $start 0151 * @throws Zend_Mail_Protocol_Exception 0152 */ 0153 protected function _assumedNextLine($start) 0154 { 0155 $line = $this->_nextLine(); 0156 return strpos($line, $start) === 0; 0157 } 0158 0159 /** 0160 * get next line and split the tag. that's the normal case for a response line 0161 * 0162 * @param string $tag tag of line is returned by reference 0163 * @return string next line 0164 * @throws Zend_Mail_Protocol_Exception 0165 */ 0166 protected function _nextTaggedLine(&$tag) 0167 { 0168 $line = $this->_nextLine(); 0169 0170 // seperate tag from line 0171 list($tag, $line) = explode(' ', $line, 2); 0172 0173 return $line; 0174 } 0175 0176 /** 0177 * split a given line in tokens. a token is literal of any form or a list 0178 * 0179 * @param string $line line to decode 0180 * @return array tokens, literals are returned as string, lists as array 0181 * @throws Zend_Mail_Protocol_Exception 0182 */ 0183 protected function _decodeLine($line) 0184 { 0185 $tokens = array(); 0186 $stack = array(); 0187 0188 /* 0189 We start to decode the response here. The unterstood tokens are: 0190 literal 0191 "literal" or also "lit\\er\"al" 0192 {bytes}<NL>literal 0193 (literals*) 0194 All tokens are returned in an array. Literals in braces (the last unterstood 0195 token in the list) are returned as an array of tokens. I.e. the following response: 0196 "foo" baz {3}<NL>bar ("f\\\"oo" bar) 0197 would be returned as: 0198 array('foo', 'baz', 'bar', array('f\\\"oo', 'bar')); 0199 0200 // TODO: add handling of '[' and ']' to parser for easier handling of response text 0201 */ 0202 // replace any trailling <NL> including spaces with a single space 0203 $line = rtrim($line) . ' '; 0204 while (($pos = strpos($line, ' ')) !== false) { 0205 $token = substr($line, 0, $pos); 0206 while ($token[0] == '(') { 0207 array_push($stack, $tokens); 0208 $tokens = array(); 0209 $token = substr($token, 1); 0210 } 0211 if ($token[0] == '"') { 0212 if (preg_match('%^\(*"((.|\\\\|\\")*?)" *%', $line, $matches)) { 0213 $tokens[] = $matches[1]; 0214 $line = substr($line, strlen($matches[0])); 0215 continue; 0216 } 0217 } 0218 if ($token[0] == '{') { 0219 $endPos = strpos($token, '}'); 0220 $chars = substr($token, 1, $endPos - 1); 0221 if (is_numeric($chars)) { 0222 $token = ''; 0223 while (strlen($token) < $chars) { 0224 $token .= $this->_nextLine(); 0225 } 0226 $line = ''; 0227 if (strlen($token) > $chars) { 0228 $line = substr($token, $chars); 0229 $token = substr($token, 0, $chars); 0230 } else { 0231 $line .= $this->_nextLine(); 0232 } 0233 $tokens[] = $token; 0234 $line = trim($line) . ' '; 0235 continue; 0236 } 0237 } 0238 if ($stack && $token[strlen($token) - 1] == ')') { 0239 // closing braces are not seperated by spaces, so we need to count them 0240 $braces = strlen($token); 0241 $token = rtrim($token, ')'); 0242 // only count braces if more than one 0243 $braces -= strlen($token) + 1; 0244 // only add if token had more than just closing braces 0245 if (rtrim($token) != '') { 0246 $tokens[] = rtrim($token); 0247 } 0248 $token = $tokens; 0249 $tokens = array_pop($stack); 0250 // special handline if more than one closing brace 0251 while ($braces-- > 0) { 0252 $tokens[] = $token; 0253 $token = $tokens; 0254 $tokens = array_pop($stack); 0255 } 0256 } 0257 $tokens[] = $token; 0258 $line = substr($line, $pos + 1); 0259 } 0260 0261 // maybe the server forgot to send some closing braces 0262 while ($stack) { 0263 $child = $tokens; 0264 $tokens = array_pop($stack); 0265 $tokens[] = $child; 0266 } 0267 0268 return $tokens; 0269 } 0270 0271 /** 0272 * read a response "line" (could also be more than one real line if response has {..}<NL>) 0273 * and do a simple decode 0274 * 0275 * @param array|string $tokens decoded tokens are returned by reference, if $dontParse 0276 * is true the unparsed line is returned here 0277 * @param string $wantedTag check for this tag for response code. Default '*' is 0278 * continuation tag. 0279 * @param bool $dontParse if true only the unparsed line is returned $tokens 0280 * @return bool if returned tag matches wanted tag 0281 * @throws Zend_Mail_Protocol_Exception 0282 */ 0283 public function readLine(&$tokens = array(), $wantedTag = '*', $dontParse = false) 0284 { 0285 $line = $this->_nextTaggedLine($tag); 0286 if (!$dontParse) { 0287 $tokens = $this->_decodeLine($line); 0288 } else { 0289 $tokens = $line; 0290 } 0291 0292 // if tag is wanted tag we might be at the end of a multiline response 0293 return $tag == $wantedTag; 0294 } 0295 0296 /** 0297 * read all lines of response until given tag is found (last line of response) 0298 * 0299 * @param string $tag the tag of your request 0300 * @param string|array $filter you can filter the response so you get only the 0301 * given response lines 0302 * @param bool $dontParse if true every line is returned unparsed instead of 0303 * the decoded tokens 0304 * @return null|bool|array tokens if success, false if error, null if bad request 0305 * @throws Zend_Mail_Protocol_Exception 0306 */ 0307 public function readResponse($tag, $dontParse = false) 0308 { 0309 $lines = array(); 0310 while (!$this->readLine($tokens, $tag, $dontParse)) { 0311 $lines[] = $tokens; 0312 } 0313 0314 if ($dontParse) { 0315 // last to chars are still needed for response code 0316 $tokens = array(substr($tokens, 0, 2)); 0317 } 0318 // last line has response code 0319 if ($tokens[0] == 'OK') { 0320 return $lines ? $lines : true; 0321 } else if ($tokens[0] == 'NO'){ 0322 return false; 0323 } 0324 return null; 0325 } 0326 0327 /** 0328 * send a request 0329 * 0330 * @param string $command your request command 0331 * @param array $tokens additional parameters to command, use escapeString() to prepare 0332 * @param string $tag provide a tag otherwise an autogenerated is returned 0333 * @return null 0334 * @throws Zend_Mail_Protocol_Exception 0335 */ 0336 public function sendRequest($command, $tokens = array(), &$tag = null) 0337 { 0338 if (!$tag) { 0339 ++$this->_tagCount; 0340 $tag = 'TAG' . $this->_tagCount; 0341 } 0342 0343 $line = $tag . ' ' . $command; 0344 0345 foreach ($tokens as $token) { 0346 if (is_array($token)) { 0347 if (@fputs($this->_socket, $line . ' ' . $token[0] . "\r\n") === false) { 0348 /** 0349 * @see Zend_Mail_Protocol_Exception 0350 */ 0351 // require_once 'Zend/Mail/Protocol/Exception.php'; 0352 throw new Zend_Mail_Protocol_Exception('cannot write - connection closed?'); 0353 } 0354 if (!$this->_assumedNextLine('+ ')) { 0355 /** 0356 * @see Zend_Mail_Protocol_Exception 0357 */ 0358 // require_once 'Zend/Mail/Protocol/Exception.php'; 0359 throw new Zend_Mail_Protocol_Exception('cannot send literal string'); 0360 } 0361 $line = $token[1]; 0362 } else { 0363 $line .= ' ' . $token; 0364 } 0365 } 0366 0367 if (@fputs($this->_socket, $line . "\r\n") === false) { 0368 /** 0369 * @see Zend_Mail_Protocol_Exception 0370 */ 0371 // require_once 'Zend/Mail/Protocol/Exception.php'; 0372 throw new Zend_Mail_Protocol_Exception('cannot write - connection closed?'); 0373 } 0374 } 0375 0376 /** 0377 * send a request and get response at once 0378 * 0379 * @param string $command command as in sendRequest() 0380 * @param array $tokens parameters as in sendRequest() 0381 * @param bool $dontParse if true unparsed lines are returned instead of tokens 0382 * @return mixed response as in readResponse() 0383 * @throws Zend_Mail_Protocol_Exception 0384 */ 0385 public function requestAndResponse($command, $tokens = array(), $dontParse = false) 0386 { 0387 $this->sendRequest($command, $tokens, $tag); 0388 $response = $this->readResponse($tag, $dontParse); 0389 0390 return $response; 0391 } 0392 0393 /** 0394 * escape one or more literals i.e. for sendRequest 0395 * 0396 * @param string|array $string the literal/-s 0397 * @return string|array escape literals, literals with newline ar returned 0398 * as array('{size}', 'string'); 0399 */ 0400 public function escapeString($string) 0401 { 0402 if (func_num_args() < 2) { 0403 if (strpos($string, "\n") !== false) { 0404 return array('{' . strlen($string) . '}', $string); 0405 } else { 0406 return '"' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $string) . '"'; 0407 } 0408 } 0409 $result = array(); 0410 foreach (func_get_args() as $string) { 0411 $result[] = $this->escapeString($string); 0412 } 0413 return $result; 0414 } 0415 0416 /** 0417 * escape a list with literals or lists 0418 * 0419 * @param array $list list with literals or lists as PHP array 0420 * @return string escaped list for imap 0421 */ 0422 public function escapeList($list) 0423 { 0424 $result = array(); 0425 foreach ($list as $k => $v) { 0426 if (!is_array($v)) { 0427 // $result[] = $this->escapeString($v); 0428 $result[] = $v; 0429 continue; 0430 } 0431 $result[] = $this->escapeList($v); 0432 } 0433 return '(' . implode(' ', $result) . ')'; 0434 } 0435 0436 /** 0437 * Login to IMAP server. 0438 * 0439 * @param string $user username 0440 * @param string $password password 0441 * @return bool success 0442 * @throws Zend_Mail_Protocol_Exception 0443 */ 0444 public function login($user, $password) 0445 { 0446 return $this->requestAndResponse('LOGIN', $this->escapeString($user, $password), true); 0447 } 0448 0449 /** 0450 * logout of imap server 0451 * 0452 * @return bool success 0453 */ 0454 public function logout() 0455 { 0456 $result = false; 0457 if ($this->_socket) { 0458 try { 0459 $result = $this->requestAndResponse('LOGOUT', array(), true); 0460 } catch (Zend_Mail_Protocol_Exception $e) { 0461 // ignoring exception 0462 } 0463 fclose($this->_socket); 0464 $this->_socket = null; 0465 } 0466 return $result; 0467 } 0468 0469 0470 /** 0471 * Get capabilities from IMAP server 0472 * 0473 * @return array list of capabilities 0474 * @throws Zend_Mail_Protocol_Exception 0475 */ 0476 public function capability() 0477 { 0478 $response = $this->requestAndResponse('CAPABILITY'); 0479 0480 if (!$response) { 0481 return $response; 0482 } 0483 0484 $capabilities = array(); 0485 foreach ($response as $line) { 0486 $capabilities = array_merge($capabilities, $line); 0487 } 0488 return $capabilities; 0489 } 0490 0491 /** 0492 * Examine and select have the same response. The common code for both 0493 * is in this method 0494 * 0495 * @param string $command can be 'EXAMINE' or 'SELECT' and this is used as command 0496 * @param string $box which folder to change to or examine 0497 * @return bool|array false if error, array with returned information 0498 * otherwise (flags, exists, recent, uidvalidity) 0499 * @throws Zend_Mail_Protocol_Exception 0500 */ 0501 public function examineOrSelect($command = 'EXAMINE', $box = 'INBOX') 0502 { 0503 $this->sendRequest($command, array($this->escapeString($box)), $tag); 0504 0505 $result = array(); 0506 while (!$this->readLine($tokens, $tag)) { 0507 if ($tokens[0] == 'FLAGS') { 0508 array_shift($tokens); 0509 $result['flags'] = $tokens; 0510 continue; 0511 } 0512 switch ($tokens[1]) { 0513 case 'EXISTS': 0514 case 'RECENT': 0515 $result[strtolower($tokens[1])] = $tokens[0]; 0516 break; 0517 case '[UIDVALIDITY': 0518 $result['uidvalidity'] = (int)$tokens[2]; 0519 break; 0520 default: 0521 // ignore 0522 } 0523 } 0524 0525 if ($tokens[0] != 'OK') { 0526 return false; 0527 } 0528 return $result; 0529 } 0530 0531 /** 0532 * change folder 0533 * 0534 * @param string $box change to this folder 0535 * @return bool|array see examineOrselect() 0536 * @throws Zend_Mail_Protocol_Exception 0537 */ 0538 public function select($box = 'INBOX') 0539 { 0540 return $this->examineOrSelect('SELECT', $box); 0541 } 0542 0543 /** 0544 * examine folder 0545 * 0546 * @param string $box examine this folder 0547 * @return bool|array see examineOrselect() 0548 * @throws Zend_Mail_Protocol_Exception 0549 */ 0550 public function examine($box = 'INBOX') 0551 { 0552 return $this->examineOrSelect('EXAMINE', $box); 0553 } 0554 0555 /** 0556 * fetch one or more items of one or more messages 0557 * 0558 * @param string|array $items items to fetch from message(s) as string (if only one item) 0559 * or array of strings 0560 * @param int $from message for items or start message if $to !== null 0561 * @param int|null $to if null only one message ($from) is fetched, else it's the 0562 * last message, INF means last message avaible 0563 * @return string|array if only one item of one message is fetched it's returned as string 0564 * if items of one message are fetched it's returned as (name => value) 0565 * if one items of messages are fetched it's returned as (msgno => value) 0566 * if items of messages are fetchted it's returned as (msgno => (name => value)) 0567 * @throws Zend_Mail_Protocol_Exception 0568 */ 0569 public function fetch($items, $from, $to = null) 0570 { 0571 if (is_array($from)) { 0572 $set = implode(',', $from); 0573 } else if ($to === null) { 0574 $set = (int)$from; 0575 } else if ($to === INF) { 0576 $set = (int)$from . ':*'; 0577 } else { 0578 $set = (int)$from . ':' . (int)$to; 0579 } 0580 0581 $items = (array)$items; 0582 $itemList = $this->escapeList($items); 0583 0584 $this->sendRequest('FETCH', array($set, $itemList), $tag); 0585 0586 $result = array(); 0587 while (!$this->readLine($tokens, $tag)) { 0588 // ignore other responses 0589 if ($tokens[1] != 'FETCH') { 0590 continue; 0591 } 0592 // ignore other messages 0593 if ($to === null && !is_array($from) && $tokens[0] != $from) { 0594 continue; 0595 } 0596 // if we only want one item we return that one directly 0597 if (count($items) == 1) { 0598 if ($tokens[2][0] == $items[0]) { 0599 $data = $tokens[2][1]; 0600 } else { 0601 // maybe the server send an other field we didn't wanted 0602 $count = count($tokens[2]); 0603 // we start with 2, because 0 was already checked 0604 for ($i = 2; $i < $count; $i += 2) { 0605 if ($tokens[2][$i] != $items[0]) { 0606 continue; 0607 } 0608 $data = $tokens[2][$i + 1]; 0609 break; 0610 } 0611 } 0612 } else { 0613 $data = array(); 0614 while (key($tokens[2]) !== null) { 0615 $data[current($tokens[2])] = next($tokens[2]); 0616 next($tokens[2]); 0617 } 0618 } 0619 // if we want only one message we can ignore everything else and just return 0620 if ($to === null && !is_array($from) && $tokens[0] == $from) { 0621 // we still need to read all lines 0622 while (!$this->readLine($tokens, $tag)); 0623 return $data; 0624 } 0625 $result[$tokens[0]] = $data; 0626 } 0627 0628 if ($to === null && !is_array($from)) { 0629 /** 0630 * @see Zend_Mail_Protocol_Exception 0631 */ 0632 // require_once 'Zend/Mail/Protocol/Exception.php'; 0633 throw new Zend_Mail_Protocol_Exception('the single id was not found in response'); 0634 } 0635 0636 return $result; 0637 } 0638 0639 /** 0640 * get mailbox list 0641 * 0642 * this method can't be named after the IMAP command 'LIST', as list is a reserved keyword 0643 * 0644 * @param string $reference mailbox reference for list 0645 * @param string $mailbox mailbox name match with wildcards 0646 * @return array mailboxes that matched $mailbox as array(globalName => array('delim' => .., 'flags' => ..)) 0647 * @throws Zend_Mail_Protocol_Exception 0648 */ 0649 public function listMailbox($reference = '', $mailbox = '*') 0650 { 0651 $result = array(); 0652 $list = $this->requestAndResponse('LIST', $this->escapeString($reference, $mailbox)); 0653 if (!$list || $list === true) { 0654 return $result; 0655 } 0656 0657 foreach ($list as $item) { 0658 if (count($item) != 4 || $item[0] != 'LIST') { 0659 continue; 0660 } 0661 $result[$item[3]] = array('delim' => $item[2], 'flags' => $item[1]); 0662 } 0663 0664 return $result; 0665 } 0666 0667 /** 0668 * set flags 0669 * 0670 * @param array $flags flags to set, add or remove - see $mode 0671 * @param int $from message for items or start message if $to !== null 0672 * @param int|null $to if null only one message ($from) is fetched, else it's the 0673 * last message, INF means last message avaible 0674 * @param string|null $mode '+' to add flags, '-' to remove flags, everything else sets the flags as given 0675 * @param bool $silent if false the return values are the new flags for the wanted messages 0676 * @return bool|array new flags if $silent is false, else true or false depending on success 0677 * @throws Zend_Mail_Protocol_Exception 0678 */ 0679 public function store(array $flags, $from, $to = null, $mode = null, $silent = true) 0680 { 0681 $item = 'FLAGS'; 0682 if ($mode == '+' || $mode == '-') { 0683 $item = $mode . $item; 0684 } 0685 if ($silent) { 0686 $item .= '.SILENT'; 0687 } 0688 0689 $flags = $this->escapeList($flags); 0690 $set = (int)$from; 0691 if ($to != null) { 0692 $set .= ':' . ($to == INF ? '*' : (int)$to); 0693 } 0694 0695 $result = $this->requestAndResponse('STORE', array($set, $item, $flags), $silent); 0696 0697 if ($silent) { 0698 return $result ? true : false; 0699 } 0700 0701 $tokens = $result; 0702 $result = array(); 0703 foreach ($tokens as $token) { 0704 if ($token[1] != 'FETCH' || $token[2][0] != 'FLAGS') { 0705 continue; 0706 } 0707 $result[$token[0]] = $token[2][1]; 0708 } 0709 0710 return $result; 0711 } 0712 0713 /** 0714 * append a new message to given folder 0715 * 0716 * @param string $folder name of target folder 0717 * @param string $message full message content 0718 * @param array $flags flags for new message 0719 * @param string $date date for new message 0720 * @return bool success 0721 * @throws Zend_Mail_Protocol_Exception 0722 */ 0723 public function append($folder, $message, $flags = null, $date = null) 0724 { 0725 $tokens = array(); 0726 $tokens[] = $this->escapeString($folder); 0727 if ($flags !== null) { 0728 $tokens[] = $this->escapeList($flags); 0729 } 0730 if ($date !== null) { 0731 $tokens[] = $this->escapeString($date); 0732 } 0733 $tokens[] = $this->escapeString($message); 0734 0735 return $this->requestAndResponse('APPEND', $tokens, true); 0736 } 0737 0738 /** 0739 * copy message set from current folder to other folder 0740 * 0741 * @param string $folder destination folder 0742 * @param int|null $to if null only one message ($from) is fetched, else it's the 0743 * last message, INF means last message avaible 0744 * @return bool success 0745 * @throws Zend_Mail_Protocol_Exception 0746 */ 0747 public function copy($folder, $from, $to = null) 0748 { 0749 $set = (int)$from; 0750 if ($to != null) { 0751 $set .= ':' . ($to == INF ? '*' : (int)$to); 0752 } 0753 0754 return $this->requestAndResponse('COPY', array($set, $this->escapeString($folder)), true); 0755 } 0756 0757 /** 0758 * create a new folder (and parent folders if needed) 0759 * 0760 * @param string $folder folder name 0761 * @return bool success 0762 */ 0763 public function create($folder) 0764 { 0765 return $this->requestAndResponse('CREATE', array($this->escapeString($folder)), true); 0766 } 0767 0768 /** 0769 * rename an existing folder 0770 * 0771 * @param string $old old name 0772 * @param string $new new name 0773 * @return bool success 0774 */ 0775 public function rename($old, $new) 0776 { 0777 return $this->requestAndResponse('RENAME', $this->escapeString($old, $new), true); 0778 } 0779 0780 /** 0781 * remove a folder 0782 * 0783 * @param string $folder folder name 0784 * @return bool success 0785 */ 0786 public function delete($folder) 0787 { 0788 return $this->requestAndResponse('DELETE', array($this->escapeString($folder)), true); 0789 } 0790 0791 /** 0792 * permanently remove messages 0793 * 0794 * @return bool success 0795 */ 0796 public function expunge() 0797 { 0798 // TODO: parse response? 0799 return $this->requestAndResponse('EXPUNGE'); 0800 } 0801 0802 /** 0803 * send noop 0804 * 0805 * @return bool success 0806 */ 0807 public function noop() 0808 { 0809 // TODO: parse response 0810 return $this->requestAndResponse('NOOP'); 0811 } 0812 0813 /** 0814 * do a search request 0815 * 0816 * This method is currently marked as internal as the API might change and is not 0817 * safe if you don't take precautions. 0818 * 0819 * @internal 0820 * @return array message ids 0821 */ 0822 public function search(array $params) 0823 { 0824 $response = $this->requestAndResponse('SEARCH', $params); 0825 if (!$response) { 0826 return $response; 0827 } 0828 0829 foreach ($response as $ids) { 0830 if ($ids[0] == 'SEARCH') { 0831 array_shift($ids); 0832 return $ids; 0833 } 0834 } 0835 return array(); 0836 } 0837 0838 }