aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/imap/MCIMAPSession.cpp
diff options
context:
space:
mode:
authorGravatar Dmitry Isaikin <isaikin-dmitry@yandex.ru>2016-06-06 04:28:53 +0400
committerGravatar HoĆ  V. DINH <dinh.viet.hoa@gmail.com>2016-06-05 17:28:53 -0700
commiteeed76e48c830fe742eadd435682f3b1e6036f83 (patch)
tree36bad63fccde47e6cdecb7033f65a3d75e1bbb71 /src/core/imap/MCIMAPSession.cpp
parent6dbe79ccf3f085da9a195ee3f9a59cb4449f6505 (diff)
Add possibility of fetching message attachment by chunks and store it to file. (#1438)
Diffstat (limited to 'src/core/imap/MCIMAPSession.cpp')
-rw-r--r--src/core/imap/MCIMAPSession.cpp162
1 files changed, 155 insertions, 7 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;