diff options
Diffstat (limited to 'src/core/imap')
-rw-r--r-- | src/core/imap/MCIMAPSession.cpp | 162 | ||||
-rw-r--r-- | src/core/imap/MCIMAPSession.h | 13 |
2 files changed, 167 insertions, 8 deletions
diff --git a/src/core/imap/MCIMAPSession.cpp b/src/core/imap/MCIMAPSession.cpp index 61be95c3..1357f47f 100644 --- a/src/core/imap/MCIMAPSession.cpp +++ b/src/core/imap/MCIMAPSession.cpp @@ -27,9 +27,63 @@ #include "MCCertificateUtils.h" #include "MCIMAPIdentity.h" #include "MCLibetpan.h" +#include "MCDataStreamDecoder.h" using namespace mailcore; +class LoadByChunkProgress : public Object, public IMAPProgressCallback { +public: + LoadByChunkProgress(); + virtual ~LoadByChunkProgress(); + + virtual void setOffset(uint32_t offset); + virtual void setEstimatedSize(uint32_t estimatedSize); + virtual void setProgressCallback(IMAPProgressCallback * progressCallback); + + virtual void bodyProgress(IMAPSession * session, unsigned int current, unsigned int maximum); + +private: + uint32_t mOffset; + uint32_t mEstimatedSize; + IMAPProgressCallback * mProgressCallback; // non retained +}; + +LoadByChunkProgress::LoadByChunkProgress() +{ + mOffset = 0; + mEstimatedSize = 0; + mProgressCallback = NULL; +} + +LoadByChunkProgress::~LoadByChunkProgress() +{ +} + +void LoadByChunkProgress::setOffset(uint32_t offset) +{ + mOffset = offset; +} + +void LoadByChunkProgress::setEstimatedSize(uint32_t estimatedSize) +{ + mEstimatedSize = estimatedSize; +} + +void LoadByChunkProgress::setProgressCallback(IMAPProgressCallback * progressCallback) +{ + mProgressCallback = progressCallback; +} + +void LoadByChunkProgress::bodyProgress(IMAPSession * session, unsigned int current, unsigned int maximum) +{ + // In case of loading attachment by chunks we need report overall progress + if (mEstimatedSize > 0 && mEstimatedSize > maximum) { + maximum = mEstimatedSize; + current += mOffset; + } + mProgressCallback->bodyProgress(session, current, maximum); +} + enum { STATE_DISCONNECTED, STATE_CONNECTED, @@ -2813,8 +2867,9 @@ static void nstringDeallocator(char * bytes, unsigned int length) { mailimap_nstring_free(bytes); }; -Data * IMAPSession::fetchMessageAttachment(String * folder, bool identifier_is_uid, +Data * IMAPSession::fetchNonDecodedMessageAttachment(String * folder, bool identifier_is_uid, uint32_t identifier, String * partID, + bool wholePart, uint32_t offset, uint32_t length, Encoding encoding, IMAPProgressCallback * progressCallback, ErrorCode * pError) { struct mailimap_fetch_type * fetch_type; @@ -2827,21 +2882,21 @@ Data * IMAPSession::fetchMessageAttachment(String * folder, bool identifier_is_u char * text = NULL; size_t text_length = 0; Data * data; - + selectIfNeeded(folder, pError); if (* pError != ErrorNone) return NULL; - + mProgressItemsCount = 0; mProgressCallback = progressCallback; bodyProgress(0, 0); - + partIDArray = partID->componentsSeparatedByString(MCSTR(".")); sec_list = clist_new(); for(unsigned int i = 0 ; i < partIDArray->count() ; i ++) { uint32_t * value; String * element; - + element = (String *) partIDArray->objectAtIndex(i); value = (uint32_t *) malloc(sizeof(* value)); * value = element->intValue(); @@ -2849,7 +2904,12 @@ Data * IMAPSession::fetchMessageAttachment(String * folder, bool identifier_is_u } section_part = mailimap_section_part_new(sec_list); section = mailimap_section_new_part(section_part); - fetch_att = mailimap_fetch_att_new_body_peek_section(section); + if (wholePart) { + fetch_att = mailimap_fetch_att_new_body_peek_section(section); + } + else { + fetch_att = mailimap_fetch_att_new_body_peek_section_partial(section, offset, length); + } fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); #ifdef LIBETPAN_HAS_MAILIMAP_RAMBLER_WORKAROUND @@ -2885,13 +2945,23 @@ Data * IMAPSession::fetchMessageAttachment(String * folder, bool identifier_is_u data = Data::data(); data->takeBytesOwnership(text, (unsigned int) text_length, nstringDeallocator); - data = data->decodedDataUsingEncoding(encoding); * pError = ErrorNone; return data; } +Data * IMAPSession::fetchMessageAttachment(String * folder, bool identifier_is_uid, + uint32_t identifier, String * partID, + Encoding encoding, IMAPProgressCallback * progressCallback, ErrorCode * pError) +{ + Data * data = fetchNonDecodedMessageAttachment(folder, identifier_is_uid, identifier, partID, true, 0, 0, encoding, progressCallback, pError); + if (data) { + data = data->decodedDataUsingEncoding(encoding); + } + return data; +} + Data * IMAPSession::fetchMessageAttachmentByUID(String * folder, uint32_t uid, String * partID, Encoding encoding, IMAPProgressCallback * progressCallback, ErrorCode * pError) { @@ -2904,6 +2974,84 @@ Data * IMAPSession::fetchMessageAttachmentByNumber(String * folder, uint32_t num return fetchMessageAttachment(folder, false, number, partID, encoding, progressCallback, pError); } +void IMAPSession::fetchMessageAttachmentToFileByUID(String * folder, uint32_t uid, String * partID, + uint32_t estimatedSize, Encoding encoding, + String * outputFile, uint32_t chunkSize, + IMAPProgressCallback * progressCallback, ErrorCode * pError) +{ + DataStreamDecoder * decoder = new DataStreamDecoder(); + decoder->setEncoding(encoding); + decoder->setFilename(outputFile); + + int nRetries = 0; + int const maxRetries = 3; + ErrorCode error = ErrorNone; + uint32_t offset = 0; + while (1) { + AutoreleasePool * pool = new AutoreleasePool(); + + LoadByChunkProgress * chunkProgressCallback = new LoadByChunkProgress(); + chunkProgressCallback->setOffset(offset); + chunkProgressCallback->setEstimatedSize(estimatedSize); + chunkProgressCallback->setProgressCallback(progressCallback); + + Data * data = fetchNonDecodedMessageAttachment(folder, true, uid, partID, false, offset, chunkSize, encoding, chunkProgressCallback, &error); + + MC_SAFE_RELEASE(chunkProgressCallback); + + if (error != ErrorNone) { + pool->release(); + if ((error == ErrorConnection || error == ErrorParse) && nRetries < maxRetries) { + error = ErrorNone; + nRetries++; + continue; + } + break; + } else { + nRetries = 0; + } + + if (data == NULL) { + break; + } + + uint32_t encodedSize = data->length(); + if (encodedSize == 0) { + pool->release(); + break; + } + + error = decoder->appendData(data); + + pool->release(); + + if (error != ErrorNone) { + break; + } + + offset += encodedSize; + + // Try detect is this chunk last. + // Estimated size (extracted from BODYSTRUCTURE info) may be incorrect. + // Also, server may return chunk with size less than requested. + // So this detection is some tricky. + bool endOfPart = ((encodedSize == 0) || + (estimatedSize > 0 && (estimatedSize <= offset) && (encodedSize != chunkSize)) || + (estimatedSize == 0 && encodedSize < chunkSize)); + if (endOfPart) { + break; + } + } + + if (error == ErrorNone) { + decoder->flushData(); + } + + MC_SAFE_RELEASE(decoder); + + * pError = error; +} + IndexSet * IMAPSession::search(String * folder, IMAPSearchKind kind, String * searchString, ErrorCode * pError) { IMAPSearchExpression * expr; diff --git a/src/core/imap/MCIMAPSession.h b/src/core/imap/MCIMAPSession.h index adbecd43..55f47de0 100644 --- a/src/core/imap/MCIMAPSession.h +++ b/src/core/imap/MCIMAPSession.h @@ -121,6 +121,12 @@ namespace mailcore { IMAPProgressCallback * progressCallback, ErrorCode * pError); virtual Data * fetchMessageAttachmentByUID(String * folder, uint32_t uid, String * partID, Encoding encoding, IMAPProgressCallback * progressCallback, ErrorCode * pError); + + virtual void fetchMessageAttachmentToFileByUID(String * folder, uint32_t uid, String * partID, + uint32_t estimatedSize, Encoding encoding, + String * outputFile, uint32_t chunkSize, + IMAPProgressCallback * progressCallback, ErrorCode * pError); + virtual Data * fetchMessageAttachmentByNumber(String * folder, uint32_t number, String * partID, Encoding encoding, IMAPProgressCallback * progressCallback, ErrorCode * pError); virtual HashMap * fetchMessageNumberUIDMapping(String * folder, uint32_t fromUID, uint32_t toUID, @@ -305,9 +311,14 @@ namespace mailcore { Data * fetchMessageAttachment(String * folder, bool identifier_is_uid, uint32_t identifier, String * partID, Encoding encoding, IMAPProgressCallback * progressCallback, ErrorCode * pError); + // in case of wholePart is false, receives range [offset, length] + Data * fetchNonDecodedMessageAttachment(String * folder, bool identifier_is_uid, + uint32_t identifier, String * partID, + bool wholePart, uint32_t offset, uint32_t length, + Encoding encoding, IMAPProgressCallback * progressCallback, ErrorCode * pError); void storeLabels(String * folder, bool identifier_is_uid, IndexSet * identifiers, IMAPStoreFlagsRequestKind kind, Array * labels, ErrorCode * pError); }; - + } #endif |