📄 imapconnection.cpp
字号:
//// VMime library (http://www.vmime.org)// Copyright (C) 2002-2008 Vincent Richard <vincent@vincent-richard.net>//// This program is free software; you can redistribute it and/or// modify it under the terms of the GNU General Public License as// published by the Free Software Foundation; either version 2 of// the License, or (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU// General Public License for more details.//// You should have received a copy of the GNU General Public License along// with this program; if not, write to the Free Software Foundation, Inc.,// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.//// Linking this library statically or dynamically with other modules is making// a combined work based on this library. Thus, the terms and conditions of// the GNU General Public License cover the whole combination.//#include "vmime/net/imap/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/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.acquire()->getInfos().getPropertyValue <type>(getSession(), \ dynamic_cast <const IMAPServiceInfos&>(m_store.acquire()->getInfos()).getProperties().prop))#define HAS_PROPERTY(prop) \ (m_store.acquire()->getInfos().hasProperty(getSession(), \ dynamic_cast <const IMAPServiceInfos&>(m_store.acquire()->getInfos()).getProperties().prop))namespace vmime {namespace net {namespace imap {IMAPConnection::IMAPConnection(ref <IMAPStore> store, ref <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){}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); ref <IMAPStore> store = m_store.acquire(); // Create the time-out handler if (store->getTimeoutHandlerFactory()) m_timeoutHandler = store->getTimeoutHandlerFactory()->create(); // Create and connect the socket m_socket = store->getSocketFactory()->create();#if VMIME_HAVE_TLS_SUPPORT if (store->isIMAPS()) // dedicated port/IMAPS { ref <tls::TLSSession> tlsSession = vmime::create <tls::TLSSession>(store->getCertificateVerifier()); ref <tls::TLSSocket> tlsSocket = tlsSession->getSocket(m_socket); m_socket = tlsSocket; m_secured = true; m_cntInfos = vmime::create <tls::TLSSecuredConnectionInfos>(address, port, tlsSession, tlsSocket); } else#endif // VMIME_HAVE_TLS_SUPPORT { m_cntInfos = vmime::create <defaultConnectionInfos>(address, port); } m_socket->connect(address, port); m_tag = vmime::create <IMAPTag>(); m_parser = vmime::create <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 utility::auto_ptr <IMAPParser::greeting> greet(m_parser->readGreeting()); bool needAuth = false; if (greet->resp_cond_bye()) { internalDisconnect(); throw exceptions::connection_greeting_error(m_parser->lastLine()); } else if (greet->resp_cond_auth()->condition() != IMAPParser::resp_cond_auth::PREAUTH) { needAuth = true; }#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->isSecuredConnection() && 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.acquire());#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); utility::auto_ptr <IMAPParser::response> resp(m_parser->readResponse()); if (resp->isBad()) { internalDisconnect(); throw exceptions::command_error("LOGIN", m_parser->lastLine()); } else if (resp->response_done()->response_tagged()-> resp_cond_state()->status() != IMAPParser::resp_cond_state::OK) { internalDisconnect(); throw exceptions::authentication_error(m_parser->lastLine()); }}#if VMIME_HAVE_SASL_SUPPORTvoid IMAPConnection::authenticateSASL(){ if (!getAuthenticator().dynamicCast <security::sasl::SASLAuthenticator>()) 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 <ref <security::sasl::SASLMechanism> > mechList; ref <security::sasl::SASLContext> saslContext = vmime::create <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 ref <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 = getAuthenticator().dynamicCast <security::sasl::SASLAuthenticator>()-> 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) { ref <security::sasl::SASLMechanism> mech = mechList[i]; ref <security::sasl::SASLSession> saslSession = saslContext->createSession("imap", getAuthenticator(), mech); saslSession->init(); send(true, "AUTHENTICATE " + mech->getName(), true); for (bool cont = true ; cont ; ) { utility::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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -