📄 couriermaildirformat.cpp
字号:
//// VMime library (http://www.vmime.org)// Copyright (C) 2002-2008 Vincent Richard <vincent@vincent-richard.net>//// This program is free software; you can redistribute it and/or// modify it under the terms of the GNU General Public License as// published by the Free Software Foundation; either version 2 of// the License, or (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU// General Public License for more details.//// You should have received a copy of the GNU General Public License along// with this program; if not, write to the Free Software Foundation, Inc.,// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.//// Linking this library statically or dynamically with other modules is making// a combined work based on this library. Thus, the terms and conditions of// the GNU General Public License cover the whole combination.//#include "vmime/net/maildir/format/courierMaildirFormat.hpp"#include "vmime/net/maildir/maildirStore.hpp"#include "vmime/net/maildir/maildirUtils.hpp"#include "vmime/platform.hpp"namespace vmime {namespace net {namespace maildir {namespace format {courierMaildirFormat::courierMaildirFormat(ref <context> ctx) : maildirFormat(ctx){}const string courierMaildirFormat::getName() const{ return "courier";}void courierMaildirFormat::createFolder(const folder::path& path){ utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); if (!fsf->isValidPath(folderPathToFileSystemPath(path, ROOT_DIRECTORY))) throw exceptions::invalid_folder_name(); ref <utility::file> rootDir = fsf->create (folderPathToFileSystemPath(path, ROOT_DIRECTORY)); ref <utility::file> newDir = fsf->create (folderPathToFileSystemPath(path, NEW_DIRECTORY)); ref <utility::file> tmpDir = fsf->create (folderPathToFileSystemPath(path, TMP_DIRECTORY)); ref <utility::file> curDir = fsf->create (folderPathToFileSystemPath(path, CUR_DIRECTORY)); rootDir->createDirectory(true); newDir->createDirectory(false); tmpDir->createDirectory(false); curDir->createDirectory(false); ref <utility::file> maildirFile = fsf->create (folderPathToFileSystemPath(path, ROOT_DIRECTORY) / utility::file::path::component("maildirfolder")); maildirFile->createFile();}void courierMaildirFormat::destroyFolder(const folder::path& path){ utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); // Recursively delete directories of subfolders const std::vector <folder::path> folders = listFolders(path, true); for (unsigned int i = 0, n = folders.size() ; i < n ; ++i) { maildirUtils::recursiveFSDelete(fsf->create (folderPathToFileSystemPath(folders[i], ROOT_DIRECTORY))); } // Recursively delete the directory of this folder maildirUtils::recursiveFSDelete(fsf->create (folderPathToFileSystemPath(path, ROOT_DIRECTORY)));}void courierMaildirFormat::renameFolder (const folder::path& oldPath, const folder::path& newPath){ const std::vector <folder::path> folders = listFolders(oldPath, true); for (unsigned int i = 0, n = folders.size() ; i < n ; ++i) { const folder::path folderOldPath = folders[i]; folder::path folderNewPath = folderOldPath; folderNewPath.renameParent(oldPath, newPath); renameFolderImpl(folderOldPath, folderNewPath); } renameFolderImpl(oldPath, newPath);}void courierMaildirFormat::renameFolderImpl (const folder::path& oldPath, const folder::path& newPath){ utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); const utility::file::path oldFSPath = folderPathToFileSystemPath(oldPath, ROOT_DIRECTORY); const utility::file::path newFSPath = folderPathToFileSystemPath(newPath, ROOT_DIRECTORY); ref <utility::file> rootDir = fsf->create(oldFSPath); rootDir->rename(newFSPath);}bool courierMaildirFormat::folderExists(const folder::path& path) const{ utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); ref <utility::file> rootDir = fsf->create (folderPathToFileSystemPath(path, ROOT_DIRECTORY)); ref <utility::file> newDir = fsf->create (folderPathToFileSystemPath(path, NEW_DIRECTORY)); ref <utility::file> tmpDir = fsf->create (folderPathToFileSystemPath(path, TMP_DIRECTORY)); ref <utility::file> curDir = fsf->create (folderPathToFileSystemPath(path, CUR_DIRECTORY)); ref <utility::file> maildirFile = fsf->create (folderPathToFileSystemPath(path, ROOT_DIRECTORY) / utility::file::path::component("maildirfolder")); bool exists = rootDir->exists() && rootDir->isDirectory() && newDir->exists() && newDir->isDirectory() && tmpDir->exists() && tmpDir->isDirectory() && curDir->exists() && curDir->isDirectory(); // If this is not the root folder, then a file named "maildirfolder" // must also be present in the directory if (!path.isRoot()) exists = exists && maildirFile->exists() && maildirFile->isFile(); return exists;}bool courierMaildirFormat::folderHasSubfolders(const folder::path& path) const{ std::vector <string> dirs; return listDirectories(path, dirs, true);}const utility::file::path courierMaildirFormat::folderPathToFileSystemPath (const folder::path& path, const DirectoryType type) const{ // Virtual folder "/MyFolder/SubFolder" corresponds to physical // directory "[store root]/.MyFolder.SubFolder" utility::file::path fsPath = getContext()->getStore()->getFileSystemPath(); if (!path.isRoot()) { string folderComp; for (int i = 0, n = path.getSize() ; i < n ; ++i) folderComp += "." + toModifiedUTF7(path[i]); fsPath /= utility::file::path::component(folderComp); } // Last component switch (type) { case ROOT_DIRECTORY: // Nothing to add break; case NEW_DIRECTORY: fsPath /= NEW_DIR; break; case CUR_DIRECTORY: fsPath /= CUR_DIR; break; case TMP_DIRECTORY: fsPath /= TMP_DIR; break; case CONTAINER_DIRECTORY: // Not used break; } return fsPath;}const std::vector <folder::path> courierMaildirFormat::listFolders (const folder::path& root, const bool recursive) const{ // First, list directories std::vector <string> dirs; listDirectories(root, dirs, false); // Then, map directories to folders std::vector <folder::path> folders; for (unsigned int i = 0, n = dirs.size() ; i < n ; ++i) { const string dir = dirs[i].substr(1) + "."; folder::path path; for (string::size_type pos = dir.find("."), prev = 0 ; pos != string::npos ; prev = pos + 1, pos = dir.find(".", pos + 1)) { const string comp = dir.substr(prev, pos - prev); path /= fromModifiedUTF7(comp); } if (recursive || path.getSize() == root.getSize() + 1) folders.push_back(path); } return folders;}bool courierMaildirFormat::listDirectories(const folder::path& root, std::vector <string>& dirs, const bool onlyTestForExistence) const{ utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); ref <utility::file> rootDir = fsf->create (getContext()->getStore()->getFileSystemPath()); if (rootDir->exists()) { // To speed up things, and if we are not searching in root folder, // search for directories with a common prefix string base; if (!root.isRoot()) { for (int i = 0, n = root.getSize() ; i < n ; ++i) base += "." + toModifiedUTF7(root[i]); } // Enumerate directories ref <utility::fileIterator> it = rootDir->getFiles(); while (it->hasMoreElements()) { ref <utility::file> file = it->nextElement(); if (isSubfolderDirectory(*file)) { const string dir = file->getFullPath().getLastComponent().getBuffer(); if (base.empty() || (dir.length() > base.length() && dir.substr(0, base.length()) == base)) { dirs.push_back(dir); if (onlyTestForExistence) return true; } } } } else { // No sub-folder } std::sort(dirs.begin(), dirs.end()); return !dirs.empty();}// staticbool courierMaildirFormat::isSubfolderDirectory(const utility::file& file){ // A directory which names starts with '.' may be a subfolder if (file.isDirectory() && file.getFullPath().getLastComponent().getBuffer().length() >= 1 && file.getFullPath().getLastComponent().getBuffer()[0] == '.') { return true; } return false;}// staticconst string courierMaildirFormat::toModifiedUTF7(const folder::path::component& text){ // From http://www.courier-mta.org/?maildir.html: // // Folder names can contain any Unicode character, except for control // characters. US-ASCII characters, U+0x0020 - U+0x007F, except for the // period, forward-slash, and ampersand characters (U+0x002E, U+0x002F, // and U+0x0026) represent themselves. The ampersand is represented by // the two character sequence "&-". The period, forward slash, and non // US-ASCII Unicode characters are represented using the UTF-7 character // set, and encoded with a modified form of base64-encoding. // // The "&" character starts the modified base64-encoded sequence; the // sequence is terminated by the "-" character. The sequence of 16-bit // Unicode characters is written in big-endian order, and encoded using // the base64-encoding method described in section 5.2 of RFC 1521, with // the following modifications: // // * The "=" padding character is omitted. When decoding, an incomplete // 16-bit character is discarded. // // * The comma character, "," is used in place of the "/" character in // the base64 alphabet. // // For example, the word "Resume" with both "e"s being the e-acute // character, U+0x00e9, is encoded as "R&AOk-sum&AOk-" (so a folder of // that name would be a maildir subdirectory called ".R&AOk-sum&AOk-"). // // Transcode path component to UTF-7 charset. // WARNING: This may throw "exceptions::charset_conv_error" const string cvt = text.getConvertedText(charset(charsets::UTF_7)); // Transcode to modified UTF-7 (RFC-2060). string out; out.reserve((cvt.length() * 3) / 2); bool inB64sequence = false; for (string::const_iterator it = cvt.begin() ; it != cvt.end() ; ++it) { const unsigned char c = *it; switch (c) { // Beginning of Base64 sequence: replace '+' with '&' case '+': { if (!inB64sequence) { inB64sequence = true; out += '&'; } else { out += '+'; } break; } // End of Base64 sequence case '-': { inB64sequence = false; out += '-'; break; } // ',' is used instead of '/' in modified Base64, // and simply UTF7-encoded out of a Base64 sequence case '/': { if (inB64sequence) out += ','; else out += "&Lw-"; break; } // Encode period (should not happen in a Base64 sequence) case '.': { out += "&Lg-"; break; } // '&' (0x26) is represented by the two-octet sequence "&-" case '&': { if (!inB64sequence) out += "&-"; else out += '&'; break; } default: { out += c; break; } } } return out;}// staticconst folder::path::component courierMaildirFormat::fromModifiedUTF7(const string& text){ // Transcode from modified UTF-7 string out; out.reserve(text.length()); bool inB64sequence = false; unsigned char prev = 0; for (string::const_iterator it = text.begin() ; it != text.end() ; ++it) { const unsigned char c = *it; switch (c) { // Start of Base64 sequence case '&': { if (!inB64sequence) { inB64sequence = true; out += '+'; } else { out += '&'; } break; } // End of Base64 sequence (or "&-" --> "&") case '-': { if (inB64sequence && prev == '&') out += '&'; else out += '-'; inB64sequence = false; break; } // ',' is used instead of '/' in modified Base64 case ',': { out += (inB64sequence ? '/' : ','); break; } default: { out += c; break; } } prev = c; } // Store it as UTF-8 by default string cvt; charset::convert(out, cvt, charset(charsets::UTF_7), charset(charsets::UTF_8)); return (folder::path::component(cvt, charset(charsets::UTF_8)));}bool courierMaildirFormat::supports() const{ utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); ref <utility::file> rootDir = fsf->create (getContext()->getStore()->getFileSystemPath()); if (rootDir->exists()) { // Try to find a file named "maildirfolder", which indicates // the Maildir is in Courier format ref <utility::fileIterator> it = rootDir->getFiles(); while (it->hasMoreElements()) { ref <utility::file> file = it->nextElement(); if (isSubfolderDirectory(*file)) { ref <utility::file> folderFile = fsf->create (file->getFullPath() / utility::file::path::component("maildirfolder")); if (folderFile->exists() && folderFile->isFile()) return true; } } } return false;}} // format} // maildir} // net} // vmime
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -