Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
bf395a8d87
@ -327,6 +327,19 @@ exception* socket_exception::clone() const { return new socket_exception(*this);
|
|||||||
const char* socket_exception::name() const throw() { return "socket_exception"; }
|
const char* socket_exception::name() const throw() { return "socket_exception"; }
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// socket_not_connected_exception
|
||||||
|
//
|
||||||
|
|
||||||
|
socket_not_connected_exception::~socket_not_connected_exception() throw() {}
|
||||||
|
socket_not_connected_exception::socket_not_connected_exception(const string& what, const exception& other)
|
||||||
|
: socket_exception(what.empty()
|
||||||
|
? "Socket is not connected." : what, other) {}
|
||||||
|
|
||||||
|
exception* socket_not_connected_exception::clone() const { return new socket_not_connected_exception(*this); }
|
||||||
|
const char* socket_not_connected_exception::name() const throw() { return "socket_not_connected_exception"; }
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// connection_error
|
// connection_error
|
||||||
//
|
//
|
||||||
|
@ -370,6 +370,23 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Socket not connected: you are trying to write to/read from a socket which
|
||||||
|
* is not connected to a peer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class VMIME_EXPORT socket_not_connected_exception : public socket_exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
socket_not_connected_exception(const string& what = "", const exception& other = NO_EXCEPTION);
|
||||||
|
~socket_not_connected_exception() throw();
|
||||||
|
|
||||||
|
exception* clone() const;
|
||||||
|
const char* name() const throw();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Error while connecting to the server: this may be a DNS resolution error
|
/** Error while connecting to the server: this may be a DNS resolution error
|
||||||
* or a connection error (for example, time-out while connecting).
|
* or a connection error (for example, time-out while connecting).
|
||||||
*/
|
*/
|
||||||
|
@ -234,23 +234,23 @@ void IMAPConnection::authenticate()
|
|||||||
authenticateSASL();
|
authenticateSASL();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (exceptions::authentication_error& e)
|
catch (exceptions::authentication_error&)
|
||||||
{
|
{
|
||||||
if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK))
|
if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK))
|
||||||
{
|
{
|
||||||
// Can't fallback on normal authentication
|
// Can't fallback on normal authentication
|
||||||
internalDisconnect();
|
internalDisconnect();
|
||||||
throw e;
|
throw;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Ignore, will try normal authentication
|
// Ignore, will try normal authentication
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (exception& e)
|
catch (exception&)
|
||||||
{
|
{
|
||||||
internalDisconnect();
|
internalDisconnect();
|
||||||
throw e;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||||
@ -482,7 +482,7 @@ void IMAPConnection::startTLS()
|
|||||||
shared_ptr <tls::TLSSocket> tlsSocket =
|
shared_ptr <tls::TLSSocket> tlsSocket =
|
||||||
tlsSession->getSocket(m_socket);
|
tlsSession->getSocket(m_socket);
|
||||||
|
|
||||||
tlsSocket->handshake(m_timeoutHandler);
|
tlsSocket->handshake();
|
||||||
|
|
||||||
m_socket = tlsSocket;
|
m_socket = tlsSocket;
|
||||||
m_parser->setSocket(m_socket);
|
m_parser->setSocket(m_socket);
|
||||||
|
@ -92,9 +92,6 @@ int IMAPFolder::getMode() const
|
|||||||
|
|
||||||
const folderAttributes IMAPFolder::getAttributes()
|
const folderAttributes IMAPFolder::getAttributes()
|
||||||
{
|
{
|
||||||
if (!isOpen())
|
|
||||||
throw exceptions::illegal_state("Folder not open");
|
|
||||||
|
|
||||||
// Root folder
|
// Root folder
|
||||||
if (m_path.isEmpty())
|
if (m_path.isEmpty())
|
||||||
{
|
{
|
||||||
@ -1124,7 +1121,7 @@ messageSet IMAPFolder::addMessage
|
|||||||
const IMAPParser::resp_text_code* respTextCode =
|
const IMAPParser::resp_text_code* respTextCode =
|
||||||
finalResp->response_done()->response_tagged()->resp_cond_state()->resp_text()->resp_text_code();
|
finalResp->response_done()->response_tagged()->resp_cond_state()->resp_text()->resp_text_code();
|
||||||
|
|
||||||
if (respTextCode->type() == IMAPParser::resp_text_code::APPENDUID)
|
if (respTextCode && respTextCode->type() == IMAPParser::resp_text_code::APPENDUID)
|
||||||
return IMAPUtils::buildMessageSet(respTextCode->uid_set());
|
return IMAPUtils::buildMessageSet(respTextCode->uid_set());
|
||||||
|
|
||||||
return messageSet::empty();
|
return messageSet::empty();
|
||||||
@ -1266,7 +1263,7 @@ messageSet IMAPFolder::copyMessages(const folder::path& dest, const messageSet&
|
|||||||
const IMAPParser::resp_text_code* respTextCode =
|
const IMAPParser::resp_text_code* respTextCode =
|
||||||
resp->response_done()->response_tagged()->resp_cond_state()->resp_text()->resp_text_code();
|
resp->response_done()->response_tagged()->resp_cond_state()->resp_text()->resp_text_code();
|
||||||
|
|
||||||
if (respTextCode->type() == IMAPParser::resp_text_code::COPYUID)
|
if (respTextCode && respTextCode->type() == IMAPParser::resp_text_code::COPYUID)
|
||||||
return IMAPUtils::buildMessageSet(respTextCode->uid_set2());
|
return IMAPUtils::buildMessageSet(respTextCode->uid_set2());
|
||||||
|
|
||||||
return messageSet::empty();
|
return messageSet::empty();
|
||||||
|
@ -233,23 +233,23 @@ void POP3Connection::authenticate(const messageId& randomMID)
|
|||||||
m_authenticated = true;
|
m_authenticated = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (exceptions::authentication_error& e)
|
catch (exceptions::authentication_error&)
|
||||||
{
|
{
|
||||||
if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK))
|
if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK))
|
||||||
{
|
{
|
||||||
// Can't fallback on APOP/normal authentication
|
// Can't fallback on APOP/normal authentication
|
||||||
internalDisconnect();
|
internalDisconnect();
|
||||||
throw e;
|
throw;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Ignore, will try APOP/normal authentication
|
// Ignore, will try APOP/normal authentication
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (exception& e)
|
catch (exception&)
|
||||||
{
|
{
|
||||||
internalDisconnect();
|
internalDisconnect();
|
||||||
throw e;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||||
@ -552,7 +552,7 @@ void POP3Connection::startTLS()
|
|||||||
shared_ptr <tls::TLSSocket> tlsSocket =
|
shared_ptr <tls::TLSSocket> tlsSocket =
|
||||||
tlsSession->getSocket(m_socket);
|
tlsSession->getSocket(m_socket);
|
||||||
|
|
||||||
tlsSocket->handshake(m_timeoutHandler);
|
tlsSocket->handshake();
|
||||||
|
|
||||||
m_socket = tlsSocket;
|
m_socket = tlsSocket;
|
||||||
|
|
||||||
|
@ -83,9 +83,6 @@ int POP3Folder::getMode() const
|
|||||||
|
|
||||||
const folderAttributes POP3Folder::getAttributes()
|
const folderAttributes POP3Folder::getAttributes()
|
||||||
{
|
{
|
||||||
if (!isOpen())
|
|
||||||
throw exceptions::illegal_state("Folder not open");
|
|
||||||
|
|
||||||
folderAttributes attribs;
|
folderAttributes attribs;
|
||||||
|
|
||||||
if (m_path.isEmpty())
|
if (m_path.isEmpty())
|
||||||
|
@ -95,7 +95,7 @@ bool POP3Message::isExpunged() const
|
|||||||
|
|
||||||
int POP3Message::getFlags() const
|
int POP3Message::getFlags() const
|
||||||
{
|
{
|
||||||
int flags = FLAG_RECENT;
|
int flags = 0;
|
||||||
|
|
||||||
if (m_deleted)
|
if (m_deleted)
|
||||||
flags |= FLAG_DELETED;
|
flags |= FLAG_DELETED;
|
||||||
|
@ -284,7 +284,7 @@ void SMTPConnection::authenticate()
|
|||||||
getAuthenticator()->setService(m_transport.lock());
|
getAuthenticator()->setService(m_transport.lock());
|
||||||
|
|
||||||
#if VMIME_HAVE_SASL_SUPPORT
|
#if VMIME_HAVE_SASL_SUPPORT
|
||||||
// First, try SASL authentication
|
// Try SASL authentication
|
||||||
if (GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL))
|
if (GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -294,23 +294,10 @@ void SMTPConnection::authenticate()
|
|||||||
m_authenticated = true;
|
m_authenticated = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (exceptions::authentication_error& e)
|
catch (exception&)
|
||||||
{
|
|
||||||
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();
|
internalDisconnect();
|
||||||
throw e;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||||
@ -487,7 +474,7 @@ void SMTPConnection::startTLS()
|
|||||||
shared_ptr <tls::TLSSocket> tlsSocket =
|
shared_ptr <tls::TLSSocket> tlsSocket =
|
||||||
tlsSession->getSocket(m_socket);
|
tlsSession->getSocket(m_socket);
|
||||||
|
|
||||||
tlsSocket->handshake(m_timeoutHandler);
|
tlsSocket->handshake();
|
||||||
|
|
||||||
m_socket = tlsSocket;
|
m_socket = tlsSocket;
|
||||||
|
|
||||||
@ -522,16 +509,19 @@ void SMTPConnection::disconnect()
|
|||||||
|
|
||||||
void SMTPConnection::internalDisconnect()
|
void SMTPConnection::internalDisconnect()
|
||||||
{
|
{
|
||||||
try
|
if (isConnected())
|
||||||
{
|
{
|
||||||
sendRequest(SMTPCommand::QUIT());
|
try
|
||||||
|
{
|
||||||
|
sendRequest(SMTPCommand::QUIT());
|
||||||
|
|
||||||
// Do not wait for server response. This is contrary to the RFC, but
|
// Do not wait for server response. This is contrary to the RFC, but
|
||||||
// some servers never send a response to a QUIT command.
|
// some servers never send a response to a QUIT command.
|
||||||
}
|
}
|
||||||
catch (exception&)
|
catch (exception&)
|
||||||
{
|
{
|
||||||
// Not important
|
// Not important
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_socket->disconnect();
|
m_socket->disconnect();
|
||||||
|
@ -141,6 +141,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual const string getPeerAddress() const = 0;
|
virtual const string getPeerAddress() const = 0;
|
||||||
|
|
||||||
|
/** Return the timeout handler associated with this socket.
|
||||||
|
*
|
||||||
|
* @return timeout handler, or NULL if none is set
|
||||||
|
*/
|
||||||
|
virtual shared_ptr <timeoutHandler> getTimeoutHandler() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
socket() { }
|
socket() { }
|
||||||
|
@ -67,7 +67,7 @@ public:
|
|||||||
* during the negociation process, exceptions::operation_timed_out
|
* during the negociation process, exceptions::operation_timed_out
|
||||||
* if a time-out occurs
|
* if a time-out occurs
|
||||||
*/
|
*/
|
||||||
virtual void handshake(shared_ptr <timeoutHandler> toHandler = null) = 0;
|
virtual void handshake() = 0;
|
||||||
|
|
||||||
/** Return the peer's certificate (chain) as sent by the peer.
|
/** Return the peer's certificate (chain) as sent by the peer.
|
||||||
*
|
*
|
||||||
|
@ -87,11 +87,17 @@ TLSSocket_GnuTLS::~TLSSocket_GnuTLS()
|
|||||||
|
|
||||||
void TLSSocket_GnuTLS::connect(const string& address, const port_t port)
|
void TLSSocket_GnuTLS::connect(const string& address, const port_t port)
|
||||||
{
|
{
|
||||||
m_wrapped->connect(address, port);
|
try
|
||||||
|
{
|
||||||
|
m_wrapped->connect(address, port);
|
||||||
|
|
||||||
handshake(null);
|
handshake();
|
||||||
|
}
|
||||||
m_connected = true;
|
catch (...)
|
||||||
|
{
|
||||||
|
disconnect();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -132,6 +138,12 @@ const string TLSSocket_GnuTLS::getPeerAddress() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
shared_ptr <timeoutHandler> TLSSocket_GnuTLS::getTimeoutHandler()
|
||||||
|
{
|
||||||
|
return m_wrapped->getTimeoutHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void TLSSocket_GnuTLS::receive(string& buffer)
|
void TLSSocket_GnuTLS::receive(string& buffer)
|
||||||
{
|
{
|
||||||
const size_t size = receiveRaw(m_buffer, sizeof(m_buffer));
|
const size_t size = receiveRaw(m_buffer, sizeof(m_buffer));
|
||||||
@ -239,14 +251,15 @@ unsigned int TLSSocket_GnuTLS::getStatus() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TLSSocket_GnuTLS::handshake(shared_ptr <timeoutHandler> toHandler)
|
void TLSSocket_GnuTLS::handshake()
|
||||||
{
|
{
|
||||||
|
shared_ptr <timeoutHandler> toHandler = m_wrapped->getTimeoutHandler();
|
||||||
|
|
||||||
if (toHandler)
|
if (toHandler)
|
||||||
toHandler->resetTimeOut();
|
toHandler->resetTimeOut();
|
||||||
|
|
||||||
// Start handshaking process
|
// Start handshaking process
|
||||||
m_handshaking = true;
|
m_handshaking = true;
|
||||||
m_toHandler = toHandler;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -280,13 +293,10 @@ void TLSSocket_GnuTLS::handshake(shared_ptr <timeoutHandler> toHandler)
|
|||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
m_handshaking = false;
|
m_handshaking = false;
|
||||||
m_toHandler = null;
|
|
||||||
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_handshaking = false;
|
m_handshaking = false;
|
||||||
m_toHandler = null;
|
|
||||||
|
|
||||||
// Verify server's certificate(s)
|
// Verify server's certificate(s)
|
||||||
shared_ptr <security::cert::certificateChain> certs = getPeerCertificates();
|
shared_ptr <security::cert::certificateChain> certs = getPeerCertificates();
|
||||||
@ -338,6 +348,8 @@ ssize_t TLSSocket_GnuTLS::gnutlsPullFunc
|
|||||||
// returns -1 and errno is set to EGAIN...
|
// returns -1 and errno is set to EGAIN...
|
||||||
if (sok->m_handshaking)
|
if (sok->m_handshaking)
|
||||||
{
|
{
|
||||||
|
shared_ptr <timeoutHandler> toHandler = sok->m_wrapped->getTimeoutHandler();
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
const ssize_t ret = static_cast <ssize_t>
|
const ssize_t ret = static_cast <ssize_t>
|
||||||
@ -355,12 +367,12 @@ ssize_t TLSSocket_GnuTLS::gnutlsPullFunc
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the time-out delay is elapsed
|
// Check whether the time-out delay is elapsed
|
||||||
if (sok->m_toHandler && sok->m_toHandler->isTimeOut())
|
if (toHandler && toHandler->isTimeOut())
|
||||||
{
|
{
|
||||||
if (!sok->m_toHandler->handleTimeOut())
|
if (!toHandler->handleTimeOut())
|
||||||
throw exceptions::operation_timed_out();
|
throw exceptions::operation_timed_out();
|
||||||
|
|
||||||
sok->m_toHandler->resetTimeOut();
|
toHandler->resetTimeOut();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ public:
|
|||||||
~TLSSocket_GnuTLS();
|
~TLSSocket_GnuTLS();
|
||||||
|
|
||||||
|
|
||||||
void handshake(shared_ptr <timeoutHandler> toHandler = null);
|
void handshake();
|
||||||
|
|
||||||
shared_ptr <security::cert::certificateChain> getPeerCertificates() const;
|
shared_ptr <security::cert::certificateChain> getPeerCertificates() const;
|
||||||
|
|
||||||
@ -78,6 +78,8 @@ public:
|
|||||||
const string getPeerName() const;
|
const string getPeerName() const;
|
||||||
const string getPeerAddress() const;
|
const string getPeerAddress() const;
|
||||||
|
|
||||||
|
shared_ptr <timeoutHandler> getTimeoutHandler();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void internalThrow();
|
void internalThrow();
|
||||||
@ -99,7 +101,6 @@ private:
|
|||||||
byte_t m_buffer[65536];
|
byte_t m_buffer[65536];
|
||||||
|
|
||||||
bool m_handshaking;
|
bool m_handshaking;
|
||||||
shared_ptr <timeoutHandler> m_toHandler;
|
|
||||||
|
|
||||||
exception* m_ex;
|
exception* m_ex;
|
||||||
|
|
||||||
|
@ -87,12 +87,6 @@ TLSSocket_OpenSSL::~TLSSocket_OpenSSL()
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
disconnect();
|
disconnect();
|
||||||
|
|
||||||
if (m_ssl)
|
|
||||||
{
|
|
||||||
SSL_free(m_ssl);
|
|
||||||
m_ssl = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
@ -130,32 +124,41 @@ void TLSSocket_OpenSSL::createSSLHandle()
|
|||||||
|
|
||||||
void TLSSocket_OpenSSL::connect(const string& address, const port_t port)
|
void TLSSocket_OpenSSL::connect(const string& address, const port_t port)
|
||||||
{
|
{
|
||||||
m_wrapped->connect(address, port);
|
try
|
||||||
|
{
|
||||||
|
m_wrapped->connect(address, port);
|
||||||
|
|
||||||
createSSLHandle();
|
createSSLHandle();
|
||||||
|
|
||||||
handshake(null);
|
handshake();
|
||||||
|
}
|
||||||
m_connected = true;
|
catch (...)
|
||||||
|
{
|
||||||
|
disconnect();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TLSSocket_OpenSSL::disconnect()
|
void TLSSocket_OpenSSL::disconnect()
|
||||||
{
|
{
|
||||||
|
if (m_ssl)
|
||||||
|
{
|
||||||
|
// Don't shut down the socket more than once.
|
||||||
|
int shutdownState = SSL_get_shutdown(m_ssl);
|
||||||
|
bool shutdownSent = (shutdownState & SSL_SENT_SHUTDOWN) == SSL_SENT_SHUTDOWN;
|
||||||
|
|
||||||
|
if (!shutdownSent)
|
||||||
|
SSL_shutdown(m_ssl);
|
||||||
|
|
||||||
|
SSL_free(m_ssl);
|
||||||
|
m_ssl = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_connected)
|
if (m_connected)
|
||||||
{
|
{
|
||||||
if (m_ssl)
|
|
||||||
{
|
|
||||||
// Don't shut down the socket more than once.
|
|
||||||
int shutdownState = SSL_get_shutdown(m_ssl);
|
|
||||||
bool shutdownSent = (shutdownState & SSL_SENT_SHUTDOWN) == SSL_SENT_SHUTDOWN;
|
|
||||||
|
|
||||||
if (!shutdownSent)
|
|
||||||
SSL_shutdown(m_ssl);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_wrapped->disconnect();
|
|
||||||
m_connected = false;
|
m_connected = false;
|
||||||
|
m_wrapped->disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,6 +187,12 @@ const string TLSSocket_OpenSSL::getPeerAddress() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
shared_ptr <timeoutHandler> TLSSocket_OpenSSL::getTimeoutHandler()
|
||||||
|
{
|
||||||
|
return m_wrapped->getTimeoutHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void TLSSocket_OpenSSL::receive(string& buffer)
|
void TLSSocket_OpenSSL::receive(string& buffer)
|
||||||
{
|
{
|
||||||
const size_t size = receiveRaw(m_buffer, sizeof(m_buffer));
|
const size_t size = receiveRaw(m_buffer, sizeof(m_buffer));
|
||||||
@ -209,6 +218,9 @@ void TLSSocket_OpenSSL::send(const char* str)
|
|||||||
|
|
||||||
size_t TLSSocket_OpenSSL::receiveRaw(byte_t* buffer, const size_t count)
|
size_t TLSSocket_OpenSSL::receiveRaw(byte_t* buffer, const size_t count)
|
||||||
{
|
{
|
||||||
|
if (!m_ssl)
|
||||||
|
throw exceptions::socket_not_connected_exception();
|
||||||
|
|
||||||
m_status &= ~STATUS_WOULDBLOCK;
|
m_status &= ~STATUS_WOULDBLOCK;
|
||||||
|
|
||||||
int rc = SSL_read(m_ssl, buffer, static_cast <int>(count));
|
int rc = SSL_read(m_ssl, buffer, static_cast <int>(count));
|
||||||
@ -235,6 +247,9 @@ size_t TLSSocket_OpenSSL::receiveRaw(byte_t* buffer, const size_t count)
|
|||||||
|
|
||||||
void TLSSocket_OpenSSL::sendRaw(const byte_t* buffer, const size_t count)
|
void TLSSocket_OpenSSL::sendRaw(const byte_t* buffer, const size_t count)
|
||||||
{
|
{
|
||||||
|
if (!m_ssl)
|
||||||
|
throw exceptions::socket_not_connected_exception();
|
||||||
|
|
||||||
m_status &= ~STATUS_WOULDBLOCK;
|
m_status &= ~STATUS_WOULDBLOCK;
|
||||||
|
|
||||||
for (size_t size = count ; size > 0 ; )
|
for (size_t size = count ; size > 0 ; )
|
||||||
@ -264,6 +279,9 @@ void TLSSocket_OpenSSL::sendRaw(const byte_t* buffer, const size_t count)
|
|||||||
|
|
||||||
size_t TLSSocket_OpenSSL::sendRawNonBlocking(const byte_t* buffer, const size_t count)
|
size_t TLSSocket_OpenSSL::sendRawNonBlocking(const byte_t* buffer, const size_t count)
|
||||||
{
|
{
|
||||||
|
if (!m_ssl)
|
||||||
|
throw exceptions::socket_not_connected_exception();
|
||||||
|
|
||||||
m_status &= ~STATUS_WOULDBLOCK;
|
m_status &= ~STATUS_WOULDBLOCK;
|
||||||
|
|
||||||
int rc = SSL_write(m_ssl, buffer, static_cast <int>(count));
|
int rc = SSL_write(m_ssl, buffer, static_cast <int>(count));
|
||||||
@ -288,14 +306,17 @@ size_t TLSSocket_OpenSSL::sendRawNonBlocking(const byte_t* buffer, const size_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TLSSocket_OpenSSL::handshake(shared_ptr <timeoutHandler> toHandler)
|
void TLSSocket_OpenSSL::handshake()
|
||||||
{
|
{
|
||||||
|
if (!m_ssl)
|
||||||
|
throw exceptions::socket_not_connected_exception();
|
||||||
|
|
||||||
|
shared_ptr <timeoutHandler> toHandler = m_wrapped->getTimeoutHandler();
|
||||||
|
|
||||||
if (toHandler)
|
if (toHandler)
|
||||||
toHandler->resetTimeOut();
|
toHandler->resetTimeOut();
|
||||||
|
|
||||||
// Start handshaking process
|
// Start handshaking process
|
||||||
m_toHandler = toHandler;
|
|
||||||
|
|
||||||
if (!m_ssl)
|
if (!m_ssl)
|
||||||
createSSLHandle();
|
createSSLHandle();
|
||||||
|
|
||||||
@ -318,25 +339,20 @@ void TLSSocket_OpenSSL::handshake(shared_ptr <timeoutHandler> toHandler)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the time-out delay is elapsed
|
// Check whether the time-out delay is elapsed
|
||||||
if (m_toHandler && m_toHandler->isTimeOut())
|
if (toHandler && toHandler->isTimeOut())
|
||||||
{
|
{
|
||||||
if (!m_toHandler->handleTimeOut())
|
if (!toHandler->handleTimeOut())
|
||||||
throw exceptions::operation_timed_out();
|
throw exceptions::operation_timed_out();
|
||||||
|
|
||||||
m_toHandler->resetTimeOut();
|
toHandler->resetTimeOut();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
SSL_free(m_ssl);
|
|
||||||
m_ssl = 0;
|
|
||||||
m_toHandler = null;
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_toHandler = null;
|
|
||||||
|
|
||||||
// Verify server's certificate(s)
|
// Verify server's certificate(s)
|
||||||
shared_ptr <security::cert::certificateChain> certs = getPeerCertificates();
|
shared_ptr <security::cert::certificateChain> certs = getPeerCertificates();
|
||||||
|
|
||||||
@ -401,6 +417,8 @@ void TLSSocket_OpenSSL::handleError(int rc)
|
|||||||
switch (sslError)
|
switch (sslError)
|
||||||
{
|
{
|
||||||
case SSL_ERROR_ZERO_RETURN:
|
case SSL_ERROR_ZERO_RETURN:
|
||||||
|
|
||||||
|
disconnect();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case SSL_ERROR_SYSCALL:
|
case SSL_ERROR_SYSCALL:
|
||||||
@ -413,8 +431,7 @@ void TLSSocket_OpenSSL::handleError(int rc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vmime::string msg;
|
std::ostringstream oss;
|
||||||
std::ostringstream oss(msg);
|
|
||||||
oss << "The BIO reported an error: " << rc;
|
oss << "The BIO reported an error: " << rc;
|
||||||
oss.flush();
|
oss.flush();
|
||||||
throw exceptions::tls_exception(oss.str());
|
throw exceptions::tls_exception(oss.str());
|
||||||
|
@ -58,7 +58,7 @@ public:
|
|||||||
~TLSSocket_OpenSSL();
|
~TLSSocket_OpenSSL();
|
||||||
|
|
||||||
|
|
||||||
void handshake(shared_ptr <timeoutHandler> toHandler = null);
|
void handshake();
|
||||||
|
|
||||||
shared_ptr <security::cert::certificateChain> getPeerCertificates() const;
|
shared_ptr <security::cert::certificateChain> getPeerCertificates() const;
|
||||||
|
|
||||||
@ -82,6 +82,8 @@ public:
|
|||||||
const string getPeerName() const;
|
const string getPeerName() const;
|
||||||
const string getPeerAddress() const;
|
const string getPeerAddress() const;
|
||||||
|
|
||||||
|
shared_ptr <timeoutHandler> getTimeoutHandler();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static BIO_METHOD sm_customBIOMethod;
|
static BIO_METHOD sm_customBIOMethod;
|
||||||
@ -108,8 +110,6 @@ private:
|
|||||||
|
|
||||||
byte_t m_buffer[65536];
|
byte_t m_buffer[65536];
|
||||||
|
|
||||||
shared_ptr <timeoutHandler> m_toHandler;
|
|
||||||
|
|
||||||
SSL* m_ssl;
|
SSL* m_ssl;
|
||||||
|
|
||||||
unsigned long m_status;
|
unsigned long m_status;
|
||||||
|
@ -654,6 +654,12 @@ unsigned int posixSocket::getStatus() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
shared_ptr <net::timeoutHandler> posixSocket::getTimeoutHandler()
|
||||||
|
{
|
||||||
|
return m_timeoutHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// posixSocketFactory
|
// posixSocketFactory
|
||||||
|
@ -65,6 +65,8 @@ public:
|
|||||||
const string getPeerName() const;
|
const string getPeerName() const;
|
||||||
const string getPeerAddress() const;
|
const string getPeerAddress() const;
|
||||||
|
|
||||||
|
shared_ptr <net::timeoutHandler> getTimeoutHandler();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
static void throwSocketError(const int err);
|
static void throwSocketError(const int err);
|
||||||
|
@ -460,6 +460,12 @@ void windowsSocket::waitForData(const WaitOpType t, bool& timedOut)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
shared_ptr <net::timeoutHandler> windowsSocket::getTimeoutHandler()
|
||||||
|
{
|
||||||
|
return m_timeoutHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// posixSocketFactory
|
// posixSocketFactory
|
||||||
|
@ -69,6 +69,8 @@ public:
|
|||||||
const string getPeerName() const;
|
const string getPeerName() const;
|
||||||
const string getPeerAddress() const;
|
const string getPeerAddress() const;
|
||||||
|
|
||||||
|
shared_ptr <net::timeoutHandler> getTimeoutHandler();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void throwSocketError(const int err);
|
void throwSocketError(const int err);
|
||||||
|
@ -96,6 +96,12 @@ const string SASLSocket::getPeerAddress() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
shared_ptr <net::timeoutHandler> SASLSocket::getTimeoutHandler()
|
||||||
|
{
|
||||||
|
return m_wrapped->getTimeoutHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SASLSocket::receive(string& buffer)
|
void SASLSocket::receive(string& buffer)
|
||||||
{
|
{
|
||||||
const size_t n = receiveRaw(m_recvBuffer, sizeof(m_recvBuffer));
|
const size_t n = receiveRaw(m_recvBuffer, sizeof(m_recvBuffer));
|
||||||
|
@ -73,6 +73,8 @@ public:
|
|||||||
const string getPeerName() const;
|
const string getPeerName() const;
|
||||||
const string getPeerAddress() const;
|
const string getPeerAddress() const;
|
||||||
|
|
||||||
|
shared_ptr <net::timeoutHandler> getTimeoutHandler();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
shared_ptr <SASLSession> m_session;
|
shared_ptr <SASLSession> m_session;
|
||||||
|
@ -62,7 +62,7 @@ shared_ptr <textPart> textPartFactory::create(const mediaType& type)
|
|||||||
return ((*it).second)();
|
return ((*it).second)();
|
||||||
}
|
}
|
||||||
|
|
||||||
throw exceptions::no_factory_available();
|
throw exceptions::no_factory_available("No 'textPart' class registered for media type '" + type.generate() + "'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -261,5 +261,52 @@ path::component& path::getComponentAt(const size_t pos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
path path::fromString(const string& str, const string& sep, const charset& cset)
|
||||||
|
{
|
||||||
|
path p;
|
||||||
|
|
||||||
|
size_t start = 0;
|
||||||
|
size_t end = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
end = str.find(sep, start);
|
||||||
|
|
||||||
|
string comp;
|
||||||
|
|
||||||
|
if (end == string::npos)
|
||||||
|
comp = str.substr(start);
|
||||||
|
else
|
||||||
|
comp = str.substr(start, end - start);
|
||||||
|
|
||||||
|
// Skip leading or trailing separators
|
||||||
|
if (comp.length())
|
||||||
|
p.appendComponent(component(comp, cset));
|
||||||
|
|
||||||
|
start = end + 1;
|
||||||
|
}
|
||||||
|
while (end != string::npos);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const string path::toString(const string& sep, const charset& cset)
|
||||||
|
{
|
||||||
|
string str;
|
||||||
|
|
||||||
|
for (size_t i = 0 ; i < m_list.size() ; ++i)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
str += sep;
|
||||||
|
|
||||||
|
str += m_list[i].getConvertedText(cset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // utility
|
} // utility
|
||||||
} // vmime
|
} // vmime
|
||||||
|
@ -158,6 +158,25 @@ public:
|
|||||||
*/
|
*/
|
||||||
void renameParent(const path& oldPath, const path& newPath);
|
void renameParent(const path& oldPath, const path& newPath);
|
||||||
|
|
||||||
|
/** Construct a new path from a string.
|
||||||
|
*
|
||||||
|
* @param str string representation of the path
|
||||||
|
* @param sep separator string (eg: "/")
|
||||||
|
* @param cset charset in which the path is encoded (use the value returned by
|
||||||
|
* vmime::charset::getLocalCharset() to use the default charset of your system)
|
||||||
|
* @return a new path corresponding to the specified string
|
||||||
|
*/
|
||||||
|
static path fromString(const string& str, const string& sep, const charset& cset);
|
||||||
|
|
||||||
|
/** Returns a string representation of this path.
|
||||||
|
*
|
||||||
|
* @param sep separator string (eg: "/")
|
||||||
|
* @param cset charset in which to encode the components (use the value returned by
|
||||||
|
* vmime::charset::getLocalCharset() to use the default charset of your system)
|
||||||
|
* @return a string representing this path
|
||||||
|
*/
|
||||||
|
const string toString(const string& sep, const charset& cset);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
list m_list;
|
list m_list;
|
||||||
|
@ -31,6 +31,7 @@ VMIME_TEST_SUITE_BEGIN(IMAPParserTest)
|
|||||||
|
|
||||||
VMIME_TEST_LIST_BEGIN
|
VMIME_TEST_LIST_BEGIN
|
||||||
VMIME_TEST(testExtraSpaceInCapaResponse)
|
VMIME_TEST(testExtraSpaceInCapaResponse)
|
||||||
|
VMIME_TEST(testContinueReqWithoutSpace)
|
||||||
VMIME_TEST_LIST_END
|
VMIME_TEST_LIST_END
|
||||||
|
|
||||||
|
|
||||||
@ -64,4 +65,40 @@ VMIME_TEST_SUITE_BEGIN(IMAPParserTest)
|
|||||||
VASSERT_THROW("strict mode", parser->readResponse(/* literalHandler */ NULL), vmime::exceptions::invalid_response);
|
VASSERT_THROW("strict mode", parser->readResponse(/* literalHandler */ NULL), vmime::exceptions::invalid_response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For Apple iCloud/Exchange IMAP server
|
||||||
|
void testContinueReqWithoutSpace()
|
||||||
|
{
|
||||||
|
// continue_req ::= "+" SPACE (resp_text / base64)
|
||||||
|
//
|
||||||
|
// Some servers do not send SPACE when response text is empty.
|
||||||
|
// IMAP parser should allow this in non-strict mode.
|
||||||
|
//
|
||||||
|
// Eg:
|
||||||
|
//
|
||||||
|
// C: a002 AUTHENTICATE xxx[CR][LF]
|
||||||
|
// S: +[CR][LF]
|
||||||
|
|
||||||
|
vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
|
||||||
|
vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
|
||||||
|
|
||||||
|
vmime::shared_ptr <vmime::net::imap::IMAPTag> tag =
|
||||||
|
vmime::make_shared <vmime::net::imap::IMAPTag>();
|
||||||
|
|
||||||
|
socket->localSend("+\r\n");
|
||||||
|
|
||||||
|
vmime::shared_ptr <vmime::net::imap::IMAPParser> parser =
|
||||||
|
vmime::make_shared <vmime::net::imap::IMAPParser>
|
||||||
|
(tag, vmime::dynamicCast <vmime::net::socket>(socket), toh);
|
||||||
|
|
||||||
|
parser->setStrict(false);
|
||||||
|
VASSERT_NO_THROW("non-strict mode", parser->readResponse());
|
||||||
|
|
||||||
|
++(*tag);
|
||||||
|
|
||||||
|
socket->localSend("+\r\n");
|
||||||
|
|
||||||
|
parser->setStrict(true);
|
||||||
|
VASSERT_THROW("strict mode", parser->readResponse(), vmime::exceptions::invalid_response);
|
||||||
|
}
|
||||||
|
|
||||||
VMIME_TEST_SUITE_END
|
VMIME_TEST_SUITE_END
|
||||||
|
@ -79,6 +79,12 @@ const vmime::string testSocket::getPeerAddress() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vmime::shared_ptr <vmime::net::timeoutHandler> testSocket::getTimeoutHandler()
|
||||||
|
{
|
||||||
|
return vmime::null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void testSocket::receive(vmime::string& buffer)
|
void testSocket::receive(vmime::string& buffer)
|
||||||
{
|
{
|
||||||
buffer = m_inBuffer;
|
buffer = m_inBuffer;
|
||||||
|
@ -263,6 +263,8 @@ public:
|
|||||||
const vmime::string getPeerName() const;
|
const vmime::string getPeerName() const;
|
||||||
const vmime::string getPeerAddress() const;
|
const vmime::string getPeerAddress() const;
|
||||||
|
|
||||||
|
vmime::shared_ptr <vmime::net::timeoutHandler> getTimeoutHandler();
|
||||||
|
|
||||||
/** Send data to client.
|
/** Send data to client.
|
||||||
*
|
*
|
||||||
* @param buffer data to send
|
* @param buffer data to send
|
||||||
|
@ -53,6 +53,10 @@ VMIME_TEST_SUITE_BEGIN(utilityPathTest)
|
|||||||
VMIME_TEST(testIsParentOf_EquivalentCharset)
|
VMIME_TEST(testIsParentOf_EquivalentCharset)
|
||||||
|
|
||||||
VMIME_TEST(testRenameParent)
|
VMIME_TEST(testRenameParent)
|
||||||
|
|
||||||
|
VMIME_TEST(testFromString)
|
||||||
|
VMIME_TEST(testFromString_IgnoreLeadingOrTrailingSep)
|
||||||
|
VMIME_TEST(testToString)
|
||||||
VMIME_TEST_LIST_END
|
VMIME_TEST_LIST_END
|
||||||
|
|
||||||
|
|
||||||
@ -313,5 +317,41 @@ VMIME_TEST_SUITE_BEGIN(utilityPathTest)
|
|||||||
VASSERT_EQ("6", "d", p.getComponentAt(4).getBuffer());
|
VASSERT_EQ("6", "d", p.getComponentAt(4).getBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testFromString()
|
||||||
|
{
|
||||||
|
path p = path::fromString("ab/cde/f", "/", vmime::charset("my-charset"));
|
||||||
|
|
||||||
|
VASSERT_EQ("count", 3, p.getSize());
|
||||||
|
VASSERT_EQ("buffer1", "ab", p.getComponentAt(0).getBuffer());
|
||||||
|
VASSERT_EQ("charset1", "my-charset", p.getComponentAt(0).getCharset().getName());
|
||||||
|
VASSERT_EQ("buffer2", "cde", p.getComponentAt(1).getBuffer());
|
||||||
|
VASSERT_EQ("charset2", "my-charset", p.getComponentAt(1).getCharset().getName());
|
||||||
|
VASSERT_EQ("buffer3", "f", p.getComponentAt(2).getBuffer());
|
||||||
|
VASSERT_EQ("charset3", "my-charset", p.getComponentAt(2).getCharset().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
void testFromString_IgnoreLeadingOrTrailingSep()
|
||||||
|
{
|
||||||
|
path p = path::fromString("//ab/cde/f////", "/", vmime::charset("my-charset"));
|
||||||
|
|
||||||
|
VASSERT_EQ("count", 3, p.getSize());
|
||||||
|
VASSERT_EQ("buffer1", "ab", p.getComponentAt(0).getBuffer());
|
||||||
|
VASSERT_EQ("charset1", "my-charset", p.getComponentAt(0).getCharset().getName());
|
||||||
|
VASSERT_EQ("buffer2", "cde", p.getComponentAt(1).getBuffer());
|
||||||
|
VASSERT_EQ("charset2", "my-charset", p.getComponentAt(1).getCharset().getName());
|
||||||
|
VASSERT_EQ("buffer3", "f", p.getComponentAt(2).getBuffer());
|
||||||
|
VASSERT_EQ("charset3", "my-charset", p.getComponentAt(2).getCharset().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
void testToString()
|
||||||
|
{
|
||||||
|
path p;
|
||||||
|
p.appendComponent(comp("ab"));
|
||||||
|
p.appendComponent(comp("cde"));
|
||||||
|
p.appendComponent(comp("f"));
|
||||||
|
|
||||||
|
VASSERT_EQ("string", "ab/cde/f", p.toString("/", vmime::charset("us-ascii")));
|
||||||
|
}
|
||||||
|
|
||||||
VMIME_TEST_SUITE_END
|
VMIME_TEST_SUITE_END
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user