📄 maildir.php
字号:
$olddir = $this->_rootdir . '.' . $folder; foreach (array('tmp', 'new', 'cur') as $subdir) { $subdir = DIRECTORY_SEPARATOR . $subdir; if (!file_exists($olddir . $subdir)) { continue; } // using copy or moving files would be even better - but also much slower if (!rename($olddir . $subdir, $newdir . $subdir)) { /** * @see Zend_Mail_Storage_Exception */ require_once 'Zend/Mail/Storage/Exception.php'; throw new Zend_Mail_Storage_Exception('error while moving ' . $subdir); } } // create a dummy if removing fails - otherwise we can't read it next time mkdir($olddir . DIRECTORY_SEPARATOR . 'cur'); $this->removeFolder($oldName); } /** * create a uniqueid for maildir filename * * This is nearly the format defined in the maildir standard. The microtime() call should already * create a uniqueid, the pid is for multicore/-cpu machine that manage to call this function at the * exact same time, and uname() gives us the hostname for multiple machines accessing the same storage. * * If someone disables posix we create a random number of the same size, so this method should also * work on Windows - if you manage to get maildir working on Windows. * Microtime could also be disabled, altough I've never seen it. * * @return string new uniqueid */ protected function _createUniqueId() { $id = ''; $id .= function_exists('microtime') ? microtime(true) : (time() . ' ' . rand(0, 100000)); $id .= '.' . (function_exists('posix_getpid') ? posix_getpid() : rand(50, 65535)); $id .= '.' . php_uname('n'); return $id; } /** * open a temporary maildir file * * makes sure tmp/ exists and create a file with a unique name * you should close the returned filehandle! * * @param string $folder name of current folder without leading . * @return array array('dirname' => dir of maildir folder, 'uniq' => unique id, 'filename' => name of create file * 'handle' => file opened for writing) * @throws Zend_Mail_Storage_Exception */ protected function _createTmpFile($folder = 'INBOX') { if ($folder == 'INBOX') { $tmpdir = $this->_rootdir . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR; } else { $tmpdir = $this->_rootdir . '.' . $folder . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR; } if (!file_exists($tmpdir)) { if (!mkdir($tmpdir)) { /** * @see Zend_Mail_Storage_Exception */ require_once 'Zend/Mail/Storage/Exception.php'; throw new Zend_Mail_Storage_Exception('problems creating tmp dir'); } } // we should retry to create a unique id if a file with the same name exists // to avoid a script timeout we only wait 1 second (instead of 2) and stop // after a defined retry count // if you change this variable take into account that it can take up to $max_tries seconds // normally we should have a valid unique name after the first try, we're just following the "standard" here $max_tries = 5; for ($i = 0; $i < $max_tries; ++$i) { $uniq = $this->_createUniqueId(); if (!file_exists($tmpdir . $uniq)) { // here is the race condition! - as defined in the standard // to avoid having a long time between stat()ing the file and creating it we're opening it here // to mark the filename as taken $fh = fopen($tmpdir . $uniq, 'w'); if (!$fh) { /** * @see Zend_Mail_Storage_Exception */ require_once 'Zend/Mail/Storage/Exception.php'; throw new Zend_Mail_Storage_Exception('could not open temp file'); } break; } sleep(1); } if (!$fh) { /** * @see Zend_Mail_Storage_Exception */ require_once 'Zend/Mail/Storage/Exception.php'; throw new Zend_Mail_Storage_Exception("tried $max_tries unique ids for a temp file, but all were taken" . ' - giving up'); } return array('dirname' => $this->_rootdir . '.' . $folder, 'uniq' => $uniq, 'filename' => $tmpdir . $uniq, 'handle' => $fh); } /** * create an info string for filenames with given flags * * @param array $flags wanted flags, with the reference you'll get the set flags with correct key (= char for flag) * @return string info string for version 2 filenames including the leading colon * @throws Zend_Mail_Storage_Exception */ protected function _getInfoString(&$flags) { // accessing keys is easier, faster and it removes duplicated flags $wanted_flags = array_flip($flags); if (isset($wanted_flags[Zend_Mail_Storage::FLAG_RECENT])) { /** * @see Zend_Mail_Storage_Exception */ require_once 'Zend/Mail/Storage/Exception.php'; throw new Zend_Mail_Storage_Exception('recent flag may not be set'); } $info = ':2,'; $flags = array(); foreach (Zend_Mail_Storage_Maildir::$_knownFlags as $char => $flag) { if (!isset($wanted_flags[$flag])) { continue; } $info .= $char; $flags[$char] = $flag; unset($wanted_flags[$flag]); } if (!empty($wanted_flags)) { $wanted_flags = implode(', ', array_keys($wanted_flags)); /** * @see Zend_Mail_Storage_Exception */ require_once 'Zend/Mail/Storage/Exception.php'; throw new Zend_Mail_Storage_Exception('unknown flag(s): ' . $wanted_flags); } return $info; } /** * append a new message to mail storage * * @param string|stream $message message as string or stream resource * @param null|string|Zend_Mail_Storage_Folder $folder folder for new message, else current folder is taken * @param null|array $flags set flags for new message, else a default set is used * @param bool $recent handle this mail as if recent flag has been set, * should only be used in delivery * @throws Zend_Mail_Storage_Exception */ // not yet * @param string|Zend_Mail_Message|Zend_Mime_Message $message message as string or instance of message class public function appendMessage($message, $folder = null, $flags = null, $recent = false) { if ($this->_quota && $this->checkQuota()) { /** * @see Zend_Mail_Storage_Exception */ require_once 'Zend/Mail/Storage/Exception.php'; throw new Zend_Mail_Storage_Exception('storage is over quota!'); } if ($folder === null) { $folder = $this->_currentFolder; } if (!($folder instanceof Zend_Mail_Storage_Folder)) { $folder = $this->getFolders($folder); } if ($flags === null) { $flags = array(Zend_Mail_Storage::FLAG_SEEN); } $info = $this->_getInfoString($flags); $temp_file = $this->_createTmpFile($folder->getGlobalName()); // TODO: handle class instances for $message if (is_resource($message) && get_resource_type($message) == 'stream') { stream_copy_to_stream($message, $temp_file['handle']); } else { fputs($temp_file['handle'], $message); } fclose($temp_file['handle']); // we're adding the size to the filename for maildir++ $size = filesize($temp_file['filename']); if ($size) { $info = ',S=' . $size . $info; } $new_filename = $temp_file['dirname'] . DIRECTORY_SEPARATOR; $new_filename .= $recent ? 'new' : 'cur'; $new_filename .= DIRECTORY_SEPARATOR . $temp_file['uniq'] . $info; // we're throwing any exception after removing our temp file and saving it to this variable instead $exception = null; if (!link($temp_file['filename'], $new_filename)) { /** * @see Zend_Mail_Storage_Exception */ require_once 'Zend/Mail/Storage/Exception.php'; $exception = new Zend_Mail_Storage_Exception('cannot link message file to final dir'); } @unlink($temp_file['filename']); if ($exception) { throw $exception; } $this->_files[] = array('uniq' => $temp_file['uniq'], 'flags' => $flags, 'filename' => $new_filename); if ($this->_quota) { $this->_addQuotaEntry((int)$size, 1); } } /** * copy an existing message * * @param int $id number of message * @param string|Zend_Mail_Storage_Folder $folder name or instance of targer folder * @return null * @throws Zend_Mail_Storage_Exception */ public function copyMessage($id, $folder) { if ($this->_quota && $this->checkQuota()) { /** * @see Zend_Mail_Storage_Exception */ require_once 'Zend/Mail/Storage/Exception.php'; throw new Zend_Mail_Storage_Exception('storage is over quota!'); } if (!($folder instanceof Zend_Mail_Storage_Folder)) { $folder = $this->getFolders($folder); } $filedata = $this->_getFileData($id); $old_file = $filedata['filename']; $flags = $filedata['flags']; // copied message can't be recent while (($key = array_search(Zend_Mail_Storage::FLAG_RECENT, $flags)) !== false) { unset($flags[$key]); } $info = $this->_getInfoString($flags); // we're creating the copy as temp file before moving to cur/ $temp_file = $this->_createTmpFile($folder->getGlobalName()); // we don't write directly to the file fclose($temp_file['handle']); // we're adding the size to the filename for maildir++ // TODO: maybe we should support maildirsize or we just let the MDA do the work $size = filesize($old_file); if ($size) { $info = ',S=' . $size . $info; } $new_file = $temp_file['dirname'] . DIRECTORY_SEPARATOR . 'cur' . DIRECTORY_SEPARATOR . $temp_file['uniq'] . $info; // we're throwing any exception after removing our temp file and saving it to this variable instead $exception = null; if (!copy($old_file, $temp_file['filename'])) { /** * @see Zend_Mail_Storage_Exception */ require_once 'Zend/Mail/Storage/Exception.php'; $exception = new Zend_Mail_Storage_Exception('cannot copy message file'); } else if (!link($temp_file['filename'], $new_file)) { /** * @see Zend_Mail_Storage_Exception */ require_once 'Zend/Mail/Storage/Exception.php'; $exception = new Zend_Mail_Storage_Exception('cannot link message file to final dir'); } @unlink($temp_file['filename']); if ($exception) { throw $exception; } if ($folder->getGlobalName() == $this->_currentFolder || ($this->_currentFolder == 'INBOX' && $folder->getGlobalName() == '/')) { $this->_files[] = array('uniq' => $temp_file['uniq'], 'flags' => $flags, 'filename' => $new_file); } if ($this->_quota) { $this->_addQuotaEntry((int)$size, 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -