From 811b8ac5057f0c77e3db388088c61e0763282fd9 Mon Sep 17 00:00:00 2001 From: AlexKar Date: Sat, 2 Apr 2016 08:36:38 +0400 Subject: Added ability of canceling for active sending operation Added ability of canceling for active sending operation --- src/async/smtp/MCSMTPSendWithDataOperation.cpp | 6 +++ src/async/smtp/MCSMTPSendWithDataOperation.h | 2 +- src/core/smtp/MCSMTPSession.cpp | 73 ++++++++++++++++++++++++-- src/core/smtp/MCSMTPSession.h | 9 ++++ 4 files changed, 85 insertions(+), 5 deletions(-) diff --git a/src/async/smtp/MCSMTPSendWithDataOperation.cpp b/src/async/smtp/MCSMTPSendWithDataOperation.cpp index 4561b5d8..28cc02bf 100644 --- a/src/async/smtp/MCSMTPSendWithDataOperation.cpp +++ b/src/async/smtp/MCSMTPSendWithDataOperation.cpp @@ -84,3 +84,9 @@ void SMTPSendWithDataOperation::main() } setError(error); } + +void SMTPSendWithDataOperation::cancel() +{ + SMTPOperation::cancel(); + session()->session()->cancelMessageSending(); +} diff --git a/src/async/smtp/MCSMTPSendWithDataOperation.h b/src/async/smtp/MCSMTPSendWithDataOperation.h index 768adda9..25685148 100644 --- a/src/async/smtp/MCSMTPSendWithDataOperation.h +++ b/src/async/smtp/MCSMTPSendWithDataOperation.h @@ -37,7 +37,7 @@ namespace mailcore { public: // subclass behavior virtual void main(); - + virtual void cancel(); private: Data * mMessageData; String * mMessageFilepath; diff --git a/src/core/smtp/MCSMTPSession.cpp b/src/core/smtp/MCSMTPSession.cpp index ebf94f43..dfd55176 100644 --- a/src/core/smtp/MCSMTPSession.cpp +++ b/src/core/smtp/MCSMTPSession.cpp @@ -21,6 +21,12 @@ enum { STATE_LOGGEDIN, }; +#define CANCEL_LOCK() pthread_mutex_lock(&mCancelLock) +#define CANCEL_UNLOCK() pthread_mutex_unlock(&mCancelLock) + +#define CAN_CANCEL_LOCK() pthread_mutex_lock(&mCanCancelLock) +#define CAN_CANCEL_UNLOCK() pthread_mutex_unlock(&mCanCancelLock) + void SMTPSession::init() { mHostname = NULL; @@ -34,6 +40,8 @@ void SMTPSession::init() mCheckCertificateEnabled = true; mUseHeloIPEnabled = false; mShouldDisconnect = false; + mSendingCancelled = false; + mCanCancel = false; mSmtp = NULL; mProgressCallback = NULL; @@ -43,6 +51,8 @@ void SMTPSession::init() mLastSMTPResponseCode = 0; mConnectionLogger = NULL; pthread_mutex_init(&mConnectionLoggerLock, NULL); + pthread_mutex_init(&mCancelLock, NULL); + pthread_mutex_init(&mCanCancelLock, NULL); } SMTPSession::SMTPSession() @@ -53,6 +63,8 @@ SMTPSession::SMTPSession() SMTPSession::~SMTPSession() { pthread_mutex_destroy(&mConnectionLoggerLock); + pthread_mutex_destroy(&mCancelLock); + pthread_mutex_destroy(&mCanCancelLock); MC_SAFE_RELEASE(mLastSMTPResponse); MC_SAFE_RELEASE(mHostname); MC_SAFE_RELEASE(mUsername); @@ -157,6 +169,12 @@ bool SMTPSession::checkCertificate() return mailcore::checkCertificate(mSmtp->stream, hostname()); } +void SMTPSession::setSendingCancelled(bool isCancelled) { + CANCEL_LOCK(); + mSendingCancelled = isCancelled; + CANCEL_UNLOCK(); +} + void SMTPSession::setUseHeloIPEnabled(bool enabled) { mUseHeloIPEnabled = enabled; @@ -609,10 +627,18 @@ void SMTPSession::checkAccount(Address * from, ErrorCode * pError) } void SMTPSession::sendMessage(Address * from, Array * recipients, Data * messageData, + SMTPProgressCallback * callback, ErrorCode * pError) +{ + setSendingCancelled(false); + internalSendMessage(from, recipients, messageData, callback, pError); +} + +void SMTPSession::internalSendMessage(Address * from, Array * recipients, Data * messageData, SMTPProgressCallback * callback, ErrorCode * pError) { clist * address_list; int r; + bool sendingCancelled; if (from == NULL) { * pError = ErrorNoSender; @@ -635,6 +661,17 @@ void SMTPSession::sendMessage(Address * from, Array * recipients, Data * message if (* pError != ErrorNone) { goto err; } + + CANCEL_LOCK(); + sendingCancelled = mSendingCancelled; + CANCEL_UNLOCK(); + if (sendingCancelled) { + goto err; + } + + CAN_CANCEL_LOCK(); + mCanCancel = true; + CAN_CANCEL_UNLOCK(); // disable DSN feature for more compatibility mSmtp->esmtp &= ~MAILSMTP_ESMTP_DSN; @@ -646,15 +683,25 @@ void SMTPSession::sendMessage(Address * from, Array * recipients, Data * message } MCLog("send"); if ((mSmtp->esmtp & MAILSMTP_ESMTP_PIPELINING) != 0) { - r = mailesmtp_send_quit(mSmtp, MCUTF8(from->mailbox()), 0, NULL, - address_list, - messageData->bytes(), messageData->length()); + r = mailesmtp_send_quit_no_disconnect(mSmtp, MCUTF8(from->mailbox()), 0, NULL, + address_list, + messageData->bytes(), messageData->length()); + CAN_CANCEL_LOCK(); + mCanCancel = false; + CAN_CANCEL_UNLOCK(); + if (mSmtp->stream != NULL) { + mailstream_close(mSmtp->stream); + mSmtp->stream = NULL; + } mShouldDisconnect = true; } else { r = mailesmtp_send(mSmtp, MCUTF8(from->mailbox()), 0, NULL, address_list, messageData->bytes(), messageData->length()); + CAN_CANCEL_LOCK(); + mCanCancel = false; + CAN_CANCEL_UNLOCK(); mailsmtp_quit(mSmtp); } esmtp_address_list_free(address_list); @@ -727,13 +774,14 @@ void SMTPSession::sendMessage(Address * from, Array * recipients, Data * message void SMTPSession::sendMessage(Address * from, Array * recipients, String * messagePath, SMTPProgressCallback * callback, ErrorCode * pError) { + setSendingCancelled(false); Data * messageData = Data::dataWithContentsOfFile(messagePath); if (!messageData) { * pError = ErrorFile; return; } - return sendMessage(from, recipients, messageData, callback, pError); + return internalSendMessage(from, recipients, messageData, callback, pError); } static void mmapStringDeallocator(char * bytes, unsigned int length) { @@ -802,6 +850,7 @@ Data * SMTPSession::dataWithFilteredBcc(Data * data) void SMTPSession::sendMessage(Data * messageData, SMTPProgressCallback * callback, ErrorCode * pError) { + setSendingCancelled(false); AutoreleasePool * pool = new AutoreleasePool(); MessageParser * parser = new MessageParser(messageData); Array * recipients = new Array(); @@ -826,6 +875,7 @@ void SMTPSession::sendMessage(Data * messageData, SMTPProgressCallback * callbac void SMTPSession::sendMessage(MessageBuilder * msg, SMTPProgressCallback * callback, ErrorCode * pError) { + setSendingCancelled(false); Array * recipients = new Array(); if (msg->header()->to() != NULL) { recipients->addObjectsFromArray(msg->header()->to()); @@ -864,6 +914,21 @@ void SMTPSession::noop(ErrorCode * pError) } } +void SMTPSession::cancelMessageSending() +{ + // main thread + + setSendingCancelled(true); + + CAN_CANCEL_LOCK(); + if (mCanCancel) { + if (mSmtp != NULL && mSmtp->stream != NULL) { + mailstream_cancel(mSmtp->stream); + } + } + CAN_CANCEL_UNLOCK(); +} + bool SMTPSession::isDisconnected() { return mState == STATE_DISCONNECTED; diff --git a/src/core/smtp/MCSMTPSession.h b/src/core/smtp/MCSMTPSession.h index 7e899881..e54673c5 100644 --- a/src/core/smtp/MCSMTPSession.h +++ b/src/core/smtp/MCSMTPSession.h @@ -63,6 +63,8 @@ namespace mailcore { virtual void sendMessage(Address * from, Array * /* Address */ recipients, String * messagePath, SMTPProgressCallback * callback, ErrorCode * pError); + virtual void cancelMessageSending(); + virtual void setConnectionLogger(ConnectionLogger * logger); virtual ConnectionLogger * connectionLogger(); @@ -85,6 +87,8 @@ namespace mailcore { bool mCheckCertificateEnabled; bool mUseHeloIPEnabled; bool mShouldDisconnect; + bool mSendingCancelled; + bool mCanCancel; mailsmtp * mSmtp; SMTPProgressCallback * mProgressCallback; @@ -92,6 +96,8 @@ namespace mailcore { String * mLastSMTPResponse; int mLastLibetpanError; int mLastSMTPResponseCode; + pthread_mutex_t mCancelLock; + pthread_mutex_t mCanCancelLock; ConnectionLogger * mConnectionLogger; pthread_mutex_t mConnectionLoggerLock; @@ -104,8 +110,11 @@ namespace mailcore { void unsetup(); void connectIfNeeded(ErrorCode * pError); bool checkCertificate(); + void setSendingCancelled(bool isCancelled); void sendMessage(MessageBuilder * msg, SMTPProgressCallback * callback, ErrorCode * pError); + void internalSendMessage(Address * from, Array * /* Address */ recipients, Data * messageData, + SMTPProgressCallback * callback, ErrorCode * pError); public: // private virtual bool isDisconnected(); -- cgit v1.2.3