diff options
Diffstat (limited to 'src/core/pop/MCPOPSession.cpp')
-rw-r--r-- | src/core/pop/MCPOPSession.cpp | 602 |
1 files changed, 602 insertions, 0 deletions
diff --git a/src/core/pop/MCPOPSession.cpp b/src/core/pop/MCPOPSession.cpp new file mode 100644 index 00000000..8415a081 --- /dev/null +++ b/src/core/pop/MCPOPSession.cpp @@ -0,0 +1,602 @@ +#include "MCWin32.h" // should be included first. + +#include "MCPOPSession.h" + +#include <string.h> +#include <libetpan/libetpan.h> + +#include "MCPOPMessageInfo.h" +#include "MCPOPProgressCallback.h" +#include "MCMessageHeader.h" +#include "MCConnectionLoggerUtils.h" +#include "MCCertificateUtils.h" + +using namespace mailcore; + +enum { + STATE_DISCONNECTED, + STATE_CONNECTED, + STATE_LOGGEDIN, + STATE_LISTED, +}; + +void POPSession::init() +{ + mHostname = NULL; + mPort = 0; + mUsername = NULL; + mPassword = NULL; + mAuthType = AuthTypeSASLNone; + mConnectionType = ConnectionTypeClear; + mCheckCertificateEnabled = true; + mTimeout = 30; + + mPop = NULL; + mCapabilities = POPCapabilityNone; + mProgressCallback = NULL; + mState = STATE_DISCONNECTED; + mConnectionLogger = NULL; +} + +POPSession::POPSession() +{ + init(); +} + +POPSession::~POPSession() +{ + MC_SAFE_RELEASE(mHostname); + MC_SAFE_RELEASE(mUsername); + MC_SAFE_RELEASE(mPassword); +} + +void POPSession::setHostname(String * hostname) +{ + MC_SAFE_REPLACE_COPY(String, mHostname, hostname); +} + +String * POPSession::hostname() +{ + return mHostname; +} + +void POPSession::setPort(unsigned int port) +{ + mPort = port; +} + +unsigned int POPSession::port() +{ + return mPort; +} + +void POPSession::setUsername(String * username) +{ + MC_SAFE_REPLACE_COPY(String, mUsername, username); +} + +String * POPSession::username() +{ + return mUsername; +} + +void POPSession::setPassword(String * password) +{ + MC_SAFE_REPLACE_COPY(String, mPassword, password); +} + +String * POPSession::password() +{ + return mPassword; +} + +void POPSession::setAuthType(AuthType authType) +{ + mAuthType = authType; +} + +AuthType POPSession::authType() +{ + return mAuthType; +} + +void POPSession::setConnectionType(ConnectionType connectionType) +{ + mConnectionType = connectionType; +} + +ConnectionType POPSession::connectionType() +{ + return mConnectionType; +} + +void POPSession::setTimeout(time_t timeout) +{ + mTimeout = timeout; +} + +time_t POPSession::timeout() +{ + return mTimeout; +} + +void POPSession::setCheckCertificateEnabled(bool enabled) +{ + mCheckCertificateEnabled = enabled; +} + +bool POPSession::isCheckCertificateEnabled() +{ + return mCheckCertificateEnabled; +} + +bool POPSession::checkCertificate() +{ + if (!isCheckCertificateEnabled()) + return true; + return mailcore::checkCertificate(mPop->pop3_stream, hostname()); +} + +void POPSession::bodyProgress(unsigned int current, unsigned int maximum) +{ + if (mProgressCallback != NULL) { + mProgressCallback->bodyProgress(this, current, maximum); + } +} + +void POPSession::body_progress(size_t current, size_t maximum, void * context) +{ + POPSession * session; + + session = (POPSession *) context; + session->bodyProgress((unsigned int) current, (unsigned int) maximum); +} + +static void logger(mailpop3 * pop3, int log_type, const char * buffer, size_t size, void * context) +{ + POPSession * session = (POPSession *) context; + + if (session->connectionLogger() == NULL) + return; + + ConnectionLogType type = getConnectionType(log_type); + bool isBuffer = isBufferFromLogType(log_type); + + if (isBuffer) { + Data * data = Data::dataWithBytes(buffer, (unsigned int) size); + session->connectionLogger()->log(session, type, data); + } + else { + session->connectionLogger()->log(session, type, NULL); + } +} + +void POPSession::setup() +{ + mPop = mailpop3_new(0, NULL); + mailpop3_set_progress_callback(mPop, POPSession::body_progress, this); + mailpop3_set_logger(mPop, logger, this); +} + +void POPSession::unsetup() +{ + if (mPop != NULL) { + if (mPop->pop3_stream != NULL) { + mailstream_close(mPop->pop3_stream); + mPop->pop3_stream = NULL; + } + mailpop3_free(mPop); + mPop = NULL; + } +} + +void POPSession::connectIfNeeded(ErrorCode * pError) +{ + if (mState == STATE_DISCONNECTED) { + connect(pError); + } + else { + * pError = ErrorNone; + } +} + +void POPSession::connect(ErrorCode * pError) +{ + int r; + + setup(); + + switch (mConnectionType) { + case ConnectionTypeStartTLS: + MCLog("connect %s %u", MCUTF8(hostname()), (unsigned int) port()); + r = mailpop3_socket_connect(mPop, MCUTF8(hostname()), port()); + if (r != MAILPOP3_NO_ERROR) { + * pError = ErrorConnection; + return; + } + + MCLog("start TLS"); + r = mailpop3_socket_starttls(mPop); + if (r != MAILPOP3_NO_ERROR) { + * pError = ErrorStartTLSNotAvailable; + return; + } + MCLog("done"); + if (!checkCertificate()) { + * pError = ErrorCertificate; + return; + } + break; + + case ConnectionTypeTLS: + MCLog("connect %s %u", MCUTF8(hostname()), (unsigned int) port()); + r = mailpop3_ssl_connect(mPop, MCUTF8(hostname()), port()); + if (r != MAILPOP3_NO_ERROR) { + * pError = ErrorConnection; + return; + } + if (!checkCertificate()) { + * pError = ErrorCertificate; + return; + } + break; + + default: + r = mailpop3_socket_connect(mPop, MCUTF8(hostname()), port()); + if (r != MAILPOP3_NO_ERROR) { + * pError = ErrorConnection; + return; + } + break; + } + + mailstream_low * low; + String * identifierString; + char * identifier; + + low = mailstream_get_low(mPop->pop3_stream); + if (mUsername != NULL) { + identifierString = String::stringWithUTF8Format("%s@%s:%u", MCUTF8(mUsername), MCUTF8(mHostname), mPort); + } + else { + identifierString = String::stringWithUTF8Format("%s:%u", MCUTF8(mUsername), mPort); + } + identifier = strdup(identifierString->UTF8Characters()); + mailstream_low_set_identifier(low, identifier); + mState = STATE_CONNECTED; + * pError = ErrorNone; +} + +void POPSession::disconnect() +{ + if (mPop == NULL) + return; + + mailpop3_quit(mPop); + mState = STATE_DISCONNECTED; + unsetup(); +} + +void POPSession::loginIfNeeded(ErrorCode * pError) +{ + connectIfNeeded(pError); + if (* pError != ErrorNone) + return; + + if (mState == STATE_CONNECTED) { + login(pError); + } + else { + * pError = ErrorNone; + } +} + +void POPSession::login(ErrorCode * pError) +{ + int r; + const char * utf8username; + const char * utf8password; + + utf8username = MCUTF8(username()); + utf8password = MCUTF8(password()); + if (utf8username == NULL) { + utf8username = ""; + } + if (utf8password == NULL) { + utf8password = ""; + } + + switch (authType()) { + case 0: + default: + r = mailpop3_user(mPop, utf8username); + if (r == MAILPOP3_ERROR_STREAM) { + * pError = ErrorConnection; + return; + } + else if (r != MAILPOP3_NO_ERROR) { + * pError = ErrorAuthentication; + return; + } + + r = mailpop3_pass(mPop, utf8password); + break; + + case AuthTypeSASLCRAMMD5: + r = mailpop3_auth(mPop, "CRAM-MD5", + MCUTF8(hostname()), + NULL, + NULL, + utf8username, utf8username, + utf8password, NULL); + break; + + case AuthTypeSASLPlain: + r = mailpop3_auth(mPop, "PLAIN", + MCUTF8(hostname()), + NULL, + NULL, + utf8username, utf8username, + utf8password, NULL); + break; + + case AuthTypeSASLGSSAPI: + // needs to be tested + r = mailpop3_auth(mPop, "GSSAPI", + MCUTF8(hostname()), + NULL, + NULL, + utf8username, utf8username, + utf8password, NULL /* realm */); + break; + + case AuthTypeSASLDIGESTMD5: + r = mailpop3_auth(mPop, "DIGEST-MD5", + MCUTF8(hostname()), + NULL, + NULL, + utf8username, utf8username, + utf8password, NULL); + break; + + case AuthTypeSASLLogin: + r = mailpop3_auth(mPop, "LOGIN", + MCUTF8(hostname()), + NULL, + NULL, + utf8username, utf8username, + utf8password, NULL); + break; + + case AuthTypeSASLSRP: + r = mailpop3_auth(mPop, "SRP", + MCUTF8(hostname()), + NULL, + NULL, + utf8username, utf8username, + utf8password, NULL); + break; + + case AuthTypeSASLNTLM: + r = mailpop3_auth(mPop, "NTLM", + MCUTF8(hostname()), + NULL, + NULL, + utf8username, utf8username, + utf8password, NULL /* realm */); + break; + + case AuthTypeSASLKerberosV4: + r = mailpop3_auth(mPop, "KERBEROS_V4", + MCUTF8(hostname()), + NULL, + NULL, + utf8username, utf8username, + utf8password, NULL /* realm */); + break; + } + if (r == MAILPOP3_ERROR_STREAM) { + * pError = ErrorConnection; + return; + } + else if (r != MAILPOP3_NO_ERROR) { + * pError = ErrorAuthentication; + return; + } + + mState = STATE_LOGGEDIN; + * pError = ErrorNone; +} + +Array * POPSession::fetchMessages(ErrorCode * pError) +{ + int r; + carray * msg_list; + + loginIfNeeded(pError); + if (* pError != ErrorNone) { + return NULL; + } + + r = mailpop3_list(mPop, &msg_list); + if (r == MAILPOP3_ERROR_STREAM) { + * pError = ErrorConnection; + return NULL; + } + else if (r != MAILPOP3_NO_ERROR) { + * pError = ErrorFetchMessageList; + return NULL; + } + + Array * result = Array::array(); + for(unsigned int i = 0 ; i < carray_count(msg_list) ; i ++) { + struct mailpop3_msg_info * msg_info; + String * uid; + + msg_info = (struct mailpop3_msg_info *) carray_get(msg_list, i); + if (msg_info->msg_uidl == NULL) + continue; + + uid = String::stringWithUTF8Characters(msg_info->msg_uidl); + + POPMessageInfo * info = new POPMessageInfo(); + info->setUid(uid); + info->setSize(msg_info->msg_size); + info->setIndex(msg_info->msg_index); + result->addObject(info); + info->release(); + } + + * pError = ErrorNone; + mState = STATE_LISTED; + + return result; +} + +void POPSession::listIfNeeded(ErrorCode * pError) +{ + if (mState == STATE_LISTED) { + * pError = ErrorNone; + return; + } + + fetchMessages(pError); +} + +MessageHeader * POPSession::fetchHeader(unsigned int index, ErrorCode * pError) +{ + int r; + char * content; + size_t content_len; + + listIfNeeded(pError); + if (* pError != ErrorNone) { + return NULL; + } + + r = mailpop3_top(mPop, index, 0, &content, &content_len); + if (r == MAILPOP3_ERROR_STREAM) { + * pError = ErrorConnection; + return NULL; + } + else if (r != MAILPOP3_NO_ERROR) { + * pError = ErrorFetch; + return NULL; + } + + Data * data; + data = new Data(content, (unsigned int) content_len); + MessageHeader * result = new MessageHeader(); + result->importHeadersData(data); + result->autorelease(); + data->release(); + + mailpop3_top_free(content); + * pError = ErrorNone; + + return result; +} + +MessageHeader * POPSession::fetchHeader(POPMessageInfo * msg, ErrorCode * pError) +{ + return fetchHeader(msg->index(), pError); +} + +Data * POPSession::fetchMessage(unsigned int index, POPProgressCallback * callback, ErrorCode * pError) +{ + int r; + char * content; + size_t content_len; + + listIfNeeded(pError); + if (* pError != ErrorNone) { + return NULL; + } + + mProgressCallback = callback; + + r = mailpop3_retr(mPop, index, &content, &content_len); + mProgressCallback = NULL; + if (r == MAILPOP3_ERROR_STREAM) { + * pError = ErrorConnection; + return NULL; + } + else if (r != MAILPOP3_NO_ERROR) { + * pError = ErrorFetch; + return NULL; + } + + Data * result; + result = Data::dataWithBytes(content, (unsigned int) content_len); + mailpop3_retr_free(content); + * pError = ErrorNone; + + return result; +} + +Data * POPSession::fetchMessage(POPMessageInfo * msg, POPProgressCallback * callback, ErrorCode * pError) +{ + return fetchMessage(msg->index(), callback, pError); +} + +void POPSession::deleteMessage(unsigned int index, ErrorCode * pError) +{ + int r; + + listIfNeeded(pError); + if (* pError != ErrorNone) { + return; + } + + r = mailpop3_dele(mPop, index); + if (r == MAILPOP3_ERROR_STREAM) { + * pError = ErrorConnection; + return; + } + else if (r != MAILPOP3_NO_ERROR) { + * pError = ErrorDeleteMessage; + return; + } + + * pError = ErrorNone; +} + +void POPSession::deleteMessage(POPMessageInfo * msg, ErrorCode * pError) +{ + deleteMessage(msg->index(), pError); +} + +void POPSession::checkAccount(ErrorCode * pError) +{ + loginIfNeeded(pError); +} + +void POPSession::noop(ErrorCode * pError) +{ + int r; + + if (mPop == NULL) + return; + + MCLog("connect"); + loginIfNeeded(pError); + if (* pError != ErrorNone) { + return; + } + if (mPop->pop3_stream != NULL) { + r = mailpop3_noop(mPop); + if ((r == MAILPOP3_ERROR_STREAM) || (r == MAILPOP3_ERROR_BAD_STATE)) { + * pError = ErrorConnection; + } + } +} + +void POPSession::setConnectionLogger(ConnectionLogger * logger) +{ + mConnectionLogger = logger; +} + +ConnectionLogger * POPSession::connectionLogger() +{ + return mConnectionLogger; +} |