diff options
| author | Vincent Richard <[email protected]> | 2013-12-29 10:02:12 +0100 |
|---|---|---|
| committer | Vincent Richard <[email protected]> | 2013-12-29 10:02:12 +0100 |
| commit | 152c6bed75598a6ca5efb7914701157270155833 (patch) | |
| tree | 8faced1d75a45c819630323da256248415992ed0 /src/net/imap | |
| parent | Merge branch 'master' of https://github.com/kisli/vmime (diff) | |
| download | vmime-152c6bed75598a6ca5efb7914701157270155833.tar.gz vmime-152c6bed75598a6ca5efb7914701157270155833.zip | |
Merged source and header files in directory structure. Got rid of SConstruct build.
Diffstat (limited to 'src/net/imap')
| -rw-r--r-- | src/net/imap/IMAPConnection.cpp | 814 | ||||
| -rw-r--r-- | src/net/imap/IMAPFolder.cpp | 1511 | ||||
| -rw-r--r-- | src/net/imap/IMAPFolderStatus.cpp | 307 | ||||
| -rw-r--r-- | src/net/imap/IMAPMessage.cpp | 649 | ||||
| -rw-r--r-- | src/net/imap/IMAPMessagePart.cpp | 161 | ||||
| -rw-r--r-- | src/net/imap/IMAPMessagePartContentHandler.cpp | 216 | ||||
| -rw-r--r-- | src/net/imap/IMAPMessageStructure.cpp | 94 | ||||
| -rw-r--r-- | src/net/imap/IMAPSStore.cpp | 79 | ||||
| -rw-r--r-- | src/net/imap/IMAPServiceInfos.cpp | 137 | ||||
| -rw-r--r-- | src/net/imap/IMAPStore.cpp | 267 | ||||
| -rw-r--r-- | src/net/imap/IMAPTag.cpp | 122 | ||||
| -rw-r--r-- | src/net/imap/IMAPUtils.cpp | 758 |
12 files changed, 0 insertions, 5115 deletions
diff --git a/src/net/imap/IMAPConnection.cpp b/src/net/imap/IMAPConnection.cpp deleted file mode 100644 index 234c2b6a..00000000 --- a/src/net/imap/IMAPConnection.cpp +++ /dev/null @@ -1,814 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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_IMAP - - -#include "vmime/net/imap/IMAPTag.hpp" -#include "vmime/net/imap/IMAPConnection.hpp" -#include "vmime/net/imap/IMAPUtils.hpp" -#include "vmime/net/imap/IMAPStore.hpp" - -#include "vmime/exception.hpp" -#include "vmime/platform.hpp" - -#include "vmime/utility/stringUtils.hpp" - -#include "vmime/net/defaultConnectionInfos.hpp" - -#if VMIME_HAVE_SASL_SUPPORT - #include "vmime/security/sasl/SASLContext.hpp" -#endif // VMIME_HAVE_SASL_SUPPORT - -#if VMIME_HAVE_TLS_SUPPORT - #include "vmime/net/tls/TLSSession.hpp" - #include "vmime/net/tls/TLSSecuredConnectionInfos.hpp" -#endif // VMIME_HAVE_TLS_SUPPORT - -#include <sstream> - - -// Helpers for service properties -#define GET_PROPERTY(type, prop) \ - (m_store.lock()->getInfos().getPropertyValue <type>(getSession(), \ - dynamic_cast <const IMAPServiceInfos&>(m_store.lock()->getInfos()).getProperties().prop)) -#define HAS_PROPERTY(prop) \ - (m_store.lock()->getInfos().hasProperty(getSession(), \ - dynamic_cast <const IMAPServiceInfos&>(m_store.lock()->getInfos()).getProperties().prop)) - - -namespace vmime { -namespace net { -namespace imap { - - -IMAPConnection::IMAPConnection(shared_ptr <IMAPStore> store, shared_ptr <security::authenticator> auth) - : m_store(store), m_auth(auth), m_socket(null), m_parser(null), m_tag(null), - m_hierarchySeparator('\0'), m_state(STATE_NONE), m_timeoutHandler(null), - m_secured(false), m_firstTag(true), m_capabilitiesFetched(false), m_noModSeq(false) -{ -} - - -IMAPConnection::~IMAPConnection() -{ - try - { - if (isConnected()) - disconnect(); - else if (m_socket) - internalDisconnect(); - } - catch (vmime::exception&) - { - // Ignore - } -} - - -void IMAPConnection::connect() -{ - if (isConnected()) - throw exceptions::already_connected(); - - m_state = STATE_NONE; - m_hierarchySeparator = '\0'; - - const string address = GET_PROPERTY(string, PROPERTY_SERVER_ADDRESS); - const port_t port = GET_PROPERTY(port_t, PROPERTY_SERVER_PORT); - - shared_ptr <IMAPStore> store = m_store.lock(); - - // Create the time-out handler - if (store->getTimeoutHandlerFactory()) - m_timeoutHandler = store->getTimeoutHandlerFactory()->create(); - - // Create and connect the socket - m_socket = store->getSocketFactory()->create(m_timeoutHandler); - -#if VMIME_HAVE_TLS_SUPPORT - if (store->isIMAPS()) // dedicated port/IMAPS - { - shared_ptr <tls::TLSSession> tlsSession = tls::TLSSession::create - (store->getCertificateVerifier(), - store->getSession()->getTLSProperties()); - - shared_ptr <tls::TLSSocket> tlsSocket = - tlsSession->getSocket(m_socket); - - m_socket = tlsSocket; - - m_secured = true; - m_cntInfos = make_shared <tls::TLSSecuredConnectionInfos>(address, port, tlsSession, tlsSocket); - } - else -#endif // VMIME_HAVE_TLS_SUPPORT - { - m_cntInfos = make_shared <defaultConnectionInfos>(address, port); - } - - m_socket->connect(address, port); - - - m_tag = make_shared <IMAPTag>(); - m_parser = make_shared <IMAPParser>(m_tag, m_socket, m_timeoutHandler); - - - setState(STATE_NON_AUTHENTICATED); - - - // Connection greeting - // - // eg: C: <connection to server> - // --- S: * OK mydomain.org IMAP4rev1 v12.256 server ready - - std::auto_ptr <IMAPParser::greeting> greet(m_parser->readGreeting()); - bool needAuth = false; - - if (greet->resp_cond_bye()) - { - internalDisconnect(); - throw exceptions::connection_greeting_error(greet->getErrorLog()); - } - else if (greet->resp_cond_auth()->condition() != IMAPParser::resp_cond_auth::PREAUTH) - { - needAuth = true; - } - - if (greet->resp_cond_auth()->resp_text()->resp_text_code() && - greet->resp_cond_auth()->resp_text()->resp_text_code()->capability_data()) - { - processCapabilityResponseData(greet->resp_cond_auth()->resp_text()->resp_text_code()->capability_data()); - } - -#if VMIME_HAVE_TLS_SUPPORT - // Setup secured connection, if requested - const bool tls = HAS_PROPERTY(PROPERTY_CONNECTION_TLS) - && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS); - const bool tlsRequired = HAS_PROPERTY(PROPERTY_CONNECTION_TLS_REQUIRED) - && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS_REQUIRED); - - if (!store->isIMAPS() && tls) // only if not IMAPS - { - try - { - startTLS(); - } - // Non-fatal error - catch (exceptions::command_error&) - { - if (tlsRequired) - { - m_state = STATE_NONE; - throw; - } - else - { - // TLS is not required, so don't bother - } - } - // Fatal error - catch (...) - { - m_state = STATE_NONE; - throw; - } - } -#endif // VMIME_HAVE_TLS_SUPPORT - - // Authentication - if (needAuth) - { - try - { - authenticate(); - } - catch (...) - { - m_state = STATE_NONE; - throw; - } - } - - // Get the hierarchy separator character - initHierarchySeparator(); - - // Switch to state "Authenticated" - setState(STATE_AUTHENTICATED); -} - - -void IMAPConnection::authenticate() -{ - getAuthenticator()->setService(m_store.lock()); - -#if VMIME_HAVE_SASL_SUPPORT - // First, try SASL authentication - if (GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL)) - { - try - { - authenticateSASL(); - return; - } - catch (exceptions::authentication_error& e) - { - if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK)) - { - // Can't fallback on normal authentication - internalDisconnect(); - throw e; - } - else - { - // Ignore, will try normal authentication - } - } - catch (exception& e) - { - internalDisconnect(); - throw e; - } - } -#endif // VMIME_HAVE_SASL_SUPPORT - - // Normal authentication - const string username = getAuthenticator()->getUsername(); - const string password = getAuthenticator()->getPassword(); - - send(true, "LOGIN " + IMAPUtils::quoteString(username) - + " " + IMAPUtils::quoteString(password), true); - - std::auto_ptr <IMAPParser::response> resp(m_parser->readResponse()); - - if (resp->isBad()) - { - internalDisconnect(); - throw exceptions::command_error("LOGIN", resp->getErrorLog()); - } - else if (resp->response_done()->response_tagged()-> - resp_cond_state()->status() != IMAPParser::resp_cond_state::OK) - { - internalDisconnect(); - throw exceptions::authentication_error(resp->getErrorLog()); - } - - // Server capabilities may change when logged in - if (!processCapabilityResponseData(resp.get())) - invalidateCapabilities(); -} - - -#if VMIME_HAVE_SASL_SUPPORT - -void IMAPConnection::authenticateSASL() -{ - if (!dynamicCast <security::sasl::SASLAuthenticator>(getAuthenticator())) - throw exceptions::authentication_error("No SASL authenticator available."); - - const std::vector <string> capa = getCapabilities(); - std::vector <string> saslMechs; - - for (unsigned int i = 0 ; i < capa.size() ; ++i) - { - const string& x = capa[i]; - - if (x.length() > 5 && - (x[0] == 'A' || x[0] == 'a') && - (x[1] == 'U' || x[1] == 'u') && - (x[2] == 'T' || x[2] == 't') && - (x[3] == 'H' || x[3] == 'h') && - x[4] == '=') - { - saslMechs.push_back(string(x.begin() + 5, x.end())); - } - } - - if (saslMechs.empty()) - throw exceptions::authentication_error("No SASL mechanism available."); - - std::vector <shared_ptr <security::sasl::SASLMechanism> > mechList; - - shared_ptr <security::sasl::SASLContext> saslContext = - make_shared <security::sasl::SASLContext>(); - - for (unsigned int i = 0 ; i < saslMechs.size() ; ++i) - { - try - { - mechList.push_back - (saslContext->createMechanism(saslMechs[i])); - } - catch (exceptions::no_such_mechanism&) - { - // Ignore mechanism - } - } - - if (mechList.empty()) - throw exceptions::authentication_error("No SASL mechanism available."); - - // Try to suggest a mechanism among all those supported - shared_ptr <security::sasl::SASLMechanism> suggestedMech = - saslContext->suggestMechanism(mechList); - - if (!suggestedMech) - throw exceptions::authentication_error("Unable to suggest SASL mechanism."); - - // Allow application to choose which mechanisms to use - mechList = dynamicCast <security::sasl::SASLAuthenticator>(getAuthenticator())-> - getAcceptableMechanisms(mechList, suggestedMech); - - if (mechList.empty()) - throw exceptions::authentication_error("No SASL mechanism available."); - - // Try each mechanism in the list in turn - for (unsigned int i = 0 ; i < mechList.size() ; ++i) - { - shared_ptr <security::sasl::SASLMechanism> mech = mechList[i]; - - shared_ptr <security::sasl::SASLSession> saslSession = - saslContext->createSession("imap", getAuthenticator(), mech); - - saslSession->init(); - - send(true, "AUTHENTICATE " + mech->getName(), true); - - for (bool cont = true ; cont ; ) - { - std::auto_ptr <IMAPParser::response> resp(m_parser->readResponse()); - - if (resp->response_done() && - resp->response_done()->response_tagged() && - resp->response_done()->response_tagged()->resp_cond_state()-> - status() == IMAPParser::resp_cond_state::OK) - { - m_socket = saslSession->getSecuredSocket(m_socket); - return; - } - else - { - std::vector <IMAPParser::continue_req_or_response_data*> - respDataList = resp->continue_req_or_response_data(); - - string response; - bool hasResponse = false; - - for (unsigned int i = 0 ; i < respDataList.size() ; ++i) - { - if (respDataList[i]->continue_req()) - { - response = respDataList[i]->continue_req()->resp_text()->text(); - hasResponse = true; - break; - } - } - - if (!hasResponse) - { - cont = false; - continue; - } - - byte_t* challenge = 0; - size_t challengeLen = 0; - - byte_t* resp = 0; - size_t respLen = 0; - - try - { - // Extract challenge - saslContext->decodeB64(response, &challenge, &challengeLen); - - // Prepare response - saslSession->evaluateChallenge - (challenge, challengeLen, &resp, &respLen); - - // Send response - send(false, saslContext->encodeB64(resp, respLen), true); - - // Server capabilities may change when logged in - invalidateCapabilities(); - } - catch (exceptions::sasl_exception& e) - { - if (challenge) - { - delete [] challenge; - challenge = NULL; - } - - if (resp) - { - delete [] resp; - resp = NULL; - } - - // Cancel SASL exchange - send(false, "*", true); - } - catch (...) - { - if (challenge) - delete [] challenge; - - if (resp) - delete [] resp; - - throw; - } - - if (challenge) - delete [] challenge; - - if (resp) - delete [] resp; - } - } - } - - throw exceptions::authentication_error - ("Could not authenticate using SASL: all mechanisms failed."); -} - -#endif // VMIME_HAVE_SASL_SUPPORT - - -#if VMIME_HAVE_TLS_SUPPORT - -void IMAPConnection::startTLS() -{ - try - { - send(true, "STARTTLS", true); - - std::auto_ptr <IMAPParser::response> resp(m_parser->readResponse()); - - if (resp->isBad() || resp->response_done()->response_tagged()-> - resp_cond_state()->status() != IMAPParser::resp_cond_state::OK) - { - throw exceptions::command_error - ("STARTTLS", resp->getErrorLog(), "bad response"); - } - - shared_ptr <tls::TLSSession> tlsSession = tls::TLSSession::create - (m_store.lock()->getCertificateVerifier(), - m_store.lock()->getSession()->getTLSProperties()); - - shared_ptr <tls::TLSSocket> tlsSocket = - tlsSession->getSocket(m_socket); - - tlsSocket->handshake(m_timeoutHandler); - - m_socket = tlsSocket; - m_parser->setSocket(m_socket); - - m_secured = true; - m_cntInfos = make_shared <tls::TLSSecuredConnectionInfos> - (m_cntInfos->getHost(), m_cntInfos->getPort(), tlsSession, tlsSocket); - - // " Once TLS has been started, the client MUST discard cached - // information about server capabilities and SHOULD re-issue the - // CAPABILITY command. This is necessary to protect against - // man-in-the-middle attacks which alter the capabilities list prior - // to STARTTLS. " (RFC-2595) - invalidateCapabilities(); - } - catch (exceptions::command_error&) - { - // Non-fatal error - throw; - } - catch (exception&) - { - // Fatal error - internalDisconnect(); - throw; - } -} - -#endif // VMIME_HAVE_TLS_SUPPORT - - -const std::vector <string> IMAPConnection::getCapabilities() -{ - if (!m_capabilitiesFetched) - fetchCapabilities(); - - return m_capabilities; -} - - -bool IMAPConnection::hasCapability(const string& capa) -{ - if (!m_capabilitiesFetched) - fetchCapabilities(); - - const string normCapa = utility::stringUtils::toUpper(capa); - - for (size_t i = 0, n = m_capabilities.size() ; i < n ; ++i) - { - if (m_capabilities[i] == normCapa) - return true; - } - - return false; -} - - -void IMAPConnection::invalidateCapabilities() -{ - m_capabilities.clear(); - m_capabilitiesFetched = false; -} - - -void IMAPConnection::fetchCapabilities() -{ - send(true, "CAPABILITY", true); - - std::auto_ptr <IMAPParser::response> resp(m_parser->readResponse()); - - if (resp->response_done()->response_tagged()-> - resp_cond_state()->status() == IMAPParser::resp_cond_state::OK) - { - processCapabilityResponseData(resp.get()); - } -} - - -bool IMAPConnection::processCapabilityResponseData(const IMAPParser::response* resp) -{ - const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList = - resp->continue_req_or_response_data(); - - for (size_t i = 0 ; i < respDataList.size() ; ++i) - { - if (respDataList[i]->response_data() == NULL) - continue; - - const IMAPParser::capability_data* capaData = - respDataList[i]->response_data()->capability_data(); - - if (capaData == NULL) - continue; - - processCapabilityResponseData(capaData); - return true; - } - - return false; -} - - -void IMAPConnection::processCapabilityResponseData(const IMAPParser::capability_data* capaData) -{ - std::vector <string> res; - - std::vector <IMAPParser::capability*> caps = capaData->capabilities(); - - for (unsigned int j = 0 ; j < caps.size() ; ++j) - { - if (caps[j]->auth_type()) - res.push_back("AUTH=" + caps[j]->auth_type()->name()); - else - res.push_back(utility::stringUtils::toUpper(caps[j]->atom()->value())); - } - - m_capabilities = res; - m_capabilitiesFetched = true; -} - - -shared_ptr <security::authenticator> IMAPConnection::getAuthenticator() -{ - return m_auth; -} - - -bool IMAPConnection::isConnected() const -{ - return (m_socket && m_socket->isConnected() && - (m_state == STATE_AUTHENTICATED || m_state == STATE_SELECTED)); -} - - -bool IMAPConnection::isSecuredConnection() const -{ - return m_secured; -} - - -shared_ptr <connectionInfos> IMAPConnection::getConnectionInfos() const -{ - return m_cntInfos; -} - - -void IMAPConnection::disconnect() -{ - if (!isConnected()) - throw exceptions::not_connected(); - - internalDisconnect(); -} - - -void IMAPConnection::internalDisconnect() -{ - if (isConnected()) - { - send(true, "LOGOUT", true); - - m_socket->disconnect(); - m_socket = null; - } - - m_timeoutHandler = null; - - m_state = STATE_LOGOUT; - - m_secured = false; - m_cntInfos = null; -} - - -void IMAPConnection::initHierarchySeparator() -{ - send(true, "LIST \"\" \"\"", true); - - std::auto_ptr <IMAPParser::response> resp(m_parser->readResponse()); - - if (resp->isBad() || resp->response_done()->response_tagged()-> - resp_cond_state()->status() != IMAPParser::resp_cond_state::OK) - { - internalDisconnect(); - throw exceptions::command_error("LIST", resp->getErrorLog(), "bad response"); - } - - const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList = - resp->continue_req_or_response_data(); - - bool found = false; - - for (unsigned int i = 0 ; !found && i < respDataList.size() ; ++i) - { - if (respDataList[i]->response_data() == NULL) - continue; - - const IMAPParser::mailbox_data* mailboxData = - static_cast <const IMAPParser::response_data*> - (respDataList[i]->response_data())->mailbox_data(); - - if (mailboxData == NULL || mailboxData->type() != IMAPParser::mailbox_data::LIST) - continue; - - if (mailboxData->mailbox_list()->quoted_char() != '\0') - { - m_hierarchySeparator = mailboxData->mailbox_list()->quoted_char(); - found = true; - } - } - - if (!found) // default - m_hierarchySeparator = '/'; -} - - -void IMAPConnection::send(bool tag, const string& what, bool end) -{ - if (tag && !m_firstTag) - ++(*m_tag); - -#if VMIME_DEBUG - std::ostringstream oss; - - if (tag) - { - oss << string(*m_tag); - oss << " "; - } - - oss << what; - - if (end) - oss << "\r\n"; - - m_socket->send(oss.str()); -#else - if (tag) - { - m_socket->send(*m_tag); - m_socket->send(" "); - } - - m_socket->send(what); - - if (end) - { - m_socket->send("\r\n"); - } -#endif - - if (tag) - m_firstTag = false; -} - - -void IMAPConnection::sendRaw(const byte_t* buffer, const size_t count) -{ - m_socket->sendRaw(buffer, count); -} - - -IMAPParser::response* IMAPConnection::readResponse(IMAPParser::literalHandler* lh) -{ - return (m_parser->readResponse(lh)); -} - - -IMAPConnection::ProtocolStates IMAPConnection::state() const -{ - return (m_state); -} - - -void IMAPConnection::setState(const ProtocolStates state) -{ - m_state = state; -} - - -char IMAPConnection::hierarchySeparator() const -{ - return (m_hierarchySeparator); -} - - -shared_ptr <const IMAPStore> IMAPConnection::getStore() const -{ - return m_store.lock(); -} - - -shared_ptr <IMAPStore> IMAPConnection::getStore() -{ - return m_store.lock(); -} - - -shared_ptr <session> IMAPConnection::getSession() -{ - return m_store.lock()->getSession(); -} - - -shared_ptr <const socket> IMAPConnection::getSocket() const -{ - return m_socket; -} - - -bool IMAPConnection::isMODSEQDisabled() const -{ - return m_noModSeq; -} - - -void IMAPConnection::disableMODSEQ() -{ - m_noModSeq = true; -} - - -} // imap -} // net -} // vmime - - -#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP - diff --git a/src/net/imap/IMAPFolder.cpp b/src/net/imap/IMAPFolder.cpp deleted file mode 100644 index fb98887c..00000000 --- a/src/net/imap/IMAPFolder.cpp +++ /dev/null @@ -1,1511 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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_IMAP - - -#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/net/imap/IMAPFolderStatus.hpp" - -#include "vmime/message.hpp" - -#include "vmime/exception.hpp" - -#include "vmime/utility/outputStreamAdapter.hpp" - -#include <algorithm> -#include <sstream> - - -namespace vmime { -namespace net { -namespace imap { - - -IMAPFolder::IMAPFolder(const folder::path& path, shared_ptr <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) -{ - store->registerFolder(this); - - m_status = make_shared <IMAPFolderStatus>(); -} - - -IMAPFolder::~IMAPFolder() -{ - shared_ptr <IMAPStore> store = m_store.lock(); - - 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) -{ - shared_ptr <IMAPStore> store = m_store.lock(); - - if (!store) - throw exceptions::illegal_state("Store disconnected"); - - // Ensure this folder is not already open in the same session - for (std::list <IMAPFolder*>::iterator it = store->m_folders.begin() ; - it != store->m_folders.end() ; ++it) - { - if ((*it) != this && (*it)->getFullPath() == m_path) - throw exceptions::folder_already_open(); - } - - // Open a connection for this folder - shared_ptr <IMAPConnection> connection = - make_shared <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())); - - if (m_connection->hasCapability("CONDSTORE")) - oss << " (CONDSTORE)"; - - connection->send(true, oss.str(), true); - - // Read the response - std::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", - resp->getErrorLog(), "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", - resp->getErrorLog(), "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::NOMODSEQ: - - connection->disableMODSEQ(); - 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; - } - - } - } - } - - processStatusUpdate(resp.get()); - - // 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) -{ - shared_ptr <IMAPStore> store = m_store.lock(); - - if (!store) - throw exceptions::illegal_state("Store disconnected"); - - if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - shared_ptr <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.lock()->connection(); - - m_open = false; - m_mode = -1; - - m_status = make_shared <IMAPFolderStatus>(); - - 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) -{ - shared_ptr <IMAPStore> store = m_store.lock(); - - 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); - - - std::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", - resp->getErrorLog(), "bad response"); - } - - // Notify folder created - shared_ptr <events::folderEvent> event = - make_shared <events::folderEvent> - (dynamicCast <folder>(shared_from_this()), - events::folderEvent::TYPE_CREATED, m_path, m_path); - - notifyFolder(event); -} - - -void IMAPFolder::destroy() -{ - shared_ptr <IMAPStore> store = m_store.lock(); - - 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); - - - std::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", - resp->getErrorLog(), "bad response"); - } - - // Notify folder deleted - shared_ptr <events::folderEvent> event = - make_shared <events::folderEvent> - (dynamicCast <folder>(shared_from_this()), - events::folderEvent::TYPE_DELETED, m_path, m_path); - - notifyFolder(event); -} - - -bool IMAPFolder::exists() -{ - shared_ptr <IMAPStore> store = m_store.lock(); - - 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); - - - std::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", - resp->getErrorLog(), "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", - resp->getErrorLog(), "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); -} - - -shared_ptr <message> IMAPFolder::getMessage(const int num) -{ - if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - if (num < 1 || num > m_status->getMessageCount()) - throw exceptions::message_not_found(); - - return make_shared <IMAPMessage>(dynamicCast <IMAPFolder>(shared_from_this()), num); -} - - -std::vector <shared_ptr <message> > IMAPFolder::getMessages(const messageSet& msgs) -{ - if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - if (msgs.isEmpty()) - return std::vector <shared_ptr <message> >(); - - std::vector <shared_ptr <message> > messages; - - if (msgs.isNumberSet()) - { - const std::vector <int> numbers = IMAPUtils::messageSetToNumberList(msgs); - - shared_ptr <IMAPFolder> thisFolder = dynamicCast <IMAPFolder>(shared_from_this()); - - for (std::vector <int>::const_iterator it = numbers.begin() ; it != numbers.end() ; ++it) - messages.push_back(make_shared <IMAPMessage>(thisFolder, *it)); - } - else if (msgs.isUIDSet()) - { - // C: . UID FETCH uuuu1,uuuu2,uuuu3 UID - // S: * nnnn1 FETCH (UID uuuu1) - // S: * nnnn2 FETCH (UID uuuu2) - // S: * nnnn3 FETCH (UID uuuu3) - // S: . OK UID FETCH completed - - // Prepare command and arguments - std::ostringstream cmd; - cmd.imbue(std::locale::classic()); - - cmd << "UID FETCH " << IMAPUtils::messageSetToSequenceSet(msgs) << " UID"; - - // Send the request - m_connection->send(true, cmd.str(), true); - - // Get the response - std::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("UID FETCH ... UID", resp->getErrorLog(), "bad response"); - } - - // Process the 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("UID FETCH ... UID", - resp->getErrorLog(), "invalid response"); - } - - const IMAPParser::message_data* messageData = - (*it)->response_data()->message_data(); - - // We are only interested in responses of type "FETCH" - if (messageData == NULL || messageData->type() != IMAPParser::message_data::FETCH) - continue; - - // Get Process fetch response for this message - const int msgNum = static_cast <int>(messageData->number()); - message::uid msgUID; - - // Find UID in message attributes - const std::vector <IMAPParser::msg_att_item*> atts = messageData->msg_att()->items(); - - for (std::vector <IMAPParser::msg_att_item*>::const_iterator - it = atts.begin() ; it != atts.end() ; ++it) - { - if ((*it)->type() == IMAPParser::msg_att_item::UID) - { - msgUID = (*it)->unique_id()->value(); - break; - } - } - - if (!msgUID.empty()) - { - shared_ptr <IMAPFolder> thisFolder = dynamicCast <IMAPFolder>(shared_from_this()); - messages.push_back(make_shared <IMAPMessage>(thisFolder, msgNum, msgUID)); - } - } - } - - return messages; -} - - -int IMAPFolder::getMessageCount() -{ - if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - return m_status->getMessageCount(); -} - - -vmime_uint32 IMAPFolder::getUIDValidity() const -{ - if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - return m_status->getUIDValidity(); -} - - -vmime_uint64 IMAPFolder::getHighestModSequence() const -{ - if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - return m_status->getHighestModSeq(); -} - - -shared_ptr <folder> IMAPFolder::getFolder(const folder::path::component& name) -{ - shared_ptr <IMAPStore> store = m_store.lock(); - - if (!store) - throw exceptions::illegal_state("Store disconnected"); - - return make_shared <IMAPFolder>(m_path / name, store); -} - - -std::vector <shared_ptr <folder> > IMAPFolder::getFolders(const bool recursive) -{ - shared_ptr <IMAPStore> store = m_store.lock(); - - 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) - { - oss << IMAPUtils::quoteString(pathString); - oss << " *"; - } - else - { - if (pathString.empty()) // don't add sep for root folder - oss << "\"\""; - else - oss << IMAPUtils::quoteString(pathString + m_connection->hierarchySeparator()); - - oss << " %"; - } - - m_connection->send(true, oss.str(), true); - - - std::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", resp->getErrorLog(), "bad response"); - } - - const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList = - resp->continue_req_or_response_data(); - - - std::vector <shared_ptr <folder> > v; - - 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", - resp->getErrorLog(), "invalid response"); - } - - const IMAPParser::mailbox_data* mailboxData = - (*it)->response_data()->mailbox_data(); - - if (mailboxData == NULL || mailboxData->type() != IMAPParser::mailbox_data::LIST) - continue; - - // Get folder path - const class IMAPParser::mailbox* mailbox = - mailboxData->mailbox_list()->mailbox(); - - folder::path path = IMAPUtils::stringToPath - (mailboxData->mailbox_list()->quoted_char(), mailbox->name()); - - if (recursive || m_path.isDirectParentOf(path)) - { - // Append folder to list - const class IMAPParser::mailbox_flag_list* mailbox_flag_list = - mailboxData->mailbox_list()->mailbox_flag_list(); - - v.push_back(make_shared <IMAPFolder>(path, store, - IMAPUtils::folderTypeFromFlags(mailbox_flag_list), - IMAPUtils::folderFlagsFromFlags(mailbox_flag_list))); - } - } - - return (v); -} - - -void IMAPFolder::fetchMessages(std::vector <shared_ptr <message> >& msg, const fetchAttributes& options, - utility::progressListener* progress) -{ - shared_ptr <IMAPStore> store = m_store.lock(); - - if (!store) - throw exceptions::illegal_state("Store disconnected"); - else if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - // Build message numbers list - std::vector <int> list; - list.reserve(msg.size()); - - std::map <int, shared_ptr <IMAPMessage> > numberToMsg; - - for (std::vector <shared_ptr <message> >::iterator it = msg.begin() ; it != msg.end() ; ++it) - { - list.push_back((*it)->getNumber()); - numberToMsg[(*it)->getNumber()] = dynamicCast <IMAPMessage>(*it); - } - - // Send the request - const string command = IMAPUtils::buildFetchRequest - (m_connection, messageSet::byNumber(list), options); - - m_connection->send(true, command, true); - - // Get the response - std::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("FETCH", - resp->getErrorLog(), "bad response"); - } - - const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList = - resp->continue_req_or_response_data(); - - const size_t total = msg.size(); - size_t current = 0; - - if (progress) - progress->start(total); - - try - { - 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("FETCH", - resp->getErrorLog(), "invalid response"); - } - - const IMAPParser::message_data* messageData = - (*it)->response_data()->message_data(); - - // We are only interested in responses of type "FETCH" - if (messageData == NULL || messageData->type() != IMAPParser::message_data::FETCH) - continue; - - // Process fetch response for this message - const int num = static_cast <int>(messageData->number()); - - std::map <int, shared_ptr <IMAPMessage> >::iterator msg = numberToMsg.find(num); - - if (msg != numberToMsg.end()) - { - (*msg).second->processFetchResponse(options, messageData); - - if (progress) - progress->progress(++current, total); - } - } - } - catch (...) - { - if (progress) - progress->stop(total); - - throw; - } - - if (progress) - progress->stop(total); - - processStatusUpdate(resp.get()); -} - - -void IMAPFolder::fetchMessage(shared_ptr <message> msg, const fetchAttributes& options) -{ - std::vector <shared_ptr <message> > msgs; - msgs.push_back(msg); - - fetchMessages(msgs, options, /* progress */ NULL); -} - - -int IMAPFolder::getFetchCapabilities() const -{ - return fetchAttributes::ENVELOPE | fetchAttributes::CONTENT_INFO | - fetchAttributes::STRUCTURE | fetchAttributes::FLAGS | - fetchAttributes::SIZE | fetchAttributes::FULL_HEADER | - fetchAttributes::UID | fetchAttributes::IMPORTANCE; -} - - -shared_ptr <folder> IMAPFolder::getParent() -{ - if (m_path.isEmpty()) - return null; - else - return make_shared <IMAPFolder>(m_path.getParent(), m_store.lock()); -} - - -shared_ptr <const store> IMAPFolder::getStore() const -{ - return m_store.lock(); -} - - -shared_ptr <store> IMAPFolder::getStore() -{ - return m_store.lock(); -} - - -void IMAPFolder::registerMessage(IMAPMessage* msg) -{ - m_messages.push_back(msg); -} - - -void IMAPFolder::unregisterMessage(IMAPMessage* msg) -{ - std::vector <IMAPMessage*>::iterator it = - std::find(m_messages.begin(), m_messages.end(), msg); - - if (it != m_messages.end()) - m_messages.erase(it); -} - - -void IMAPFolder::onStoreDisconnected() -{ - m_store.reset(); -} - - -void IMAPFolder::deleteMessages(const messageSet& msgs) -{ - shared_ptr <IMAPStore> store = m_store.lock(); - - if (msgs.isEmpty()) - throw exceptions::invalid_argument(); - - if (!store) - throw exceptions::illegal_state("Store disconnected"); - else if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - else if (m_mode == MODE_READ_ONLY) - throw exceptions::illegal_state("Folder is read-only"); - - // Build the request text - std::ostringstream command; - command.imbue(std::locale::classic()); - - if (msgs.isUIDSet()) - command << "UID STORE " << IMAPUtils::messageSetToSequenceSet(msgs); - else - command << "STORE " << IMAPUtils::messageSetToSequenceSet(msgs); - - command << " +FLAGS (\\Deleted)"; - - // Send the request - m_connection->send(true, command.str(), true); - - // Get the response - std::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("STORE", - resp->getErrorLog(), "bad response"); - } - - processStatusUpdate(resp.get()); -} - - -void IMAPFolder::setMessageFlags(const messageSet& msgs, const int flags, const int mode) -{ - // Build the request text - std::ostringstream command; - command.imbue(std::locale::classic()); - - if (msgs.isUIDSet()) - command << "UID STORE " << IMAPUtils::messageSetToSequenceSet(msgs); - else - command << "STORE " << IMAPUtils::messageSetToSequenceSet(msgs); - - switch (mode) - { - case message::FLAG_MODE_ADD: command << " +FLAGS "; break; - case message::FLAG_MODE_REMOVE: command << " -FLAGS "; break; - default: - case message::FLAG_MODE_SET: command << " FLAGS "; break; - } - - const string flagList = IMAPUtils::messageFlagList(flags); - - if (!flagList.empty()) - { - command << flagList; - - // Send the request - m_connection->send(true, command.str(), true); - - // Get the response - std::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("STORE", - resp->getErrorLog(), "bad response"); - } - - processStatusUpdate(resp.get()); - } -} - - -void IMAPFolder::addMessage(shared_ptr <vmime::message> msg, const int flags, - vmime::datetime* date, utility::progressListener* progress) -{ - std::ostringstream oss; - utility::outputStreamAdapter ossAdapter(oss); - - msg->generate(ossAdapter); - - const string& str = oss.str(); - utility::inputStreamStringAdapter strAdapter(str); - - addMessage(strAdapter, str.length(), flags, date, progress); -} - - -void IMAPFolder::addMessage(utility::inputStream& is, const size_t size, const int flags, - vmime::datetime* date, utility::progressListener* progress) -{ - shared_ptr <IMAPStore> store = m_store.lock(); - - if (!store) - throw exceptions::illegal_state("Store disconnected"); - else if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - else if (m_mode == MODE_READ_ONLY) - throw exceptions::illegal_state("Folder is read-only"); - - // Build the request text - std::ostringstream command; - command.imbue(std::locale::classic()); - - command << "APPEND " << IMAPUtils::quoteString(IMAPUtils::pathToString - (m_connection->hierarchySeparator(), getFullPath())) << ' '; - - const string flagList = IMAPUtils::messageFlagList(flags); - - if (flags != message::FLAG_UNDEFINED && !flagList.empty()) - { - command << flagList; - command << ' '; - } - - if (date != NULL) - { - command << IMAPUtils::dateTime(*date); - command << ' '; - } - - command << '{' << size << '}'; - - // Send the request - m_connection->send(true, command.str(), true); - - // Get the response - std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse()); - - bool ok = false; - const std::vector <IMAPParser::continue_req_or_response_data*>& respList - = resp->continue_req_or_response_data(); - - for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator - it = respList.begin() ; !ok && (it != respList.end()) ; ++it) - { - if ((*it)->continue_req()) - ok = true; - } - - if (!ok) - { - throw exceptions::command_error("APPEND", - resp->getErrorLog(), "bad response"); - } - - // Send message data - const size_t total = size; - size_t current = 0; - - if (progress) - progress->start(total); - - const size_t blockSize = std::min(is.getBlockSize(), - static_cast <size_t>(m_connection->getSocket()->getBlockSize())); - - std::vector <byte_t> vbuffer(blockSize); - byte_t* buffer = &vbuffer.front(); - - while (!is.eof()) - { - // Read some data from the input stream - const size_t read = is.read(buffer, sizeof(buffer)); - current += read; - - // Put read data into socket output stream - m_connection->sendRaw(buffer, read); - - // Notify progress - if (progress) - progress->progress(current, total); - } - - m_connection->send(false, "", true); - - if (progress) - progress->stop(total); - - // Get the response - std::auto_ptr <IMAPParser::response> finalResp(m_connection->readResponse()); - - if (finalResp->isBad() || finalResp->response_done()->response_tagged()-> - resp_cond_state()->status() != IMAPParser::resp_cond_state::OK) - { - throw exceptions::command_error("APPEND", - resp->getErrorLog(), "bad response"); - } - - processStatusUpdate(resp.get()); -} - - -void IMAPFolder::expunge() -{ - shared_ptr <IMAPStore> store = m_store.lock(); - - if (!store) - throw exceptions::illegal_state("Store disconnected"); - else if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - else if (m_mode == MODE_READ_ONLY) - throw exceptions::illegal_state("Folder is read-only"); - - // Send the request - m_connection->send(true, "EXPUNGE", true); - - // Get the response - std::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("EXPUNGE", - resp->getErrorLog(), "bad response"); - } - - processStatusUpdate(resp.get()); -} - - -void IMAPFolder::rename(const folder::path& newPath) -{ - shared_ptr <IMAPStore> store = m_store.lock(); - - if (!store) - throw exceptions::illegal_state("Store disconnected"); - else if (m_path.isEmpty() || newPath.isEmpty()) - throw exceptions::illegal_operation("Cannot rename root folder"); - else if (m_path.getSize() == 1 && m_name.getBuffer() == "INBOX") - throw exceptions::illegal_operation("Cannot rename 'INBOX' folder"); - else if (!store->isValidFolderName(newPath.getLastComponent())) - throw exceptions::invalid_folder_name(); - - // Build the request text - std::ostringstream command; - command.imbue(std::locale::classic()); - - command << "RENAME "; - command << IMAPUtils::quoteString(IMAPUtils::pathToString - (m_connection->hierarchySeparator(), getFullPath())) << " "; - command << IMAPUtils::quoteString(IMAPUtils::pathToString - (m_connection->hierarchySeparator(), newPath)); - - // Send the request - m_connection->send(true, command.str(), true); - - // Get the response - std::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("RENAME", - resp->getErrorLog(), "bad response"); - } - - // Notify folder renamed - folder::path oldPath(m_path); - - m_path = newPath; - m_name = newPath.getLastComponent(); - - shared_ptr <events::folderEvent> event = - make_shared <events::folderEvent> - (dynamicCast <folder>(shared_from_this()), - events::folderEvent::TYPE_RENAMED, oldPath, newPath); - - notifyFolder(event); - - // Notify sub-folders - for (std::list <IMAPFolder*>::iterator it = store->m_folders.begin() ; - it != store->m_folders.end() ; ++it) - { - if ((*it) != this && oldPath.isParentOf((*it)->getFullPath())) - { - folder::path oldPath((*it)->m_path); - - (*it)->m_path.renameParent(oldPath, newPath); - - shared_ptr <events::folderEvent> event = - make_shared <events::folderEvent> - (dynamicCast <folder>((*it)->shared_from_this()), - events::folderEvent::TYPE_RENAMED, oldPath, (*it)->m_path); - - (*it)->notifyFolder(event); - } - } - - processStatusUpdate(resp.get()); -} - - -void IMAPFolder::copyMessages(const folder::path& dest, const messageSet& set) -{ - shared_ptr <IMAPStore> store = m_store.lock(); - - if (!store) - throw exceptions::illegal_state("Store disconnected"); - else if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - // Build the request text - std::ostringstream command; - command.imbue(std::locale::classic()); - - command << "COPY " << IMAPUtils::messageSetToSequenceSet(set) << " "; - command << IMAPUtils::quoteString(IMAPUtils::pathToString - (m_connection->hierarchySeparator(), dest)); - - // Send the request - m_connection->send(true, command.str(), true); - - // Get the response - std::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("COPY", - resp->getErrorLog(), "bad response"); - } - - processStatusUpdate(resp.get()); -} - - -void IMAPFolder::status(int& count, int& unseen) -{ - count = 0; - unseen = 0; - - shared_ptr <folderStatus> status = getStatus(); - - count = status->getMessageCount(); - unseen = status->getUnseenCount(); -} - - -shared_ptr <folderStatus> IMAPFolder::getStatus() -{ - shared_ptr <IMAPStore> store = m_store.lock(); - - if (!store) - throw exceptions::illegal_state("Store disconnected"); - - // Build the request text - std::ostringstream command; - command.imbue(std::locale::classic()); - - command << "STATUS "; - command << IMAPUtils::quoteString(IMAPUtils::pathToString - (m_connection->hierarchySeparator(), getFullPath())); - command << " ("; - - command << "MESSAGES" << ' ' << "UNSEEN" << ' ' << "UIDNEXT" << ' ' << "UIDVALIDITY"; - - if (m_connection->hasCapability("CONDSTORE")) - command << ' ' << "HIGHESTMODSEQ"; - - command << ")"; - - // Send the request - m_connection->send(true, command.str(), true); - - // Get the response - std::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("STATUS", - resp->getErrorLog(), "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) - { - const IMAPParser::response_data* responseData = (*it)->response_data(); - - if (responseData->mailbox_data() && - responseData->mailbox_data()->type() == IMAPParser::mailbox_data::STATUS) - { - shared_ptr <IMAPFolderStatus> status = make_shared <IMAPFolderStatus>(); - status->updateFromResponse(responseData->mailbox_data()); - - m_status->updateFromResponse(responseData->mailbox_data()); - - return status; - } - } - } - - throw exceptions::command_error("STATUS", - resp->getErrorLog(), "invalid response"); -} - - -void IMAPFolder::noop() -{ - shared_ptr <IMAPStore> store = m_store.lock(); - - if (!store) - throw exceptions::illegal_state("Store disconnected"); - - m_connection->send(true, "NOOP", true); - - std::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("NOOP", resp->getErrorLog()); - } - - processStatusUpdate(resp.get()); -} - - -std::vector <int> IMAPFolder::getMessageNumbersStartingOnUID(const message::uid& uid) -{ - std::vector<int> v; - - std::ostringstream command; - command.imbue(std::locale::classic()); - - command << "SEARCH UID " << uid << ":*"; - - // Send the request - m_connection->send(true, command.str(), true); - - // Get the response - std::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("SEARCH", - resp->getErrorLog(), "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("SEARCH", - resp->getErrorLog(), "invalid response"); - } - - const IMAPParser::mailbox_data* mailboxData = - (*it)->response_data()->mailbox_data(); - - // We are only interested in responses of type "SEARCH" - if (mailboxData == NULL || - mailboxData->type() != IMAPParser::mailbox_data::SEARCH) - { - continue; - } - - for (std::vector <IMAPParser::nz_number*>::const_iterator - it = mailboxData->search_nz_number_list().begin() ; - it != mailboxData->search_nz_number_list().end(); - ++it) - { - v.push_back((*it)->value()); - } - } - - processStatusUpdate(resp.get()); - - return v; -} - - -void IMAPFolder::processStatusUpdate(const IMAPParser::response* resp) -{ - std::vector <shared_ptr <events::event> > events; - - shared_ptr <IMAPFolderStatus> oldStatus = vmime::clone(m_status); - int expungedMessageCount = 0; - - // Process tagged response - if (resp->response_done() && resp->response_done()->response_tagged() && - resp->response_done()->response_tagged() - ->resp_cond_state()->resp_text()->resp_text_code()) - { - const IMAPParser::resp_text_code* code = - resp->response_done()->response_tagged() - ->resp_cond_state()->resp_text()->resp_text_code(); - - m_status->updateFromResponse(code); - } - - // Process untagged responses - for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator - it = resp->continue_req_or_response_data().begin() ; - it != resp->continue_req_or_response_data().end() ; ++it) - { - if ((*it)->response_data() && (*it)->response_data()->resp_cond_state() && - (*it)->response_data()->resp_cond_state()->resp_text()->resp_text_code()) - { - const IMAPParser::resp_text_code* code = - (*it)->response_data()->resp_cond_state()->resp_text()->resp_text_code(); - - m_status->updateFromResponse(code); - } - else if ((*it)->response_data() && (*it)->response_data()->mailbox_data()) - { - m_status->updateFromResponse((*it)->response_data()->mailbox_data()); - } - else if ((*it)->response_data() && (*it)->response_data()->message_data()) - { - const IMAPParser::message_data* msgData = (*it)->response_data()->message_data(); - const int msgNumber = msgData->number(); - - if ((*it)->response_data()->message_data()->type() == IMAPParser::message_data::FETCH) - { - // Message changed - for (std::vector <IMAPMessage*>::iterator mit = - m_messages.begin() ; mit != m_messages.end() ; ++mit) - { - if ((*mit)->getNumber() == msgNumber) - (*mit)->processFetchResponse(/* options */ 0, msgData); - } - - events.push_back(make_shared <events::messageChangedEvent> - (dynamicCast <folder>(shared_from_this()), - events::messageChangedEvent::TYPE_FLAGS, - std::vector <int>(1, msgNumber))); - } - else if ((*it)->response_data()->message_data()->type() == IMAPParser::message_data::EXPUNGE) - { - // A message has been expunged, renumber messages - for (std::vector <IMAPMessage*>::iterator jt = - m_messages.begin() ; jt != m_messages.end() ; ++jt) - { - if ((*jt)->getNumber() == msgNumber) - (*jt)->setExpunged(); - else if ((*jt)->getNumber() > msgNumber) - (*jt)->renumber((*jt)->getNumber() - 1); - } - - events.push_back(make_shared <events::messageCountEvent> - (dynamicCast <folder>(shared_from_this()), - events::messageCountEvent::TYPE_REMOVED, - std::vector <int>(1, msgNumber))); - - expungedMessageCount++; - } - } - } - - // New messages arrived - if (m_status->getMessageCount() > oldStatus->getMessageCount() - expungedMessageCount) - { - std::vector <int> newMessageNumbers; - - for (int msgNumber = oldStatus->getMessageCount() - expungedMessageCount ; - msgNumber <= m_status->getMessageCount() ; ++msgNumber) - { - newMessageNumbers.push_back(msgNumber); - } - - events.push_back(make_shared <events::messageCountEvent> - (dynamicCast <folder>(shared_from_this()), - events::messageCountEvent::TYPE_ADDED, - newMessageNumbers)); - } - - // Dispatch notifications - for (std::vector <shared_ptr <events::event> >::iterator evit = - events.begin() ; evit != events.end() ; ++evit) - { - notifyEvent(*evit); - } -} - - -} // imap -} // net -} // vmime - - -#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP - diff --git a/src/net/imap/IMAPFolderStatus.cpp b/src/net/imap/IMAPFolderStatus.cpp deleted file mode 100644 index c78a40f3..00000000 --- a/src/net/imap/IMAPFolderStatus.cpp +++ /dev/null @@ -1,307 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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_IMAP - - -#include "vmime/net/imap/IMAPFolderStatus.hpp" - - -namespace vmime { -namespace net { -namespace imap { - - -IMAPFolderStatus::IMAPFolderStatus() - : m_count(0), - m_unseen(0), - m_recent(0), - m_uidValidity(0), - m_uidNext(0), - m_highestModSeq(0) -{ -} - - -IMAPFolderStatus::IMAPFolderStatus(const IMAPFolderStatus& other) - : folderStatus(), - m_count(other.m_count), - m_unseen(other.m_unseen), - m_recent(other.m_recent), - m_uidValidity(other.m_uidValidity), - m_uidNext(other.m_uidNext), - m_highestModSeq(other.m_highestModSeq) -{ -} - - -unsigned int IMAPFolderStatus::getMessageCount() const -{ - return m_count; -} - - -unsigned int IMAPFolderStatus::getUnseenCount() const -{ - return m_unseen; -} - - -unsigned int IMAPFolderStatus::getRecentCount() const -{ - return m_recent; -} - - -vmime_uint32 IMAPFolderStatus::getUIDValidity() const -{ - return m_uidValidity; -} - - -vmime_uint32 IMAPFolderStatus::getUIDNext() const -{ - return m_uidNext; -} - - -vmime_uint64 IMAPFolderStatus::getHighestModSeq() const -{ - return m_highestModSeq; -} - - -shared_ptr <folderStatus> IMAPFolderStatus::clone() const -{ - return make_shared <IMAPFolderStatus>(*this); -} - - -bool IMAPFolderStatus::updateFromResponse(const IMAPParser::mailbox_data* resp) -{ - bool changed = false; - - if (resp->type() == IMAPParser::mailbox_data::STATUS) - { - const IMAPParser::status_att_list* statusAttList = resp->status_att_list(); - - for (std::vector <IMAPParser::status_att_val*>::const_iterator - jt = statusAttList->values().begin() ; jt != statusAttList->values().end() ; ++jt) - { - switch ((*jt)->type()) - { - case IMAPParser::status_att_val::MESSAGES: - { - const unsigned int count = - static_cast <unsigned int>((*jt)->value_as_number()->value()); - - if (m_count != count) - { - m_count = count; - changed = true; - } - - break; - } - case IMAPParser::status_att_val::UNSEEN: - { - const unsigned int unseen = - static_cast <unsigned int>((*jt)->value_as_number()->value()); - - if (m_unseen != unseen) - { - m_unseen = unseen; - changed = true; - } - - break; - } - case IMAPParser::status_att_val::RECENT: - { - const unsigned int recent = - static_cast <unsigned int>((*jt)->value_as_number()->value()); - - if (m_recent != recent) - { - m_recent = recent; - changed = true; - } - - break; - } - case IMAPParser::status_att_val::UIDNEXT: - { - const vmime_uint32 uidNext = - static_cast <vmime_uint32>((*jt)->value_as_number()->value()); - - if (m_uidNext != uidNext) - { - m_uidNext = uidNext; - changed = true; - } - - break; - } - case IMAPParser::status_att_val::UIDVALIDITY: - { - const vmime_uint32 uidValidity = - static_cast <vmime_uint32>((*jt)->value_as_number()->value()); - - if (m_uidValidity != uidValidity) - { - m_uidValidity = uidValidity; - changed = true; - } - - break; - } - case IMAPParser::status_att_val::HIGHESTMODSEQ: - { - const vmime_uint64 highestModSeq = - static_cast <vmime_uint64>((*jt)->value_as_mod_sequence_value()->value()); - - if (m_highestModSeq != highestModSeq) - { - m_highestModSeq = highestModSeq; - changed = true; - } - - break; - } - - } - } - } - else if (resp->type() == IMAPParser::mailbox_data::EXISTS) - { - const unsigned int count = - static_cast <unsigned int>(resp->number()->value()); - - if (m_count != count) - { - m_count = count; - changed = true; - } - } - else if (resp->type() == IMAPParser::mailbox_data::RECENT) - { - const unsigned int recent = - static_cast <unsigned int>(resp->number()->value()); - - if (m_recent != recent) - { - m_recent = recent; - changed = true; - } - } - - return changed; -} - - -bool IMAPFolderStatus::updateFromResponse(const IMAPParser::resp_text_code* resp) -{ - bool changed = false; - - switch (resp->type()) - { - case IMAPParser::resp_text_code::UIDVALIDITY: - { - const vmime_uint32 uidValidity = - static_cast <vmime_uint32>(resp->nz_number()->value()); - - if (m_uidValidity != uidValidity) - { - m_uidValidity = uidValidity; - changed = true; - } - - break; - } - case IMAPParser::resp_text_code::UIDNEXT: - { - const vmime_uint32 uidNext = - static_cast <vmime_uint32>(resp->nz_number()->value()); - - if (m_uidNext != uidNext) - { - m_uidNext = uidNext; - changed = true; - } - - break; - } - case IMAPParser::resp_text_code::UNSEEN: - { - const unsigned int unseen = - static_cast <unsigned int>(resp->nz_number()->value()); - - if (m_unseen != unseen) - { - m_unseen = unseen; - changed = true; - } - - break; - } - case IMAPParser::resp_text_code::HIGHESTMODSEQ: - { - const vmime_uint64 highestModSeq = - static_cast <vmime_uint64>(resp->mod_sequence_value()->value()); - - if (m_highestModSeq != highestModSeq) - { - m_highestModSeq = highestModSeq; - changed = true; - } - - break; - } - case IMAPParser::resp_text_code::NOMODSEQ: - { - if (m_highestModSeq != 0) - { - m_highestModSeq = 0; - changed = true; - } - - break; - } - default: - - break; - } - - return changed; -} - - -} // imap -} // net -} // vmime - - -#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP diff --git a/src/net/imap/IMAPMessage.cpp b/src/net/imap/IMAPMessage.cpp deleted file mode 100644 index c11aafc2..00000000 --- a/src/net/imap/IMAPMessage.cpp +++ /dev/null @@ -1,649 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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_IMAP - - -#include "vmime/net/imap/IMAPParser.hpp" -#include "vmime/net/imap/IMAPMessage.hpp" -#include "vmime/net/imap/IMAPFolder.hpp" -#include "vmime/net/imap/IMAPFolderStatus.hpp" -#include "vmime/net/imap/IMAPStore.hpp" -#include "vmime/net/imap/IMAPConnection.hpp" -#include "vmime/net/imap/IMAPUtils.hpp" -#include "vmime/net/imap/IMAPMessageStructure.hpp" -#include "vmime/net/imap/IMAPMessagePart.hpp" -#include "vmime/net/imap/IMAPMessagePartContentHandler.hpp" - -#include "vmime/utility/outputStreamAdapter.hpp" - -#include <sstream> -#include <iterator> -#include <typeinfo> - - -namespace vmime { -namespace net { -namespace imap { - - -#ifndef VMIME_BUILDING_DOC - -// -// IMAPMessage_literalHandler -// - -class IMAPMessage_literalHandler : public IMAPParser::literalHandler -{ -public: - - IMAPMessage_literalHandler(utility::outputStream& os, utility::progressListener* progress) - : m_os(os), m_progress(progress) - { - } - - target* targetFor(const IMAPParser::component& comp, const int /* data */) - { - if (typeid(comp) == typeid(IMAPParser::msg_att_item)) - { - const int type = static_cast - <const IMAPParser::msg_att_item&>(comp).type(); - - if (type == IMAPParser::msg_att_item::BODY_SECTION || - type == IMAPParser::msg_att_item::RFC822_TEXT) - { - return new targetStream(m_progress, m_os); - } - } - - return (NULL); - } - -private: - - utility::outputStream& m_os; - utility::progressListener* m_progress; -}; - -#endif // VMIME_BUILDING_DOC - - - -// -// IMAPMessage -// - - -IMAPMessage::IMAPMessage(shared_ptr <IMAPFolder> folder, const int num) - : m_folder(folder), m_num(num), m_size(-1U), m_flags(FLAG_UNDEFINED), - m_expunged(false), m_modseq(0), m_structure(null) -{ - folder->registerMessage(this); -} - - -IMAPMessage::IMAPMessage(shared_ptr <IMAPFolder> folder, const int num, const uid& uid) - : m_folder(folder), m_num(num), m_size(-1), m_flags(FLAG_UNDEFINED), - m_expunged(false), m_uid(uid), m_modseq(0), m_structure(null) -{ - folder->registerMessage(this); -} - - -IMAPMessage::~IMAPMessage() -{ - shared_ptr <IMAPFolder> folder = m_folder.lock(); - - if (folder) - folder->unregisterMessage(this); -} - - -void IMAPMessage::onFolderClosed() -{ - m_folder.reset(); -} - - -int IMAPMessage::getNumber() const -{ - return (m_num); -} - - -const message::uid IMAPMessage::getUID() const -{ - return m_uid; -} - - -vmime_uint64 IMAPMessage::getModSequence() const -{ - return m_modseq; -} - - -size_t IMAPMessage::getSize() const -{ - if (m_size == -1U) - throw exceptions::unfetched_object(); - - return (m_size); -} - - -bool IMAPMessage::isExpunged() const -{ - return (m_expunged); -} - - -int IMAPMessage::getFlags() const -{ - if (m_flags == FLAG_UNDEFINED) - throw exceptions::unfetched_object(); - - return (m_flags); -} - - -shared_ptr <const messageStructure> IMAPMessage::getStructure() const -{ - if (m_structure == NULL) - throw exceptions::unfetched_object(); - - return m_structure; -} - - -shared_ptr <messageStructure> IMAPMessage::getStructure() -{ - if (m_structure == NULL) - throw exceptions::unfetched_object(); - - return m_structure; -} - - -shared_ptr <const header> IMAPMessage::getHeader() const -{ - if (m_header == NULL) - throw exceptions::unfetched_object(); - - return (m_header); -} - - -void IMAPMessage::extract - (utility::outputStream& os, - utility::progressListener* progress, - const size_t start, const size_t length, - const bool peek) const -{ - shared_ptr <const IMAPFolder> folder = m_folder.lock(); - - if (!folder) - throw exceptions::folder_not_found(); - - extractImpl(null, os, progress, start, length, - EXTRACT_HEADER | EXTRACT_BODY | (peek ? EXTRACT_PEEK : 0)); -} - - -void IMAPMessage::extractPart - (shared_ptr <const messagePart> p, - utility::outputStream& os, - utility::progressListener* progress, - const size_t start, const size_t length, - const bool peek) const -{ - shared_ptr <const IMAPFolder> folder = m_folder.lock(); - - if (!folder) - throw exceptions::folder_not_found(); - - extractImpl(p, os, progress, start, length, - EXTRACT_HEADER | EXTRACT_BODY | (peek ? EXTRACT_PEEK : 0)); -} - - -void IMAPMessage::fetchPartHeader(shared_ptr <messagePart> p) -{ - shared_ptr <IMAPFolder> folder = m_folder.lock(); - - if (!folder) - throw exceptions::folder_not_found(); - - std::ostringstream oss; - utility::outputStreamAdapter ossAdapter(oss); - - extractImpl(p, ossAdapter, NULL, 0, -1, EXTRACT_HEADER | EXTRACT_PEEK); - - dynamicCast <IMAPMessagePart>(p)->getOrCreateHeader().parse(oss.str()); -} - - -void IMAPMessage::fetchPartHeaderForStructure(shared_ptr <messageStructure> str) -{ - for (size_t i = 0, n = str->getPartCount() ; i < n ; ++i) - { - shared_ptr <messagePart> part = str->getPartAt(i); - - // Fetch header of current part - fetchPartHeader(part); - - // Fetch header of sub-parts - fetchPartHeaderForStructure(part->getStructure()); - } -} - - -void IMAPMessage::extractImpl - (shared_ptr <const messagePart> p, - utility::outputStream& os, - utility::progressListener* progress, - const size_t start, const size_t length, - const int extractFlags) const -{ - shared_ptr <const IMAPFolder> folder = m_folder.lock(); - - IMAPMessage_literalHandler literalHandler(os, progress); - - // Construct section identifier - std::ostringstream section; - section.imbue(std::locale::classic()); - - if (p != NULL) - { - shared_ptr <const IMAPMessagePart> currentPart = dynamicCast <const IMAPMessagePart>(p); - std::vector <int> numbers; - - numbers.push_back(currentPart->getNumber()); - currentPart = currentPart->getParent(); - - while (currentPart != NULL) - { - numbers.push_back(currentPart->getNumber()); - currentPart = currentPart->getParent(); - } - - numbers.erase(numbers.end() - 1); - - for (std::vector <int>::reverse_iterator it = numbers.rbegin() ; it != numbers.rend() ; ++it) - { - if (it != numbers.rbegin()) section << "."; - section << (*it + 1); - } - } - - // Build the request text - std::ostringstream command; - command.imbue(std::locale::classic()); - - if (m_uid.empty()) - command << "FETCH " << m_num << " BODY"; - else - command << "UID FETCH " << m_uid << " BODY"; - - /* - BODY[] header + body - BODY.PEEK[] header + body (peek) - BODY[HEADER] header - BODY.PEEK[HEADER] header (peek) - BODY[TEXT] body - BODY.PEEK[TEXT] body (peek) - */ - - if (extractFlags & EXTRACT_PEEK) - command << ".PEEK"; - - command << "["; - - if (section.str().empty()) - { - // header + body - if ((extractFlags & EXTRACT_HEADER) && (extractFlags & EXTRACT_BODY)) - command << ""; - // body only - else if (extractFlags & EXTRACT_BODY) - command << "TEXT"; - // header only - else if (extractFlags & EXTRACT_HEADER) - command << "HEADER"; - } - else - { - command << section.str(); - - // header + body - if ((extractFlags & EXTRACT_HEADER) && (extractFlags & EXTRACT_BODY)) - throw exceptions::operation_not_supported(); - // body only - else if (extractFlags & EXTRACT_BODY) - command << ".TEXT"; - // header only - else if (extractFlags & EXTRACT_HEADER) - command << ".MIME"; // "MIME" not "HEADER" for parts - } - - command << "]"; - - if (start != 0 || length != static_cast <size_t>(-1)) - command << "<" << start << "." << length << ">"; - - // Send the request - constCast <IMAPFolder>(folder)->m_connection->send(true, command.str(), true); - - // Get the response - std::auto_ptr <IMAPParser::response> resp - (constCast <IMAPFolder>(folder)->m_connection->readResponse(&literalHandler)); - - if (resp->isBad() || resp->response_done()->response_tagged()-> - resp_cond_state()->status() != IMAPParser::resp_cond_state::OK) - { - throw exceptions::command_error("FETCH", - resp->getErrorLog(), "bad response"); - } - - - if (extractFlags & EXTRACT_BODY) - { - // TODO: update the flags (eg. flag "\Seen" may have been set) - } -} - - -int IMAPMessage::processFetchResponse - (const fetchAttributes& options, const IMAPParser::message_data* msgData) -{ - shared_ptr <IMAPFolder> folder = m_folder.lock(); - - // Get message attributes - const std::vector <IMAPParser::msg_att_item*> atts = msgData->msg_att()->items(); - int changes = 0; - - for (std::vector <IMAPParser::msg_att_item*>::const_iterator - it = atts.begin() ; it != atts.end() ; ++it) - { - switch ((*it)->type()) - { - case IMAPParser::msg_att_item::FLAGS: - { - int flags = IMAPUtils::messageFlagsFromFlags((*it)->flag_list()); - - if (m_flags != flags) - { - m_flags = flags; - changes |= events::messageChangedEvent::TYPE_FLAGS; - } - - break; - } - case IMAPParser::msg_att_item::UID: - { - m_uid = (*it)->unique_id()->value(); - break; - } - case IMAPParser::msg_att_item::MODSEQ: - { - m_modseq = (*it)->mod_sequence_value()->value(); - break; - } - case IMAPParser::msg_att_item::ENVELOPE: - { - if (!options.has(fetchAttributes::FULL_HEADER)) - { - const IMAPParser::envelope* env = (*it)->envelope(); - shared_ptr <vmime::header> hdr = getOrCreateHeader(); - - // Date - hdr->Date()->setValue(env->env_date()->value()); - - // Subject - text subject; - text::decodeAndUnfold(env->env_subject()->value(), &subject); - - hdr->Subject()->setValue(subject); - - // From - mailboxList from; - IMAPUtils::convertAddressList(*(env->env_from()), from); - - if (!from.isEmpty()) - hdr->From()->setValue(*(from.getMailboxAt(0))); - - // To - mailboxList to; - IMAPUtils::convertAddressList(*(env->env_to()), to); - - hdr->To()->setValue(to.toAddressList()); - - // Sender - mailboxList sender; - IMAPUtils::convertAddressList(*(env->env_sender()), sender); - - if (!sender.isEmpty()) - hdr->Sender()->setValue(*(sender.getMailboxAt(0))); - - // Reply-to - mailboxList replyTo; - IMAPUtils::convertAddressList(*(env->env_reply_to()), replyTo); - - if (!replyTo.isEmpty()) - hdr->ReplyTo()->setValue(*(replyTo.getMailboxAt(0))); - - // Cc - mailboxList cc; - IMAPUtils::convertAddressList(*(env->env_cc()), cc); - - if (!cc.isEmpty()) - hdr->Cc()->setValue(cc); - - // Bcc - mailboxList bcc; - IMAPUtils::convertAddressList(*(env->env_bcc()), bcc); - - if (!bcc.isEmpty()) - hdr->Bcc()->setValue(bcc); - } - - break; - } - case IMAPParser::msg_att_item::BODY_STRUCTURE: - { - m_structure = make_shared <IMAPMessageStructure>((*it)->body()); - break; - } - case IMAPParser::msg_att_item::RFC822_HEADER: - { - getOrCreateHeader()->parse((*it)->nstring()->value()); - break; - } - case IMAPParser::msg_att_item::RFC822_SIZE: - { - m_size = static_cast <size_t>((*it)->number()->value()); - break; - } - case IMAPParser::msg_att_item::BODY_SECTION: - { - if (!options.has(fetchAttributes::FULL_HEADER)) - { - if ((*it)->section()->section_text1() && - (*it)->section()->section_text1()->type() - == IMAPParser::section_text::HEADER_FIELDS) - { - header tempHeader; - tempHeader.parse((*it)->nstring()->value()); - - vmime::header& hdr = *getOrCreateHeader(); - std::vector <shared_ptr <headerField> > fields = tempHeader.getFieldList(); - - for (std::vector <shared_ptr <headerField> >::const_iterator jt = fields.begin() ; - jt != fields.end() ; ++jt) - { - hdr.appendField(vmime::clone(*jt)); - } - } - } - - break; - } - case IMAPParser::msg_att_item::INTERNALDATE: - case IMAPParser::msg_att_item::RFC822: - case IMAPParser::msg_att_item::RFC822_TEXT: - case IMAPParser::msg_att_item::BODY: - { - break; - } - - } - } - - return changes; -} - - -shared_ptr <header> IMAPMessage::getOrCreateHeader() -{ - if (m_header != NULL) - return (m_header); - else - return (m_header = make_shared <header>()); -} - - -void IMAPMessage::setFlags(const int flags, const int mode) -{ - shared_ptr <IMAPFolder> folder = m_folder.lock(); - - if (!folder) - throw exceptions::folder_not_found(); - - if (!m_uid.empty()) - folder->setMessageFlags(messageSet::byUID(m_uid), flags, mode); - else - folder->setMessageFlags(messageSet::byNumber(m_num), flags, mode); -} - - -void IMAPMessage::constructParsedMessage - (shared_ptr <bodyPart> parentPart, shared_ptr <messageStructure> str, int level) -{ - if (level == 0) - { - shared_ptr <messagePart> part = str->getPartAt(0); - - // Copy header - shared_ptr <const header> hdr = part->getHeader(); - parentPart->getHeader()->copyFrom(*hdr); - - // Initialize body - parentPart->getBody()->setContents - (make_shared <IMAPMessagePartContentHandler> - (dynamicCast <IMAPMessage>(shared_from_this()), - part, parentPart->getBody()->getEncoding())); - - constructParsedMessage(parentPart, part->getStructure(), 1); - } - else - { - for (size_t i = 0, n = str->getPartCount() ; i < n ; ++i) - { - shared_ptr <messagePart> part = str->getPartAt(i); - - shared_ptr <bodyPart> childPart = make_shared <bodyPart>(); - - // Copy header - shared_ptr <const header> hdr = part->getHeader(); - childPart->getHeader()->copyFrom(*hdr); - - // Initialize body - childPart->getBody()->setContents - (make_shared <IMAPMessagePartContentHandler> - (dynamicCast <IMAPMessage>(shared_from_this()), - part, childPart->getBody()->getEncoding())); - - // Add child part - parentPart->getBody()->appendPart(childPart); - - // Construct sub parts - constructParsedMessage(childPart, part->getStructure(), ++level); - } - } -} - - -shared_ptr <vmime::message> IMAPMessage::getParsedMessage() -{ - // Fetch structure - shared_ptr <messageStructure> structure; - - try - { - structure = getStructure(); - } - catch (exceptions::unfetched_object&) - { - std::vector <shared_ptr <message> > msgs; - msgs.push_back(dynamicCast <IMAPMessage>(shared_from_this())); - - m_folder.lock()->fetchMessages - (msgs, fetchAttributes(fetchAttributes::STRUCTURE), /* progress */ NULL); - - structure = getStructure(); - } - - // Fetch header for each part - fetchPartHeaderForStructure(structure); - - // Construct message from structure - shared_ptr <vmime::message> msg = make_shared <vmime::message>(); - - constructParsedMessage(msg, structure); - - return msg; -} - - -void IMAPMessage::renumber(const int number) -{ - m_num = number; -} - - -void IMAPMessage::setExpunged() -{ - m_expunged = true; -} - - -} // imap -} // net -} // vmime - - -#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP - diff --git a/src/net/imap/IMAPMessagePart.cpp b/src/net/imap/IMAPMessagePart.cpp deleted file mode 100644 index eed885dc..00000000 --- a/src/net/imap/IMAPMessagePart.cpp +++ /dev/null @@ -1,161 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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_IMAP - - -#include "vmime/net/imap/IMAPMessagePart.hpp" -#include "vmime/net/imap/IMAPMessageStructure.hpp" - - -namespace vmime { -namespace net { -namespace imap { - - -IMAPMessagePart::IMAPMessagePart(shared_ptr <IMAPMessagePart> parent, const int number, const IMAPParser::body_type_mpart* mpart) - : m_parent(parent), m_header(null), m_number(number), m_size(0) -{ - m_mediaType = vmime::mediaType - ("multipart", mpart->media_subtype()->value()); -} - - -IMAPMessagePart::IMAPMessagePart(shared_ptr <IMAPMessagePart> parent, const int number, const IMAPParser::body_type_1part* part) - : m_parent(parent), m_header(null), m_number(number), m_size(0) -{ - if (part->body_type_text()) - { - m_mediaType = vmime::mediaType - ("text", part->body_type_text()-> - media_text()->media_subtype()->value()); - - m_size = part->body_type_text()->body_fields()->body_fld_octets()->value(); - } - else if (part->body_type_msg()) - { - m_mediaType = vmime::mediaType - ("message", part->body_type_msg()-> - media_message()->media_subtype()->value()); - } - else - { - m_mediaType = vmime::mediaType - (part->body_type_basic()->media_basic()->media_type()->value(), - part->body_type_basic()->media_basic()->media_subtype()->value()); - - m_size = part->body_type_basic()->body_fields()->body_fld_octets()->value(); - } - - m_structure = null; -} - - -shared_ptr <const messageStructure> IMAPMessagePart::getStructure() const -{ - if (m_structure != NULL) - return m_structure; - else - return IMAPMessageStructure::emptyStructure(); -} - - -shared_ptr <messageStructure> IMAPMessagePart::getStructure() -{ - if (m_structure != NULL) - return m_structure; - else - return IMAPMessageStructure::emptyStructure(); -} - - -shared_ptr <const IMAPMessagePart> IMAPMessagePart::getParent() const -{ - return m_parent.lock(); -} - - -const mediaType& IMAPMessagePart::getType() const -{ - return m_mediaType; -} - - -size_t IMAPMessagePart::getSize() const -{ - return m_size; -} - - -int IMAPMessagePart::getNumber() const -{ - return m_number; -} - - -shared_ptr <const header> IMAPMessagePart::getHeader() const -{ - if (m_header == NULL) - throw exceptions::unfetched_object(); - else - return m_header; -} - - -// static -shared_ptr <IMAPMessagePart> IMAPMessagePart::create - (shared_ptr <IMAPMessagePart> parent, const int number, const IMAPParser::body* body) -{ - if (body->body_type_mpart()) - { - shared_ptr <IMAPMessagePart> part = make_shared <IMAPMessagePart>(parent, number, body->body_type_mpart()); - part->m_structure = make_shared <IMAPMessageStructure>(part, body->body_type_mpart()->list()); - - return part; - } - else - { - return make_shared <IMAPMessagePart>(parent, number, body->body_type_1part()); - } -} - - -header& IMAPMessagePart::getOrCreateHeader() -{ - if (m_header != NULL) - return *m_header; - else - return *(m_header = make_shared <header>()); -} - - -} // imap -} // net -} // vmime - - -#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP - diff --git a/src/net/imap/IMAPMessagePartContentHandler.cpp b/src/net/imap/IMAPMessagePartContentHandler.cpp deleted file mode 100644 index 1f53f082..00000000 --- a/src/net/imap/IMAPMessagePartContentHandler.cpp +++ /dev/null @@ -1,216 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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_IMAP - - -#include "vmime/net/imap/IMAPMessagePartContentHandler.hpp" -#include "vmime/net/imap/IMAPFolder.hpp" -#include "vmime/net/imap/IMAPConnection.hpp" -#include "vmime/net/imap/IMAPFolderStatus.hpp" -#include "vmime/net/imap/IMAPStore.hpp" - -#include "vmime/utility/outputStreamAdapter.hpp" -#include "vmime/utility/inputStreamStringProxyAdapter.hpp" - - -namespace vmime { -namespace net { -namespace imap { - - -IMAPMessagePartContentHandler::IMAPMessagePartContentHandler - (shared_ptr <IMAPMessage> msg, shared_ptr <messagePart> part, const vmime::encoding& encoding) - : m_message(msg), m_part(part), m_encoding(encoding) -{ -} - - -shared_ptr <contentHandler> IMAPMessagePartContentHandler::clone() const -{ - return make_shared <IMAPMessagePartContentHandler> - (constCast <IMAPMessage>(m_message.lock()), - constCast <messagePart>(m_part.lock()), - m_encoding); -} - - -void IMAPMessagePartContentHandler::generate - (utility::outputStream& os, const vmime::encoding& enc, const size_t maxLineLength) const -{ - shared_ptr <IMAPMessage> msg = constCast <IMAPMessage>(m_message.lock()); - shared_ptr <messagePart> part = constCast <messagePart>(m_part.lock()); - - // Data is already encoded - if (isEncoded()) - { - // The data is already encoded but the encoding specified for - // the generation is different from the current one. We need - // to re-encode data: decode from input buffer to temporary - // buffer, and then re-encode to output stream... - if (m_encoding != enc) - { - // Extract part contents to temporary buffer - std::ostringstream oss; - utility::outputStreamAdapter tmp(oss); - - msg->extractPart(part, tmp, NULL); - - // Decode to another temporary buffer - utility::inputStreamStringProxyAdapter in(oss.str()); - - std::ostringstream oss2; - utility::outputStreamAdapter tmp2(oss2); - - shared_ptr <utility::encoder::encoder> theDecoder = m_encoding.getEncoder(); - theDecoder->decode(in, tmp2); - - // Reencode to output stream - string str = oss2.str(); - utility::inputStreamStringAdapter tempIn(str); - - shared_ptr <utility::encoder::encoder> theEncoder = enc.getEncoder(); - theEncoder->getProperties()["maxlinelength"] = maxLineLength; - theEncoder->getProperties()["text"] = (m_contentType.getType() == mediaTypes::TEXT); - - theEncoder->encode(tempIn, os); - } - // No encoding to perform - else - { - msg->extractPart(part, os); - } - } - // Need to encode data before - else - { - // Extract part contents to temporary buffer - std::ostringstream oss; - utility::outputStreamAdapter tmp(oss); - - msg->extractPart(part, tmp, NULL); - - // Encode temporary buffer to output stream - shared_ptr <utility::encoder::encoder> theEncoder = enc.getEncoder(); - theEncoder->getProperties()["maxlinelength"] = maxLineLength; - theEncoder->getProperties()["text"] = (m_contentType.getType() == mediaTypes::TEXT); - - utility::inputStreamStringAdapter is(oss.str()); - - theEncoder->encode(is, os); - } -} - - -void IMAPMessagePartContentHandler::extract - (utility::outputStream& os, utility::progressListener* progress) const -{ - shared_ptr <IMAPMessage> msg = constCast <IMAPMessage>(m_message.lock()); - shared_ptr <messagePart> part = constCast <messagePart>(m_part.lock()); - - // No decoding to perform - if (!isEncoded()) - { - msg->extractImpl(part, os, progress, 0, -1, IMAPMessage::EXTRACT_BODY); - } - // Need to decode data - else - { - // Extract part contents to temporary buffer - std::ostringstream oss; - utility::outputStreamAdapter tmp(oss); - - msg->extractImpl(part, tmp, NULL, 0, -1, IMAPMessage::EXTRACT_BODY); - - // Encode temporary buffer to output stream - utility::inputStreamStringAdapter is(oss.str()); - utility::progressListenerSizeAdapter plsa(progress, getLength()); - - shared_ptr <utility::encoder::encoder> theDecoder = m_encoding.getEncoder(); - theDecoder->decode(is, os, &plsa); - } -} - - -void IMAPMessagePartContentHandler::extractRaw - (utility::outputStream& os, utility::progressListener* progress) const -{ - shared_ptr <IMAPMessage> msg = constCast <IMAPMessage>(m_message.lock()); - shared_ptr <messagePart> part = constCast <messagePart>(m_part.lock()); - - msg->extractPart(part, os, progress); -} - - -size_t IMAPMessagePartContentHandler::getLength() const -{ - return m_part.lock()->getSize(); -} - - -bool IMAPMessagePartContentHandler::isEncoded() const -{ - return m_encoding != NO_ENCODING; -} - - -const vmime::encoding& IMAPMessagePartContentHandler::getEncoding() const -{ - return m_encoding; -} - - -bool IMAPMessagePartContentHandler::isEmpty() const -{ - return getLength() == 0; -} - - -bool IMAPMessagePartContentHandler::isBuffered() const -{ - return true; -} - - -void IMAPMessagePartContentHandler::setContentTypeHint(const mediaType& type) -{ - m_contentType = type; -} - - -const mediaType IMAPMessagePartContentHandler::getContentTypeHint() const -{ - return m_contentType; -} - - -} // imap -} // net -} // vmime - - -#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP - diff --git a/src/net/imap/IMAPMessageStructure.cpp b/src/net/imap/IMAPMessageStructure.cpp deleted file mode 100644 index 8dc333e9..00000000 --- a/src/net/imap/IMAPMessageStructure.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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_IMAP - - -#include "vmime/net/imap/IMAPMessageStructure.hpp" -#include "vmime/net/imap/IMAPMessagePart.hpp" - - -namespace vmime { -namespace net { -namespace imap { - - -IMAPMessageStructure::IMAPMessageStructure() -{ -} - - -IMAPMessageStructure::IMAPMessageStructure(const IMAPParser::body* body) -{ - m_parts.push_back(IMAPMessagePart::create(null, 0, body)); -} - - -IMAPMessageStructure::IMAPMessageStructure(shared_ptr <IMAPMessagePart> parent, const std::vector <IMAPParser::body*>& list) -{ - int number = 0; - - for (std::vector <IMAPParser::body*>::const_iterator - it = list.begin() ; it != list.end() ; ++it, ++number) - { - m_parts.push_back(IMAPMessagePart::create(parent, number, *it)); - } -} - - -shared_ptr <const messagePart> IMAPMessageStructure::getPartAt(const size_t x) const -{ - return m_parts[x]; -} - - -shared_ptr <messagePart> IMAPMessageStructure::getPartAt(const size_t x) -{ - return m_parts[x]; -} - - -size_t IMAPMessageStructure::getPartCount() const -{ - return m_parts.size(); -} - - -// static -shared_ptr <IMAPMessageStructure> IMAPMessageStructure::emptyStructure() -{ - static shared_ptr <IMAPMessageStructure> emptyStructure = make_shared <IMAPMessageStructure>(); - return emptyStructure; -} - - -} // imap -} // net -} // vmime - - -#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP - diff --git a/src/net/imap/IMAPSStore.cpp b/src/net/imap/IMAPSStore.cpp deleted file mode 100644 index c9e64f5b..00000000 --- a/src/net/imap/IMAPSStore.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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_IMAP - - -#include "vmime/net/imap/IMAPSStore.hpp" - - -namespace vmime { -namespace net { -namespace imap { - - -IMAPSStore::IMAPSStore(shared_ptr <session> sess, shared_ptr <security::authenticator> auth) - : IMAPStore(sess, auth, true) -{ -} - - -IMAPSStore::~IMAPSStore() -{ -} - - -const string IMAPSStore::getProtocolName() const -{ - return "imaps"; -} - - - -// Service infos - -IMAPServiceInfos IMAPSStore::sm_infos(true); - - -const serviceInfos& IMAPSStore::getInfosInstance() -{ - return sm_infos; -} - - -const serviceInfos& IMAPSStore::getInfos() const -{ - return sm_infos; -} - - -} // imap -} // net -} // vmime - - -#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP - diff --git a/src/net/imap/IMAPServiceInfos.cpp b/src/net/imap/IMAPServiceInfos.cpp deleted file mode 100644 index 46dbc2e1..00000000 --- a/src/net/imap/IMAPServiceInfos.cpp +++ /dev/null @@ -1,137 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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_IMAP - - -#include "vmime/net/imap/IMAPServiceInfos.hpp" - - -namespace vmime { -namespace net { -namespace imap { - - -IMAPServiceInfos::IMAPServiceInfos(const bool imaps) - : m_imaps(imaps) -{ -} - - -const string IMAPServiceInfos::getPropertyPrefix() const -{ - if (m_imaps) - return "store.imaps."; - else - return "store.imap."; -} - - -const IMAPServiceInfos::props& IMAPServiceInfos::getProperties() const -{ - static props imapProps = - { - // IMAP-specific options -#if VMIME_HAVE_SASL_SUPPORT - property("options.sasl", serviceInfos::property::TYPE_BOOLEAN, "true"), - property("options.sasl.fallback", serviceInfos::property::TYPE_BOOLEAN, "true"), -#endif // VMIME_HAVE_SASL_SUPPORT - - // Common properties - property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED), - property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED), - -#if VMIME_HAVE_TLS_SUPPORT - property(serviceInfos::property::CONNECTION_TLS), - property(serviceInfos::property::CONNECTION_TLS_REQUIRED), -#endif // VMIME_HAVE_TLS_SUPPORT - - property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED), - property(serviceInfos::property::SERVER_PORT, "143"), - }; - - static props imapsProps = - { - // IMAP-specific options -#if VMIME_HAVE_SASL_SUPPORT - property("options.sasl", serviceInfos::property::TYPE_BOOLEAN, "true"), - property("options.sasl.fallback", serviceInfos::property::TYPE_BOOLEAN, "true"), -#endif // VMIME_HAVE_SASL_SUPPORT - - // Common properties - property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED), - property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED), - -#if VMIME_HAVE_TLS_SUPPORT - property(serviceInfos::property::CONNECTION_TLS), - property(serviceInfos::property::CONNECTION_TLS_REQUIRED), -#endif // VMIME_HAVE_TLS_SUPPORT - - property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED), - property(serviceInfos::property::SERVER_PORT, "993"), - }; - - return m_imaps ? imapsProps : imapProps; -} - - -const std::vector <serviceInfos::property> IMAPServiceInfos::getAvailableProperties() const -{ - std::vector <property> list; - const props& p = getProperties(); - - // IMAP-specific options -#if VMIME_HAVE_SASL_SUPPORT - list.push_back(p.PROPERTY_OPTIONS_SASL); - list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK); -#endif // VMIME_HAVE_SASL_SUPPORT - - // Common properties - list.push_back(p.PROPERTY_AUTH_USERNAME); - list.push_back(p.PROPERTY_AUTH_PASSWORD); - -#if VMIME_HAVE_TLS_SUPPORT - if (!m_imaps) - { - list.push_back(p.PROPERTY_CONNECTION_TLS); - list.push_back(p.PROPERTY_CONNECTION_TLS_REQUIRED); - } -#endif // VMIME_HAVE_TLS_SUPPORT - - list.push_back(p.PROPERTY_SERVER_ADDRESS); - list.push_back(p.PROPERTY_SERVER_PORT); - - return list; -} - - -} // imap -} // net -} // vmime - - -#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP - diff --git a/src/net/imap/IMAPStore.cpp b/src/net/imap/IMAPStore.cpp deleted file mode 100644 index a1a8c9ca..00000000 --- a/src/net/imap/IMAPStore.cpp +++ /dev/null @@ -1,267 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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_IMAP - - -#include "vmime/net/imap/IMAPStore.hpp" -#include "vmime/net/imap/IMAPFolder.hpp" -#include "vmime/net/imap/IMAPConnection.hpp" -#include "vmime/net/imap/IMAPFolderStatus.hpp" - -#include "vmime/exception.hpp" -#include "vmime/platform.hpp" - -#include <map> - - -namespace vmime { -namespace net { -namespace imap { - - -IMAPStore::IMAPStore(shared_ptr <session> sess, shared_ptr <security::authenticator> auth, const bool secured) - : store(sess, getInfosInstance(), auth), m_connection(null), m_isIMAPS(secured) -{ -} - - -IMAPStore::~IMAPStore() -{ - try - { - if (isConnected()) - disconnect(); - } - catch (vmime::exception&) - { - // Ignore - } -} - - -const string IMAPStore::getProtocolName() const -{ - return "imap"; -} - - -shared_ptr <folder> IMAPStore::getRootFolder() -{ - if (!isConnected()) - throw exceptions::illegal_state("Not connected"); - - return make_shared <IMAPFolder> - (folder::path(), - dynamicCast <IMAPStore>(shared_from_this())); -} - - -shared_ptr <folder> IMAPStore::getDefaultFolder() -{ - if (!isConnected()) - throw exceptions::illegal_state("Not connected"); - - return make_shared <IMAPFolder> - (folder::path::component("INBOX"), - dynamicCast <IMAPStore>(shared_from_this())); -} - - -shared_ptr <folder> IMAPStore::getFolder(const folder::path& path) -{ - if (!isConnected()) - throw exceptions::illegal_state("Not connected"); - - return make_shared <IMAPFolder> - (path, dynamicCast <IMAPStore>(shared_from_this())); -} - - -bool IMAPStore::isValidFolderName(const folder::path::component& /* name */) const -{ - return true; -} - - -void IMAPStore::connect() -{ - if (isConnected()) - throw exceptions::already_connected(); - - m_connection = make_shared <IMAPConnection> - (dynamicCast <IMAPStore>(shared_from_this()), getAuthenticator()); - - try - { - m_connection->connect(); - } - catch (std::exception&) - { - m_connection = null; - throw; - } -} - - -bool IMAPStore::isConnected() const -{ - return (m_connection && m_connection->isConnected()); -} - - -bool IMAPStore::isIMAPS() const -{ - return m_isIMAPS; -} - - -bool IMAPStore::isSecuredConnection() const -{ - if (m_connection == NULL) - return false; - - return m_connection->isSecuredConnection(); -} - - -shared_ptr <connectionInfos> IMAPStore::getConnectionInfos() const -{ - if (m_connection == NULL) - return null; - - return m_connection->getConnectionInfos(); -} - - -shared_ptr <IMAPConnection> IMAPStore::getConnection() -{ - return m_connection; -} - - -void IMAPStore::disconnect() -{ - if (!isConnected()) - throw exceptions::not_connected(); - - for (std::list <IMAPFolder*>::iterator it = m_folders.begin() ; - it != m_folders.end() ; ++it) - { - (*it)->onStoreDisconnected(); - } - - m_folders.clear(); - - - m_connection->disconnect(); - - m_connection = null; -} - - -void IMAPStore::noop() -{ - if (!isConnected()) - throw exceptions::not_connected(); - - m_connection->send(true, "NOOP", true); - - std::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("NOOP", resp->getErrorLog()); - } - - - for (std::list <IMAPFolder*>::iterator it = m_folders.begin() ; - it != m_folders.end() ; ++it) - { - if ((*it)->isOpen()) - (*it)->noop(); - } -} - - -shared_ptr <IMAPConnection> IMAPStore::connection() -{ - return (m_connection); -} - - -void IMAPStore::registerFolder(IMAPFolder* folder) -{ - m_folders.push_back(folder); -} - - -void IMAPStore::unregisterFolder(IMAPFolder* folder) -{ - std::list <IMAPFolder*>::iterator it = std::find(m_folders.begin(), m_folders.end(), folder); - if (it != m_folders.end()) m_folders.erase(it); -} - - -int IMAPStore::getCapabilities() const -{ - return (CAPABILITY_CREATE_FOLDER | - CAPABILITY_RENAME_FOLDER | - CAPABILITY_ADD_MESSAGE | - CAPABILITY_COPY_MESSAGE | - CAPABILITY_DELETE_MESSAGE | - CAPABILITY_PARTIAL_FETCH | - CAPABILITY_MESSAGE_FLAGS | - CAPABILITY_EXTRACT_PART); -} - - - -// Service infos - -IMAPServiceInfos IMAPStore::sm_infos(false); - - -const serviceInfos& IMAPStore::getInfosInstance() -{ - return sm_infos; -} - - -const serviceInfos& IMAPStore::getInfos() const -{ - return sm_infos; -} - - -} // imap -} // net -} // vmime - - -#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP - diff --git a/src/net/imap/IMAPTag.cpp b/src/net/imap/IMAPTag.cpp deleted file mode 100644 index 14d12788..00000000 --- a/src/net/imap/IMAPTag.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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_IMAP - - -#include "vmime/net/imap/IMAPTag.hpp" - - -namespace vmime { -namespace net { -namespace imap { - - -const int IMAPTag::sm_maxNumber = 52 * 10 * 10 * 10; - - -IMAPTag::IMAPTag(const int number) - : m_number(number) -{ - m_tag.resize(4); - generate(); -} - - -IMAPTag::IMAPTag(const IMAPTag& tag) - : object(), m_number(tag.m_number) -{ - m_tag.resize(4); - generate(); -} - - -IMAPTag::IMAPTag() - : m_number(1) -{ - m_tag.resize(4); - generate(); -} - - -IMAPTag& IMAPTag::operator++() -{ - ++m_number; - - if (m_number >= sm_maxNumber) - m_number = 1; - - generate(); - - return (*this); -} - - -const IMAPTag IMAPTag::operator++(int) -{ - IMAPTag old(*this); - operator++(); - return (old); -} - - -int IMAPTag::maximumNumber() const -{ - return sm_maxNumber - 1; -} - - -int IMAPTag::number() const -{ - return (m_number); -} - - -IMAPTag::operator string() const -{ - return (m_tag); -} - - -void IMAPTag::generate() -{ - static const char prefixChars[53] = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - m_tag[0] = prefixChars[m_number / 1000]; - m_tag[1] = static_cast <char>('0' + (m_number % 1000) / 100); - m_tag[2] = static_cast <char>('0' + (m_number % 100) / 10); - m_tag[3] = static_cast <char>('0' + m_number % 10); -} - - -} // imap -} // net -} // vmime - - -#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP - diff --git a/src/net/imap/IMAPUtils.cpp b/src/net/imap/IMAPUtils.cpp deleted file mode 100644 index ff81ce71..00000000 --- a/src/net/imap/IMAPUtils.cpp +++ /dev/null @@ -1,758 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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_IMAP - - -#include "vmime/net/imap/IMAPUtils.hpp" -#include "vmime/net/imap/IMAPStore.hpp" - -#include "vmime/net/message.hpp" -#include "vmime/net/folder.hpp" - -#include <sstream> -#include <iterator> -#include <algorithm> - - -namespace vmime { -namespace net { -namespace imap { - - -// static -const string IMAPUtils::quoteString(const string& text) -{ - // - // ATOM_CHAR ::= <any CHAR except atom_specials> - // - // atom_specials ::= "(" / ")" / "{" / SPACE / CTL / - // list_wildcards / quoted_specials - // - // list_wildcards ::= "%" / "*" - // - // quoted_specials ::= <"> / "\" - // - // CHAR ::= <any 7-bit US-ASCII character except NUL, - // 0x01 - 0x7f> - // - // CTL ::= <any ASCII control character and DEL, - // 0x00 - 0x1f, 0x7f> - // - - bool needQuoting = text.empty(); - - for (string::const_iterator it = text.begin() ; - !needQuoting && it != text.end() ; ++it) - { - const unsigned char c = *it; - - switch (c) - { - case '(': - case ')': - case '{': - case 0x20: // SPACE - case '%': - case '*': - case '"': - case '\\': - - needQuoting = true; - break; - - default: - - if (c <= 0x1f || c >= 0x7f) - needQuoting = true; - } - } - - if (needQuoting) - { - string quoted; - quoted.reserve((text.length() * 3) / 2 + 2); - - quoted += '"'; - - for (string::const_iterator it = text.begin() ; it != text.end() ; ++it) - { - const unsigned char c = *it; - - if (c == '\\' || c == '"') - quoted += '\\'; - - quoted += c; - } - - quoted += '"'; - - return (quoted); - } - else - { - return (text); - } -} - - -const string IMAPUtils::pathToString - (const char hierarchySeparator, const folder::path& path) -{ - string result; - - for (size_t i = 0 ; i < path.getSize() ; ++i) - { - if (i > 0) result += hierarchySeparator; - result += toModifiedUTF7(hierarchySeparator, path[i]); - } - - return (result); -} - - -const folder::path IMAPUtils::stringToPath - (const char hierarchySeparator, const string& str) -{ - folder::path result; - string::const_iterator begin = str.begin(); - - for (string::const_iterator it = str.begin() ; it != str.end() ; ++it) - { - if (*it == hierarchySeparator) - { - result /= fromModifiedUTF7(string(begin, it)); - begin = it + 1; - } - } - - if (begin != str.end()) - { - result /= fromModifiedUTF7(string(begin, str.end())); - } - - return (result); -} - - -const string IMAPUtils::toModifiedUTF7 - (const char hierarchySeparator, const folder::path::component& text) -{ - // We will replace the hierarchy separator with an equivalent - // UTF-7 sequence, so we compute it here... - const char base64alphabet[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,="; - - const unsigned int hs = static_cast <unsigned int>(static_cast <unsigned char>(hierarchySeparator)); - - string hsUTF7; - hsUTF7.resize(3); - - hsUTF7[0] = base64alphabet[0]; - hsUTF7[1] = base64alphabet[(hs & 0xF0) >> 4]; - hsUTF7[2] = base64alphabet[(hs & 0x0F) << 2]; - - // iconv() is buggy with UTF-8 to UTF-7 conversion, so we do it "by hand". - // This code is largely inspired from "imap/utf7.c", in mutt 1.4. - // Copyright (C) 2000 Edmund Grimley Evans <[email protected]> - - // WARNING: This may throw "exceptions::charset_conv_error" - const string cvt = text.getConvertedText(charset(charsets::UTF_8)); - - // In the worst case we convert 2 chars to 7 chars. - // For example: "\x10&\x10&..." -> "&ABA-&-&ABA-&-...". - string out; - out.reserve((cvt.length() / 2) * 7 + 6); - - int b = 0, k = 0; - bool base64 = false; - - size_t remaining = cvt.length(); - - for (size_t i = 0, len = cvt.length() ; i < len ; ) - { - const unsigned char c = cvt[i]; - - // Replace hierarchy separator with an equivalent UTF-7 Base64 sequence - if (!base64 && c == hierarchySeparator) - { - out += "&" + hsUTF7 + "-"; - - ++i; - --remaining; - continue; - } - - size_t n = 0; - int ch = 0; - - if (c < 0x80) - ch = c, n = 0; - else if (c < 0xc2) - return ""; - else if (c < 0xe0) - ch = c & 0x1f, n = 1; - else if (c < 0xf0) - ch = c & 0x0f, n = 2; - else if (c < 0xf8) - ch = c & 0x07, n = 3; - else if (c < 0xfc) - ch = c & 0x03, n = 4; - else if (c < 0xfe) - ch = c & 0x01, n = 5; - else - return ""; - - if (n > remaining) - return ""; // error - - ++i; - --remaining; - - for (size_t j = 0 ; j < n ; j++) - { - if ((cvt[i + j] & 0xc0) != 0x80) - return ""; // error - - ch = (ch << 6) | (cvt[i + j] & 0x3f); - } - - if (n > 1 && !(ch >> (n * 5 + 1))) - return ""; // error - - i += n; - remaining -= n; - - if (ch < 0x20 || ch >= 0x7f) - { - if (!base64) - { - out += '&'; - base64 = true; - b = 0; - k = 10; - } - - if (ch & ~0xffff) - ch = 0xfffe; - - out += base64alphabet[b | ch >> k]; - - k -= 6; - - for ( ; k >= 0 ; k -= 6) - out += base64alphabet[(ch >> k) & 0x3f]; - - b = (ch << (-k)) & 0x3f; - k += 16; - } - else - { - if (base64) - { - if (k > 10) - out += base64alphabet[b]; - - out += '-'; - base64 = false; - } - - out += static_cast <char>(ch); - - if (ch == '&') - out += '-'; - } - } - - if (base64) - { - if (k > 10) - out += base64alphabet[b]; - - out += '-'; - } - - return (out); -} - - -const folder::path::component IMAPUtils::fromModifiedUTF7(const string& text) -{ - // Transcode from modified UTF-7 (RFC-2060). - 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))); -} - - -int IMAPUtils::folderTypeFromFlags(const IMAPParser::mailbox_flag_list* list) -{ - // Get folder type - int type = folder::TYPE_CONTAINS_MESSAGES | folder::TYPE_CONTAINS_FOLDERS; - const std::vector <IMAPParser::mailbox_flag*>& flags = list->flags(); - - for (std::vector <IMAPParser::mailbox_flag*>::const_iterator it = flags.begin() ; - it != flags.end() ; ++it) - { - if ((*it)->type() == IMAPParser::mailbox_flag::NOSELECT) - type &= ~folder::TYPE_CONTAINS_MESSAGES; - } - - if (type & folder::TYPE_CONTAINS_MESSAGES) - type &= ~folder::TYPE_CONTAINS_FOLDERS; - - return (type); -} - - -int IMAPUtils::folderFlagsFromFlags(const IMAPParser::mailbox_flag_list* list) -{ - // Get folder flags - int folderFlags = folder::FLAG_CHILDREN; - const std::vector <IMAPParser::mailbox_flag*>& flags = list->flags(); - - for (std::vector <IMAPParser::mailbox_flag*>::const_iterator it = flags.begin() ; - it != flags.end() ; ++it) - { - if ((*it)->type() == IMAPParser::mailbox_flag::NOSELECT) - folderFlags |= folder::FLAG_NO_OPEN; - else if ((*it)->type() == IMAPParser::mailbox_flag::NOINFERIORS) - folderFlags &= ~folder::FLAG_CHILDREN; - } - - return (folderFlags); -} - - -int IMAPUtils::messageFlagsFromFlags(const IMAPParser::flag_list* list) -{ - const std::vector <IMAPParser::flag*>& flagList = list->flags(); - int flags = 0; - - for (std::vector <IMAPParser::flag*>::const_iterator - it = flagList.begin() ; it != flagList.end() ; ++it) - { - switch ((*it)->type()) - { - case IMAPParser::flag::ANSWERED: - flags |= message::FLAG_REPLIED; - break; - case IMAPParser::flag::FLAGGED: - flags |= message::FLAG_MARKED; - break; - case IMAPParser::flag::DELETED: - flags |= message::FLAG_DELETED; - break; - case IMAPParser::flag::SEEN: - flags |= message::FLAG_SEEN; - break; - case IMAPParser::flag::DRAFT: - flags |= message::FLAG_DRAFT; - break; - - default: - //case IMAPParser::flag::UNKNOWN: - break; - } - } - - return (flags); -} - - -const string IMAPUtils::messageFlagList(const int flags) -{ - std::vector <string> flagList; - - if (flags & message::FLAG_REPLIED) flagList.push_back("\\Answered"); - if (flags & message::FLAG_MARKED) flagList.push_back("\\Flagged"); - if (flags & message::FLAG_DELETED) flagList.push_back("\\Deleted"); - if (flags & message::FLAG_SEEN) flagList.push_back("\\Seen"); - if (flags & message::FLAG_DRAFT) flagList.push_back("\\Draft"); - - if (!flagList.empty()) - { - std::ostringstream res; - res.imbue(std::locale::classic()); - - res << "("; - - if (flagList.size() >= 2) - { - std::copy(flagList.begin(), flagList.end() - 1, - std::ostream_iterator <string>(res, " ")); - } - - res << *(flagList.end() - 1) << ")"; - - return (res.str()); - } - - return ""; -} - - -// static -const string IMAPUtils::dateTime(const vmime::datetime& date) -{ - std::ostringstream res; - res.imbue(std::locale::classic()); - - // date_time ::= <"> date_day_fixed "-" date_month "-" date_year - // SPACE time SPACE zone <"> - // - // time ::= 2digit ":" 2digit ":" 2digit - // ;; Hours minutes seconds - // zone ::= ("+" / "-") 4digit - // ;; Signed four-digit value of hhmm representing - // ;; hours and minutes west of Greenwich - res << '"'; - - // Date - if (date.getDay() < 10) res << ' '; - res << date.getDay(); - - res << '-'; - - static const char* monthNames[12] = - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - - res << monthNames[std::min(std::max(date.getMonth() - 1, 0), 11)]; - - res << '-'; - - if (date.getYear() < 10) res << '0'; - if (date.getYear() < 100) res << '0'; - if (date.getYear() < 1000) res << '0'; - res << date.getYear(); - - res << ' '; - - // Time - if (date.getHour() < 10) res << '0'; - res << date.getHour() << ':'; - - if (date.getMinute() < 10) res << '0'; - res << date.getMinute() << ':'; - - if (date.getSecond() < 10) res << '0'; - res << date.getSecond(); - - res << ' '; - - // Zone - const int zs = (date.getZone() < 0 ? -1 : 1); - const int zh = (date.getZone() * zs) / 60; - const int zm = (date.getZone() * zs) % 60; - - res << (zs < 0 ? '-' : '+'); - - if (zh < 10) res << '0'; - res << zh; - - if (zm < 10) res << '0'; - res << zm; - - res << '"'; - - - return (res.str()); -} - - -// static -const string IMAPUtils::buildFetchRequest - (shared_ptr <IMAPConnection> cnt, const messageSet& msgs, const fetchAttributes& options) -{ - // Example: - // C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)]) - // S: * 2 FETCH .... - // S: * 3 FETCH .... - // S: * 4 FETCH .... - // S: A654 OK FETCH completed - - std::vector <string> items; - - if (options.has(fetchAttributes::SIZE)) - items.push_back("RFC822.SIZE"); - - if (options.has(fetchAttributes::FLAGS)) - items.push_back("FLAGS"); - - if (options.has(fetchAttributes::STRUCTURE)) - items.push_back("BODYSTRUCTURE"); - - if (options.has(fetchAttributes::UID)) - { - items.push_back("UID"); - - // Also fetch MODSEQ if CONDSTORE is supported - if (cnt->hasCapability("CONDSTORE") && !cnt->isMODSEQDisabled()) - items.push_back("MODSEQ"); - } - - if (options.has(fetchAttributes::FULL_HEADER)) - items.push_back("RFC822.HEADER"); - else - { - if (options.has(fetchAttributes::ENVELOPE)) - items.push_back("ENVELOPE"); - - std::vector <string> headerFields; - - if (options.has(fetchAttributes::CONTENT_INFO)) - headerFields.push_back("CONTENT_TYPE"); - - if (options.has(fetchAttributes::IMPORTANCE)) - { - headerFields.push_back("IMPORTANCE"); - headerFields.push_back("X-PRIORITY"); - } - - // Also add custom header fields to fetch, if any - const std::vector <string> customHeaderFields = options.getHeaderFields(); - std::copy(customHeaderFields.begin(), customHeaderFields.end(), std::back_inserter(headerFields)); - - if (!headerFields.empty()) - { - string list; - - for (std::vector <string>::iterator it = headerFields.begin() ; - it != headerFields.end() ; ++it) - { - if (it != headerFields.begin()) - list += " "; - - list += *it; - } - - items.push_back("BODY[HEADER.FIELDS (" + list + ")]"); - } - } - - // Build the request text - std::ostringstream command; - command.imbue(std::locale::classic()); - - if (msgs.isUIDSet()) - command << "UID FETCH " << messageSetToSequenceSet(msgs) << " ("; - else - command << "FETCH " << messageSetToSequenceSet(msgs) << " ("; - - for (std::vector <string>::const_iterator it = items.begin() ; - it != items.end() ; ++it) - { - if (it != items.begin()) command << " "; - command << *it; - } - - command << ")"; - - return command.str(); -} - - -// static -void IMAPUtils::convertAddressList - (const IMAPParser::address_list& src, mailboxList& dest) -{ - for (std::vector <IMAPParser::address*>::const_iterator - it = src.addresses().begin() ; it != src.addresses().end() ; ++it) - { - const IMAPParser::address& addr = **it; - - text name; - text::decodeAndUnfold(addr.addr_name()->value(), &name); - - string email = addr.addr_mailbox()->value() - + "@" + addr.addr_host()->value(); - - dest.appendMailbox(make_shared <mailbox>(name, email)); - } -} - - - -class IMAPUIDMessageSetEnumerator : public messageSetEnumerator -{ -public: - - IMAPUIDMessageSetEnumerator() - : m_first(true) - { - } - - void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) - { - if (!m_first) - m_oss << ","; - - if (range.getFirst() == range.getLast()) - m_oss << range.getFirst(); - else - m_oss << range.getFirst() << ":" << range.getLast(); - - m_first = false; - } - - void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& range) - { - if (!m_first) - m_oss << ","; - - if (range.getFirst() == range.getLast()) - m_oss << range.getFirst(); - else - m_oss << range.getFirst() << ":" << range.getLast(); - - m_first = false; - } - - const std::string str() const - { - return m_oss.str(); - } - -private: - - std::ostringstream m_oss; - bool m_first; -}; - - -class IMAPMessageSetEnumerator : public messageSetEnumerator -{ -public: - - void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) - { - for (int i = range.getFirst(), last = range.getLast() ; i <= last ; ++i) - m_list.push_back(i); - } - - void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& /* range */) - { - // Not used - } - - const std::vector <int>& list() const - { - return m_list; - } - -public: - - std::vector <int> m_list; -}; - - - -// static -const string IMAPUtils::messageSetToSequenceSet(const messageSet& msgs) -{ - IMAPUIDMessageSetEnumerator en; - msgs.enumerate(en); - - return en.str(); -} - - -// static -const std::vector <int> IMAPUtils::messageSetToNumberList(const messageSet& msgs) -{ - IMAPMessageSetEnumerator en; - msgs.enumerate(en); - - return en.list(); -} - - -} // imap -} // net -} // vmime - - -#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP - |
