/** * Public constructor * * In addition to the parameters of Part::__construct() this constructor supports: * - file filename or file handle of a file with raw message content * - flags array with flags for message, keys are ignored, use constants defined in \Zend\Mail\Storage * * @param array $params * @throws Exception\RuntimeException */ public function __construct(array $params) { if (isset($params['file'])) { if (!is_resource($params['file'])) { ErrorHandler::start(); $params['raw'] = file_get_contents($params['file']); $error = ErrorHandler::stop(); if ($params['raw'] === false) { throw new Exception\RuntimeException('could not open file', 0, $error); } } else { $params['raw'] = stream_get_contents($params['file']); } } if (!empty($params['flags'])) { // set key and value to the same value for easy lookup $this->flags = array_combine($params['flags'], $params['flags']); } parent::__construct($params); }
/** * Open connection to IMAP server * * @param string $host hostname or IP address of IMAP server * @param int|null $port of IMAP server, default is 143 (993 for ssl) * @param string|bool $ssl use 'SSL', 'TLS' or false * @throws Exception\RuntimeException * @return string welcome message */ public function connect($host, $port = null, $ssl = false) { $isTls = false; if ($ssl) { $ssl = strtolower($ssl); } switch ($ssl) { case 'ssl': $host = 'ssl://' . $host; if (!$port) { $port = 993; } break; case 'tls': $isTls = true; // break intentionally omitted // break intentionally omitted default: if (!$port) { $port = 143; } } ErrorHandler::start(); $this->socket = fsockopen($host, $port, $errno, $errstr, self::TIMEOUT_CONNECTION); $error = ErrorHandler::stop(); if (!$this->socket) { throw new Exception\RuntimeException(sprintf('cannot connect to host %s', $error ? sprintf('; error = %s (errno = %d )', $error->getMessage(), $error->getCode()) : ''), 0, $error); } if (!$this->_assumedNextLine('* OK')) { throw new Exception\RuntimeException('host doesn\'t allow connection'); } if ($isTls) { $result = $this->requestAndResponse('STARTTLS'); $result = $result && stream_socket_enable_crypto($this->socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT); if (!$result) { throw new Exception\RuntimeException('cannot enable TLS'); } } }
/** * get currently set quota * * @see \Zend\Mail\Storage\Writable\Maildir::setQuota() * @param bool $fromStorage * @throws \Zend\Mail\Storage\Exception\RuntimeException * @return bool|array */ public function getQuota($fromStorage = false) { if ($fromStorage) { ErrorHandler::start(E_WARNING); $fh = fopen($this->rootdir . 'maildirsize', 'r'); $error = ErrorHandler::stop(); if (!$fh) { throw new StorageException\RuntimeException('cannot open maildirsize', 0, $error); } $definition = fgets($fh); fclose($fh); $definition = explode(',', trim($definition)); $quota = array(); foreach ($definition as $member) { $key = $member[strlen($member) - 1]; if ($key == 'S' || $key == 'C') { $key = $key == 'C' ? 'count' : 'size'; } $quota[$key] = substr($member, 0, -1); } return $quota; } return $this->quota; }
/** * read a response * * @param bool $multiline response has multiple lines and should be read until "<nl>.<nl>" * @throws Exception\RuntimeException * @return string response */ public function readResponse($multiline = false) { ErrorHandler::start(); $result = fgets($this->socket); $error = ErrorHandler::stop(); if (!is_string($result)) { throw new Exception\RuntimeException('read failed - connection closed?', 0, $error); } $result = trim($result); if (strpos($result, ' ')) { list($status, $message) = explode(' ', $result, 2); } else { $status = $result; $message = ''; } if ($status != '+OK') { throw new Exception\RuntimeException('last request failed'); } if ($multiline) { $message = ''; $line = fgets($this->socket); while ($line && rtrim($line, "\r\n") != '.') { if ($line[0] == '.') { $line = substr($line, 1); } $message .= $line; $line = fgets($this->socket); } } return $message; }
/** * get root folder or given folder * * @param string $rootFolder get folder structure for given folder, else root * @throws \Zend\Mail\Storage\Exception\InvalidArgumentException * @return \Zend\Mail\Storage\Folder root or wanted folder */ public function getFolders($rootFolder = null) { if (!$rootFolder || $rootFolder == 'INBOX') { return $this->rootFolder; } // rootdir is same as INBOX in maildir if (strpos($rootFolder, 'INBOX' . $this->delim) === 0) { $rootFolder = substr($rootFolder, 6); } $currentFolder = $this->rootFolder; $subname = trim($rootFolder, $this->delim); while ($currentFolder) { ErrorHandler::start(E_NOTICE); list($entry, $subname) = explode($this->delim, $subname, 2); ErrorHandler::stop(); $currentFolder = $currentFolder->{$entry}; if (!$subname) { break; } } if ($currentFolder->getGlobalName() != rtrim($rootFolder, $this->delim)) { throw new Exception\InvalidArgumentException("folder {$rootFolder} not found"); } return $currentFolder; }
/** * get root folder or given folder * * @param string $rootFolder get folder structure for given folder, else root * @throws \Zend\Mail\Storage\Exception\InvalidArgumentException * @return \Zend\Mail\Storage\Folder root or wanted folder */ public function getFolders($rootFolder = null) { if (!$rootFolder) { return $this->rootFolder; } $currentFolder = $this->rootFolder; $subname = trim($rootFolder, DIRECTORY_SEPARATOR); while ($currentFolder) { ErrorHandler::start(E_NOTICE); list($entry, $subname) = explode(DIRECTORY_SEPARATOR, $subname, 2); ErrorHandler::stop(); $currentFolder = $currentFolder->{$entry}; if (!$subname) { break; } } if ($currentFolder->getGlobalName() != DIRECTORY_SEPARATOR . trim($rootFolder, DIRECTORY_SEPARATOR)) { throw new Exception\InvalidArgumentException("folder {$rootFolder} not found"); } return $currentFolder; }
/** * split a message in header and body part, if no header or an * invalid header is found $headers is empty * * The charset of the returned headers depend on your iconv settings. * * @param string|Headers $message raw message with header and optional content * @param Headers $headers output param, headers container * @param string $body output param, content of message * @param string $EOL EOL string; defaults to {@link Zend\Mime\Mime::LINEEND} * @param bool $strict enable strict mode for parsing message * @return null */ public static function splitMessage($message, &$headers, &$body, $EOL = Mime::LINEEND, $strict = false) { if ($message instanceof Headers) { $message = $message->toString(); } // check for valid header at first line $firstline = strtok($message, "\n"); if (!preg_match('%^[^\\s]+[^:]*:%', $firstline)) { $headers = array(); // TODO: we're ignoring \r for now - is this function fast enough and is it safe to assume noone needs \r? $body = str_replace(array("\r", "\n"), array('', $EOL), $message); return; } // see @ZF2-372, pops the first line off a message if it doesn't contain a header if (!$strict) { $parts = explode(':', $firstline, 2); if (count($parts) != 2) { $message = substr($message, strpos($message, $EOL) + 1); } } // find an empty line between headers and body // default is set new line if (strpos($message, $EOL . $EOL)) { list($headers, $body) = explode($EOL . $EOL, $message, 2); // next is the standard new line } elseif ($EOL != "\r\n" && strpos($message, "\r\n\r\n")) { list($headers, $body) = explode("\r\n\r\n", $message, 2); // next is the other "standard" new line } elseif ($EOL != "\n" && strpos($message, "\n\n")) { list($headers, $body) = explode("\n\n", $message, 2); // at last resort find anything that looks like a new line } else { ErrorHandler::start(E_NOTICE | E_WARNING); list($headers, $body) = preg_split("%([\r\n]+)\\1%U", $message, 2); ErrorHandler::stop(); } $headers = Headers::fromString($headers, $EOL); }
/** * magic method for unserialize() * * with this method you can cache the mbox class * for cache validation the mtime of the mbox file is used * * @throws Exception\RuntimeException */ public function __wakeup() { ErrorHandler::start(); $filemtime = filemtime($this->filename); ErrorHandler::stop(); if ($this->filemtime != $filemtime) { $this->close(); $this->openMboxFile($this->filename); } else { ErrorHandler::start(); $this->fh = fopen($this->filename, 'r'); $error = ErrorHandler::stop(); if (!$this->fh) { throw new Exception\RuntimeException('cannot open mbox file', 0, $error); } } }
/** * find all files in opened dir handle and add to maildir files * * @param resource $dh dir handle used for search * @param string $dirname dirname of dir in $dh * @param array $defaultFlags default flags for given dir */ protected function _getMaildirFiles($dh, $dirname, $defaultFlags = array()) { while (($entry = readdir($dh)) !== false) { if ($entry[0] == '.' || !is_file($dirname . $entry)) { continue; } ErrorHandler::start(E_NOTICE); list($uniq, $info) = explode(':', $entry, 2); list(, $size) = explode(',', $uniq, 2); ErrorHandler::stop(); if ($size && $size[0] == 'S' && $size[1] == '=') { $size = substr($size, 2); } if (!ctype_digit($size)) { $size = null; } ErrorHandler::start(E_NOTICE); list($version, $flags) = explode(',', $info, 2); ErrorHandler::stop(); if ($version != 2) { $flags = ''; } $namedFlags = $defaultFlags; $length = strlen($flags); for ($i = 0; $i < $length; ++$i) { $flag = $flags[$i]; $namedFlags[$flag] = isset(static::$knownFlags[$flag]) ? static::$knownFlags[$flag] : $flag; } $data = array('uniq' => $uniq, 'flags' => $namedFlags, 'flaglookup' => array_flip($namedFlags), 'filename' => $dirname . $entry); if ($size !== null) { $data['size'] = (int) $size; } $this->files[] = $data; } }