📄 maildir.php
字号:
} } /** * set flags for message * * NOTE: this method can't set the recent flag. * * @param int $id number of message * @param array $flags new flags for message * @throws Zend_Mail_Storage_Exception */ public function setFlags($id, $flags) { $info = $this->_getInfoString($flags); $filedata = $this->_getFileData($id); // TODO: move file from new to cur $new_filename = dirname($filedata['filename']) . DIRECTORY_SEPARATOR . "$filedata[uniq]$info"; if (!@rename($filedata['filename'], $new_filename)) { /** * @see Zend_Mail_Storage_Exception */ require_once 'Zend/Mail/Storage/Exception.php'; throw new Zend_Mail_Storage_Exception('cannot rename file'); } $filedata['flags'] = $flags; $filedata['filename'] = $new_filename; $this->_files[$id - 1] = $filedata; } /** * stub for not supported message deletion * * @return null * @throws Zend_Mail_Storage_Exception */ public function removeMessage($id) { $filename = $this->_getFileData($id, 'filename'); if ($this->_quota) { $size = filesize($filename); } if (!@unlink($filename)) { /** * @see Zend_Mail_Storage_Exception */ require_once 'Zend/Mail/Storage/Exception.php'; throw new Zend_Mail_Storage_Exception('cannot remove message'); } unset($this->_files[$id - 1]); // remove the gap $this->_files = array_values($this->_files); if ($this->_quota) { $this->_addQuotaEntry(0 - (int)$size, -1); } } /** * enable/disable quota and set a quota value if wanted or needed * * You can enable/disable quota with true/false. If you don't have * a MDA or want to enforce a quota value you can also set this value * here. Use array('size' => SIZE_QUOTA, 'count' => MAX_MESSAGE) do * define your quota. Order of these fields does matter! * * @param bool|array $value new quota value * @return null */ public function setQuota($value) { $this->_quota = $value; } /** * get currently set quota * * @see Zend_Mail_Storage_Writable_Maildir::setQuota() * * @return bool|array */ public function getQuota($fromStorage = false) { if ($fromStorage) { $fh = @fopen($this->_rootdir . 'maildirsize', 'r'); if (!$fh) { /** * @see Zend_Mail_Storage_Exception */ require_once 'Zend/Mail/Storage/Exception.php'; throw new Zend_Mail_Storage_Exception('cannot open maildirsize'); } $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; } /** * @see http://www.inter7.com/courierimap/README.maildirquota.html "Calculating maildirsize" */ protected function _calculateMaildirsize() { $timestamps = array(); $messages = 0; $total_size = 0; if (is_array($this->_quota)) { $quota = $this->_quota; } else { try { $quota = $this->getQuota(true); } catch (Zend_Mail_Storage_Exception $e) { throw new Zend_Mail_Storage_Exception('no quota defintion found'); } } $folders = new RecursiveIteratorIterator($this->getFolders(), RecursiveIteratorIterator::SELF_FIRST); foreach ($folders as $folder) { $subdir = $folder->getGlobalName(); if ($subdir == 'INBOX') { $subdir = ''; } else { $subdir = '.' . $subdir; } if ($subdir == 'Trash') { continue; } foreach (array('cur', 'new') as $subsubdir) { $dirname = $this->_rootdir . $subdir . DIRECTORY_SEPARATOR . $subsubdir . DIRECTORY_SEPARATOR; if (!file_exists($dirname)) { continue; } // NOTE: we are using mtime instead of "the latest timestamp". The latest would be atime // and as we are accessing the directory it would make the whole calculation useless. $timestamps[$dirname] = filemtime($dirname); $dh = opendir($dirname); // NOTE: Should have been checked in constructor. Not throwing an exception here, quotas will // therefore not be fully enforeced, but next request will fail anyway, if problem persists. if (!$dh) { continue; } while (($entry = readdir()) !== false) { if ($entry[0] == '.' || !is_file($dirname . $entry)) { continue; } if (strpos($entry, ',S=')) { strtok($entry, '='); $filesize = strtok(':'); if (is_numeric($filesize)) { $total_size += $filesize; ++$messages; continue; } } $size = filesize($dirname . $entry); if ($size === false) { // ignore, as we assume file got removed continue; } $total_size += $size; ++$messages; } } } $tmp = $this->_createTmpFile(); $fh = $tmp['handle']; $definition = array(); foreach ($quota as $type => $value) { if ($type == 'size' || $type == 'count') { $type = $type == 'count' ? 'C' : 'S'; } $definition[] = $value . $type; } $definition = implode(',', $definition); fputs($fh, "$definition\n"); fputs($fh, "$total_size $messages\n"); fclose($fh); rename($tmp['filename'], $this->_rootdir . 'maildirsize'); foreach ($timestamps as $dir => $timestamp) { if ($timestamp < filemtime($dir)) { unlink($this->_rootdir . 'maildirsize'); break; } } return array('size' => $total_size, 'count' => $messages, 'quota' => $quota); } /** * @see http://www.inter7.com/courierimap/README.maildirquota.html "Calculating the quota for a Maildir++" */ protected function _calculateQuota($forceRecalc = false) { $fh = null; $total_size = 0; $messages = 0; $maildirsize = ''; if (!$forceRecalc && file_exists($this->_rootdir . 'maildirsize') && filesize($this->_rootdir . 'maildirsize') < 5120) { $fh = fopen($this->_rootdir . 'maildirsize', 'r'); } if ($fh) { $maildirsize = fread($fh, 5120); if (strlen($maildirsize) >= 5120) { fclose($fh); $fh = null; $maildirsize = ''; } } if (!$fh) { $result = $this->_calculateMaildirsize(); $total_size = $result['size']; $messages = $result['count']; $quota = $result['quota']; } else { $maildirsize = explode("\n", $maildirsize); if (is_array($this->_quota)) { $quota = $this->_quota; } else { $definition = explode(',', $maildirsize[0]); $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); } } unset($maildirsize[0]); foreach ($maildirsize as $line) { list($size, $count) = explode(' ', trim($line)); $total_size += $size; $messages += $count; } } $over_quota = false; $over_quota = $over_quota || (isset($quota['size']) && $total_size > $quota['size']); $over_quota = $over_quota || (isset($quota['count']) && $messages > $quota['count']); // NOTE: $maildirsize equals false if it wasn't set (AKA we recalculated) or it's only // one line, because $maildirsize[0] gets unsetted. // Also we're using local time to calculate the 15 minute offset. Touching a file just for known the // local time of the file storage isn't worth the hassle. if ($over_quota && ($maildirsize || filemtime($this->_rootdir . 'maildirsize') > time() - 900)) { $result = $this->_calculateMaildirsize(); $total_size = $result['size']; $messages = $result['count']; $quota = $result['quota']; $over_quota = false; $over_quota = $over_quota || (isset($quota['size']) && $total_size > $quota['size']); $over_quota = $over_quota || (isset($quota['count']) && $messages > $quota['count']); } if ($fh) { // TODO is there a safe way to keep the handle open for writing? fclose($fh); } return array('size' => $total_size, 'count' => $messages, 'quota' => $quota, 'over_quota' => $over_quota); } protected function _addQuotaEntry($size, $count = 1) { if (!file_exists($this->_rootdir . 'maildirsize')) { // TODO: should get file handler from _calculateQuota } $size = (int)$size; $count = (int)$count; file_put_contents($this->_rootdir . 'maildirsize', "$size $count\n", FILE_APPEND); } /** * check if storage is currently over quota * * @param bool $detailedResponse return known data of quota and current size and message count @see _calculateQuota() * @return bool|array over quota state or detailed response */ public function checkQuota($detailedResponse = false, $forceRecalc = false) { $result = $this->_calculateQuota($forceRecalc); return $detailedResponse ? $result : $result['over_quota']; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -