// // VMime library (http://www.vmime.org) // Copyright (C) 2002-2013 Vincent Richard // // 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 3 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/config.hpp" #if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR #include "vmime/net/maildir/maildirUtils.hpp" #include "vmime/net/maildir/maildirStore.hpp" #include "vmime/utility/random.hpp" #include "vmime/platform.hpp" #include "vmime/exception.hpp" namespace vmime { namespace net { namespace maildir { bool maildirUtils::isMessageFile(const utility::file& file) { // Ignore files which name begins with '.' if (file.isFile() && file.getFullPath().getLastComponent().getBuffer().length() >= 1 && file.getFullPath().getLastComponent().getBuffer()[0] != '.') { return (true); } return (false); } // NOTE ABOUT ID/FLAGS SEPARATOR // ----------------------------- // In the maildir specification, the character ':' is used to separate // the unique identifier and the message flags. // // On Windows (and particularly FAT file systems), ':' is not allowed // in a filename, so we use a dash ('-') instead. This is the solution // used by Mutt/Win32, so we also use it here. // // To be compatible between implementations, we check for both // characters when reading file names. const utility::file::path::component maildirUtils::extractId (const utility::file::path::component& filename) { size_t sep = filename.getBuffer().rfind(':'); // try colon if (sep == string::npos) { sep = filename.getBuffer().rfind('-'); // try dash (Windows) if (sep == string::npos) return (filename); } return (utility::path::component (string(filename.getBuffer().begin(), filename.getBuffer().begin() + sep))); } int maildirUtils::extractFlags(const utility::file::path::component& comp) { size_t sep = comp.getBuffer().rfind(':'); // try colon if (sep == string::npos) { sep = comp.getBuffer().rfind('-'); // try dash (Windows) if (sep == string::npos) return 0; } const string flagsString(comp.getBuffer().begin() + sep + 1, comp.getBuffer().end()); const size_t count = flagsString.length(); int flags = 0; for (size_t i = 0 ; i < count ; ++i) { switch (flagsString[i]) { case 'R': case 'r': flags |= message::FLAG_REPLIED; break; case 'S': case 's': flags |= message::FLAG_SEEN; break; case 'T': case 't': flags |= message::FLAG_DELETED; break; case 'F': case 'f': flags |= message::FLAG_MARKED; break; case 'P': case 'p': flags |= message::FLAG_PASSED; break; case 'D': case 'd': flags |= message::FLAG_DRAFT; break; } } return (flags); } const utility::file::path::component maildirUtils::buildFlags(const int flags) { string str; str.reserve(8); str += "2,"; if (flags & message::FLAG_MARKED) str += "F"; if (flags & message::FLAG_PASSED) str += "P"; if (flags & message::FLAG_REPLIED) str += "R"; if (flags & message::FLAG_SEEN) str += "S"; if (flags & message::FLAG_DELETED) str += "T"; if (flags & message::FLAG_DRAFT) str += "D"; return (utility::file::path::component(str)); } const utility::file::path::component maildirUtils::buildFilename (const utility::file::path::component& id, const int flags) { if (flags == message::FLAG_RECENT) return id; else return (buildFilename(id, buildFlags(flags))); } const utility::file::path::component maildirUtils::buildFilename (const utility::file::path::component& id, const utility::file::path::component& flags) { #if VMIME_PLATFORM_IS_WINDOWS static const char DELIMITER[] = "-"; #else static const char DELIMITER[] = ":"; #endif return utility::path::component(id.getBuffer() + DELIMITER + flags.getBuffer()); } const utility::file::path::component maildirUtils::generateId() { std::ostringstream oss; oss.imbue(std::locale::classic()); oss << utility::random::getTime(); oss << "."; oss << utility::random::getProcess(); oss << "."; oss << utility::random::getString(6); oss << "."; oss << platform::getHandler()->getHostName(); return (utility::file::path::component(oss.str())); } void maildirUtils::recursiveFSDelete(shared_ptr dir) { shared_ptr files = dir->getFiles(); // First, delete files and subdirectories in this directory while (files->hasMoreElements()) { shared_ptr file = files->nextElement(); if (file->isDirectory()) { maildirUtils::recursiveFSDelete(file); } else { try { file->remove(); } catch (exceptions::filesystem_exception&) { // Ignore } } } // Then, delete this (empty) directory try { dir->remove(); } catch (exceptions::filesystem_exception&) { // Ignore } } class maildirMessageSetEnumerator : public messageSetEnumerator { public: maildirMessageSetEnumerator(const size_t msgCount) : m_msgCount(msgCount) { } void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) { size_t last = range.getLast(); if (last == size_t(-1)) last = m_msgCount; for (size_t i = range.getFirst() ; i <= last ; ++i) list.push_back(i); } void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& /* range */) { // Not supported } public: std::vector list; private: size_t m_msgCount; }; // static const std::vector maildirUtils::messageSetToNumberList(const messageSet& msgs, const size_t msgCount) { maildirMessageSetEnumerator en(msgCount); msgs.enumerate(en); return en.list; } // // messageIdComparator // maildirUtils::messageIdComparator::messageIdComparator (const utility::file::path::component& comp) : m_comp(maildirUtils::extractId(comp)) { } bool maildirUtils::messageIdComparator::operator() (const utility::file::path::component& other) const { return (m_comp == maildirUtils::extractId(other)); } } // maildir } // net } // vmime #endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR