📄 imapfolder.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/imap/IMAPFolder.hpp"#include "vmime/net/imap/IMAPStore.hpp"#include "vmime/net/imap/IMAPParser.hpp"#include "vmime/net/imap/IMAPMessage.hpp"#include "vmime/net/imap/IMAPUtils.hpp"#include "vmime/net/imap/IMAPConnection.hpp"#include "vmime/message.hpp"#include "vmime/exception.hpp"#include "vmime/utility/smartPtr.hpp"#include <algorithm>#include <sstream>namespace vmime {namespace net {namespace imap {IMAPFolder::IMAPFolder(const folder::path& path, ref <IMAPStore> store, const int type, const int flags) : m_store(store), m_connection(store->connection()), m_path(path), m_name(path.isEmpty() ? folder::path::component("") : path.getLastComponent()), m_mode(-1), m_open(false), m_type(type), m_flags(flags), m_messageCount(0), m_uidValidity(0){ store->registerFolder(this);}IMAPFolder::~IMAPFolder(){ ref <IMAPStore> store = m_store.acquire(); if (store) { if (m_open) close(false); store->unregisterFolder(this); } else if (m_open) { m_connection = NULL; onClose(); }}int IMAPFolder::getMode() const{ if (!isOpen()) throw exceptions::illegal_state("Folder not open"); return (m_mode);}int IMAPFolder::getType(){ if (!isOpen()) throw exceptions::illegal_state("Folder not open"); // Root folder if (m_path.isEmpty()) { return (TYPE_CONTAINS_FOLDERS); } else { if (m_type == TYPE_UNDEFINED) testExistAndGetType(); return (m_type); }}int IMAPFolder::getFlags(){ if (!isOpen()) throw exceptions::illegal_state("Folder not open"); // Root folder if (m_path.isEmpty()) { return (FLAG_CHILDREN | FLAG_NO_OPEN); } else { if (m_flags == FLAG_UNDEFINED) testExistAndGetType(); return (m_flags); }}const folder::path::component IMAPFolder::getName() const{ return (m_name);}const folder::path IMAPFolder::getFullPath() const{ return (m_path);}void IMAPFolder::open(const int mode, bool failIfModeIsNotAvailable){ ref <IMAPStore> store = m_store.acquire(); if (!store) throw exceptions::illegal_state("Store disconnected"); // Open a connection for this folder ref <IMAPConnection> connection = vmime::create <IMAPConnection>(store, store->getAuthenticator()); try { connection->connect(); // Emit the "SELECT" command // // Example: C: A142 SELECT INBOX // S: * 172 EXISTS // S: * 1 RECENT // S: * OK [UNSEEN 12] Message 12 is first unseen // S: * OK [UIDVALIDITY 3857529045] UIDs valid // S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft) // S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited // S: A142 OK [READ-WRITE] SELECT completed std::ostringstream oss; if (mode == MODE_READ_ONLY) oss << "EXAMINE "; else oss << "SELECT "; oss << IMAPUtils::quoteString(IMAPUtils::pathToString (connection->hierarchySeparator(), getFullPath())); connection->send(true, oss.str(), true); // Read the response utility::auto_ptr <IMAPParser::response> resp(connection->readResponse()); if (resp->isBad() || resp->response_done()->response_tagged()-> resp_cond_state()->status() != IMAPParser::resp_cond_state::OK) { throw exceptions::command_error("SELECT", connection->getParser()->lastLine(), "bad response"); } const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList = resp->continue_req_or_response_data(); for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator it = respDataList.begin() ; it != respDataList.end() ; ++it) { if ((*it)->response_data() == NULL) { throw exceptions::command_error("SELECT", connection->getParser()->lastLine(), "invalid response"); } const IMAPParser::response_data* responseData = (*it)->response_data(); // OK Untagged responses: UNSEEN, PERMANENTFLAGS, UIDVALIDITY (optional) if (responseData->resp_cond_state()) { const IMAPParser::resp_text_code* code = responseData->resp_cond_state()->resp_text()->resp_text_code(); if (code != NULL) { switch (code->type()) { case IMAPParser::resp_text_code::UIDVALIDITY: m_uidValidity = code->nz_number()->value(); break; default: break; } } } // Untagged responses: FLAGS, EXISTS, RECENT (required) else if (responseData->mailbox_data()) { switch (responseData->mailbox_data()->type()) { default: break; case IMAPParser::mailbox_data::FLAGS: { m_type = IMAPUtils::folderTypeFromFlags (responseData->mailbox_data()->mailbox_flag_list()); m_flags = IMAPUtils::folderFlagsFromFlags (responseData->mailbox_data()->mailbox_flag_list()); break; } case IMAPParser::mailbox_data::EXISTS: { m_messageCount = responseData->mailbox_data()->number()->value(); break; } case IMAPParser::mailbox_data::RECENT: { // TODO break; } } } } // Check for access mode (read-only or read-write) const IMAPParser::resp_text_code* respTextCode = resp->response_done()-> response_tagged()->resp_cond_state()->resp_text()->resp_text_code(); if (respTextCode) { const int openMode = (respTextCode->type() == IMAPParser::resp_text_code::READ_WRITE) ? MODE_READ_WRITE : MODE_READ_ONLY; if (failIfModeIsNotAvailable && mode == MODE_READ_WRITE && openMode == MODE_READ_ONLY) { throw exceptions::operation_not_supported(); } } m_connection = connection; m_open = true; m_mode = mode; } catch (std::exception&) { throw; }}void IMAPFolder::close(const bool expunge){ ref <IMAPStore> store = m_store.acquire(); if (!store) throw exceptions::illegal_state("Store disconnected"); if (!isOpen()) throw exceptions::illegal_state("Folder not open"); ref <IMAPConnection> oldConnection = m_connection; // Emit the "CLOSE" command to expunge messages marked // as deleted (this is fastest than "EXPUNGE") if (expunge) { if (m_mode == MODE_READ_ONLY) throw exceptions::operation_not_supported(); oldConnection->send(true, "CLOSE", true); } // Close this folder connection oldConnection->disconnect(); // Now use default store connection m_connection = m_store.acquire()->connection(); m_open = false; m_mode = -1; m_uidValidity = 0; onClose();}void IMAPFolder::onClose(){ for (std::vector <IMAPMessage*>::iterator it = m_messages.begin() ; it != m_messages.end() ; ++it) { (*it)->onFolderClosed(); } m_messages.clear();}void IMAPFolder::create(const int type){ ref <IMAPStore> store = m_store.acquire(); if (!store) throw exceptions::illegal_state("Store disconnected"); else if (isOpen()) throw exceptions::illegal_state("Folder is open"); else if (exists()) throw exceptions::illegal_state("Folder already exists"); else if (!store->isValidFolderName(m_name)) throw exceptions::invalid_folder_name(); // Emit the "CREATE" command // // Example: C: A003 CREATE owatagusiam/ // S: A003 OK CREATE completed // C: A004 CREATE owatagusiam/blurdybloop // S: A004 OK CREATE completed string mailbox = IMAPUtils::pathToString (m_connection->hierarchySeparator(), getFullPath()); if (type & TYPE_CONTAINS_FOLDERS) mailbox += m_connection->hierarchySeparator(); std::ostringstream oss; oss << "CREATE " << IMAPUtils::quoteString(mailbox); m_connection->send(true, oss.str(), true); utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse()); if (resp->isBad() || resp->response_done()->response_tagged()-> resp_cond_state()->status() != IMAPParser::resp_cond_state::OK) { throw exceptions::command_error("CREATE", m_connection->getParser()->lastLine(), "bad response"); } // Notify folder created events::folderEvent event (thisRef().dynamicCast <folder>(), events::folderEvent::TYPE_CREATED, m_path, m_path); notifyFolder(event);}void IMAPFolder::destroy(){ ref <IMAPStore> store = m_store.acquire(); if (!store) throw exceptions::illegal_state("Store disconnected"); if (isOpen()) throw exceptions::illegal_state("Folder is open"); const string mailbox = IMAPUtils::pathToString (m_connection->hierarchySeparator(), getFullPath()); std::ostringstream oss; oss << "DELETE " << IMAPUtils::quoteString(mailbox); m_connection->send(true, oss.str(), true); utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse()); if (resp->isBad() || resp->response_done()->response_tagged()-> resp_cond_state()->status() != IMAPParser::resp_cond_state::OK) { throw exceptions::command_error("DELETE", m_connection->getParser()->lastLine(), "bad response"); } // Notify folder deleted events::folderEvent event (thisRef().dynamicCast <folder>(), events::folderEvent::TYPE_DELETED, m_path, m_path); notifyFolder(event);}bool IMAPFolder::exists(){ ref <IMAPStore> store = m_store.acquire(); if (!isOpen() && !store) throw exceptions::illegal_state("Store disconnected"); return (testExistAndGetType() != TYPE_UNDEFINED);}int IMAPFolder::testExistAndGetType(){ m_type = TYPE_UNDEFINED; // To test whether a folder exists, we simple list it using // the "LIST" command, and there should be one unique mailbox // with this name... // // Eg. Test whether '/foo/bar' exists // // C: a005 list "" foo/bar // S: * LIST (\NoSelect) "/" foo/bar // S: a005 OK LIST completed // // ==> OK, exists // // Test whether '/foo/bar/zap' exists // // C: a005 list "" foo/bar/zap // S: a005 OK LIST completed // // ==> NO, does not exist std::ostringstream oss; oss << "LIST \"\" "; oss << IMAPUtils::quoteString(IMAPUtils::pathToString (m_connection->hierarchySeparator(), getFullPath())); m_connection->send(true, oss.str(), true); utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse()); if (resp->isBad() || resp->response_done()->response_tagged()-> resp_cond_state()->status() != IMAPParser::resp_cond_state::OK) { throw exceptions::command_error("LIST", m_connection->getParser()->lastLine(), "bad response"); } // Check whether the result mailbox list contains this folder const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList = resp->continue_req_or_response_data(); for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator it = respDataList.begin() ; it != respDataList.end() ; ++it) { if ((*it)->response_data() == NULL) { throw exceptions::command_error("LIST", m_connection->getParser()->lastLine(), "invalid response"); } const IMAPParser::mailbox_data* mailboxData = (*it)->response_data()->mailbox_data(); // We are only interested in responses of type "LIST" if (mailboxData != NULL && mailboxData->type() == IMAPParser::mailbox_data::LIST) { // Get the folder type/flags at the same time m_type = IMAPUtils::folderTypeFromFlags (mailboxData->mailbox_list()->mailbox_flag_list()); m_flags = IMAPUtils::folderFlagsFromFlags (mailboxData->mailbox_list()->mailbox_flag_list()); } } return (m_type);}bool IMAPFolder::isOpen() const{ return (m_open);}ref <message> IMAPFolder::getMessage(const int num){ if (!isOpen()) throw exceptions::illegal_state("Folder not open"); if (num < 1 || num > m_messageCount) throw exceptions::message_not_found(); return vmime::create <IMAPMessage>(thisRef().dynamicCast <IMAPFolder>(), num);}std::vector <ref <message> > IMAPFolder::getMessages(const int from, const int to){ const int messageCount = getMessageCount(); const int to2 = (to == -1 ? messageCount : to); if (!isOpen()) throw exceptions::illegal_state("Folder not open"); else if (to2 < from || from < 1 || to2 < 1 || from > messageCount || to2 > messageCount) throw exceptions::message_not_found(); std::vector <ref <message> > v; ref <IMAPFolder> thisFolder = thisRef().dynamicCast <IMAPFolder>(); for (int i = from ; i <= to2 ; ++i) v.push_back(vmime::create <IMAPMessage>(thisFolder, i)); return (v);}std::vector <ref <message> > IMAPFolder::getMessages(const std::vector <int>& nums){ if (!isOpen()) throw exceptions::illegal_state("Folder not open"); std::vector <ref <message> > v; ref <IMAPFolder> thisFolder = thisRef().dynamicCast <IMAPFolder>(); for (std::vector <int>::const_iterator it = nums.begin() ; it != nums.end() ; ++it) v.push_back(vmime::create <IMAPMessage>(thisFolder, *it)); return (v);}int IMAPFolder::getMessageCount(){ if (!isOpen()) throw exceptions::illegal_state("Folder not open"); return (m_messageCount);}ref <folder> IMAPFolder::getFolder(const folder::path::component& name){ ref <IMAPStore> store = m_store.acquire(); if (!store) throw exceptions::illegal_state("Store disconnected"); return vmime::create <IMAPFolder>(m_path / name, store);}std::vector <ref <folder> > IMAPFolder::getFolders(const bool recursive){ ref <IMAPStore> store = m_store.acquire(); if (!isOpen() && !store) throw exceptions::illegal_state("Store disconnected"); // Eg. List folders in '/foo/bar' // // C: a005 list "foo/bar" * // S: * LIST (\NoSelect) "/" foo/bar // S: * LIST (\NoInferiors) "/" foo/bar/zap // S: a005 OK LIST completed std::ostringstream oss; oss << "LIST "; const string pathString = IMAPUtils::pathToString (m_connection->hierarchySeparator(), getFullPath()); if (recursive) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -