diff options
author | Dmitry Isaikin <isaikin-dmitry@yandex.ru> | 2016-06-06 04:28:53 +0400 |
---|---|---|
committer | Hoà V. DINH <dinh.viet.hoa@gmail.com> | 2016-06-05 17:28:53 -0700 |
commit | eeed76e48c830fe742eadd435682f3b1e6036f83 (patch) | |
tree | 36bad63fccde47e6cdecb7033f65a3d75e1bbb71 /src/core/basetypes | |
parent | 6dbe79ccf3f085da9a195ee3f9a59cb4449f6505 (diff) |
Add possibility of fetching message attachment by chunks and store it to file. (#1438)
Diffstat (limited to 'src/core/basetypes')
-rw-r--r-- | src/core/basetypes/MCData.cpp | 170 | ||||
-rw-r--r-- | src/core/basetypes/MCData.h | 4 | ||||
-rw-r--r-- | src/core/basetypes/MCDataDecoderUtils.cpp | 192 | ||||
-rw-r--r-- | src/core/basetypes/MCDataDecoderUtils.h | 25 | ||||
-rw-r--r-- | src/core/basetypes/MCDataStreamDecoder.cpp | 105 | ||||
-rw-r--r-- | src/core/basetypes/MCDataStreamDecoder.h | 51 |
6 files changed, 382 insertions, 165 deletions
diff --git a/src/core/basetypes/MCData.cpp b/src/core/basetypes/MCData.cpp index 796f580e..1fee18aa 100644 --- a/src/core/basetypes/MCData.cpp +++ b/src/core/basetypes/MCData.cpp @@ -28,6 +28,7 @@ #include "MCBase64.h" #include "MCSet.h" #include "MCLock.h" +#include "MCDataDecoderUtils.h" #define MCDATA_DEFAULT_CHARSET "iso-8859-1" @@ -565,170 +566,10 @@ Data * Data::dataWithContentsOfFile(String * filename) return data; } -static size_t uudecode(const char * text, size_t size, char * dst, size_t dst_buf_size) -{ - unsigned int count = 0; - const char *b = text; /* beg */ - const char *s = b; /* src */ - const char *e = b+size; /* end */ - char *d = dst; - int out = (*s++ & 0x7f) - 0x20; - - /* don't process lines without leading count character */ - if (out < 0) - return size; - - /* dummy check. user must allocate buffer with appropriate length */ - if (dst_buf_size < out) - return size; - - /* don't process begin and end lines */ - if ((strncasecmp((const char *)b, "begin ", 6) == 0) || - (strncasecmp((const char *)b, "end", 3) == 0)) - return size; - - //while (s < e - 4) - while (s < e && count < out) - { - int v = 0; - int i; - for (i = 0; i < 4; i += 1) { - char c = *s++; - v = v << 6 | ((c - 0x20) & 0x3F); - } - for (i = 2; i >= 0; i -= 1) { - char c = (char) (v & 0xFF); - d[i] = c; - v = v >> 8; - } - d += 3; - count += 3; - } - return count; -} - -static void decodedPartDeallocator(char * decoded, unsigned int decoded_length) { - mailmime_decoded_part_free(decoded); -}; - Data * Data::decodedDataUsingEncoding(Encoding encoding) { - const char * text; - size_t text_length; - - text = bytes(); - text_length = length(); - - switch (encoding) { - case Encoding7Bit: - case Encoding8Bit: - case EncodingBinary: - case EncodingOther: - default: - { - return this; - } - case EncodingBase64: - case EncodingQuotedPrintable: - { - char * decoded; - size_t decoded_length; - size_t cur_token; - int mime_encoding; - Data * data; - - switch (encoding) { - default: //disable warning - case EncodingBase64: - mime_encoding = MAILMIME_MECHANISM_BASE64; - break; - case EncodingQuotedPrintable: - mime_encoding = MAILMIME_MECHANISM_QUOTED_PRINTABLE; - break; - } - - cur_token = 0; - mailmime_part_parse(text, text_length, &cur_token, - mime_encoding, &decoded, &decoded_length); - - data = Data::data(); - data->takeBytesOwnership(decoded, (unsigned int) decoded_length, decodedPartDeallocator); - return data; - } - case EncodingUUEncode: - { - Data * data; - const char * current_p; - - data = Data::dataWithCapacity((unsigned int) text_length); - - current_p = text; - while (1) { - /* In uuencoded files each data line usually have 45 bytes of decoded data. - Maximum possible length is limited by (0x7f-0x20) bytes. - So 256-bytes buffer is enough. */ - char decoded_buf[256]; - size_t decoded_length; - size_t length; - const char * p; - const char * p1; - const char * p2; - const char * end_line; - - p1 = strchr(current_p, '\n'); - p2 = strchr(current_p, '\r'); - if (p1 == NULL) { - p = p2; - } - else if (p2 == NULL) { - p = p1; - } - else { - if (p1 - current_p < p2 - current_p) { - p = p1; - } - else { - p = p2; - } - } - end_line = p; - if (p != NULL) { - while ((size_t) (p - text) < text_length) { - if ((* p != '\r') && (* p != '\n')) { - break; - } - p ++; - } - } - if (p == NULL) { - length = text_length - (current_p - text); - } - else { - length = end_line - current_p; - } - if (length == 0) { - break; - } - decoded_length = uudecode(current_p, length, decoded_buf, sizeof(decoded_buf)); - if (decoded_length != 0 && decoded_length < length) { - data->appendBytes(decoded_buf, (unsigned int) decoded_length); - } - - if (p == NULL) - break; - - current_p = p; - while ((size_t) (current_p - text) < text_length) { - if ((* current_p != '\r') && (* current_p != '\n')) { - break; - } - current_p ++; - } - } - - return data; - } - } + Data * unused = NULL; + return MCDecodeData(this, encoding, false, &unused); } Data * Data::data() @@ -765,11 +606,14 @@ void Data::importSerializable(HashMap * serializable) ErrorCode Data::writeToFile(String * filename) { FILE * f = fopen(filename->fileSystemRepresentation(), "wb"); + if (f == NULL) { return ErrorFile; } size_t result = fwrite(bytes(), length(), 1, f); - fclose(f); + if (fclose(f) != 0) { + return ErrorFile; + } if (result == 0) { return ErrorFile; } diff --git a/src/core/basetypes/MCData.h b/src/core/basetypes/MCData.h index 11c0d6c2..ef7acda3 100644 --- a/src/core/basetypes/MCData.h +++ b/src/core/basetypes/MCData.h @@ -46,11 +46,11 @@ namespace mailcore { virtual String * stringWithDetectedCharset(String * charset, bool isHTML); virtual String * stringWithCharset(const char * charset); virtual Data * decodedDataUsingEncoding(Encoding encoding); - + virtual String * base64String(); virtual ErrorCode writeToFile(String * filename); - + public: // private virtual String * charsetWithFilteredHTML(bool filterHTML, String * hintCharset = NULL); diff --git a/src/core/basetypes/MCDataDecoderUtils.cpp b/src/core/basetypes/MCDataDecoderUtils.cpp new file mode 100644 index 00000000..4ea739ce --- /dev/null +++ b/src/core/basetypes/MCDataDecoderUtils.cpp @@ -0,0 +1,192 @@ +#include "MCDataDecoderUtils.h" + +#include <libetpan/libetpan.h> + +#include <string.h> +#include <strings.h> + +namespace mailcore { + +static size_t uudecode(const char * text, size_t size, char * dst, size_t dst_buf_size) +{ + unsigned int count = 0; + const char *b = text; /* beg */ + const char *s = b; /* src */ + const char *e = b+size; /* end */ + char *d = dst; + int out = (*s++ & 0x7f) - 0x20; + + /* don't process lines without leading count character */ + if (out < 0) + return size; + + /* dummy check. user must allocate buffer with appropriate length */ + if (dst_buf_size < out) + return size; + + /* don't process begin and end lines */ + if ((strncasecmp((const char *)b, "begin ", 6) == 0) || + (strncasecmp((const char *)b, "end", 3) == 0)) + return size; + + while (s < e && count < out) + { + int v = 0; + int i; + for (i = 0; i < 4; i += 1) { + char c = *s++; + v = v << 6 | ((c - 0x20) & 0x3F); + } + for (i = 2; i >= 0; i -= 1) { + char c = (char) (v & 0xFF); + d[i] = c; + v = v >> 8; + } + d += 3; + count += 3; + } + return count; +} + +static void decodedPartDeallocator(char * decoded, unsigned int decoded_length) { + mailmime_decoded_part_free(decoded); +} + +Data * MCDecodeData(Data * encodedData, Encoding encoding, bool partialContent, Data ** pRemainingData) +{ + const char * text; + size_t text_length; + + text = encodedData->bytes(); + text_length = encodedData->length(); + + * pRemainingData = NULL; + + switch (encoding) { + case Encoding7Bit: + case Encoding8Bit: + case EncodingBinary: + case EncodingOther: + default: + { + return encodedData; + } + case EncodingBase64: + case EncodingQuotedPrintable: + { + char * decoded; + size_t decoded_length; + size_t cur_token; + int mime_encoding; + + switch (encoding) { + default: //disable warning + case EncodingBase64: + mime_encoding = MAILMIME_MECHANISM_BASE64; + break; + case EncodingQuotedPrintable: + mime_encoding = MAILMIME_MECHANISM_QUOTED_PRINTABLE; + break; + } + + cur_token = 0; + if (partialContent) { + mailmime_part_parse_partial(text, text_length, &cur_token, + mime_encoding, &decoded, &decoded_length); + } + else { + mailmime_part_parse(text, text_length, &cur_token, + mime_encoding, &decoded, &decoded_length); + } + + if (cur_token < text_length) { + * pRemainingData = Data::dataWithBytes(text + cur_token, (unsigned int)(text_length - cur_token)); + } + + Data * data = Data::data(); + data->takeBytesOwnership(decoded, (unsigned int) decoded_length, decodedPartDeallocator); + return data; + } + case EncodingUUEncode: + { + Data * data; + const char * current_p; + + data = Data::dataWithCapacity((unsigned int) text_length); + + current_p = text; + while (1) { + /* In uuencoded files each data line usually have 45 bytes of decoded data. + Maximum possible length is limited by (0x7f-0x20) bytes. + So 256-bytes buffer is enough. */ + char decoded_buf[256]; + size_t decoded_length; + size_t length; + const char * p; + const char * p1; + const char * p2; + const char * end_line; + + p1 = strchr(current_p, '\n'); + p2 = strchr(current_p, '\r'); + if (p1 == NULL) { + p = p2; + } + else if (p2 == NULL) { + p = p1; + } + else { + if (p1 - current_p < p2 - current_p) { + p = p1; + } + else { + p = p2; + } + } + end_line = p; + if (partialContent && (p1 == NULL || p2 == NULL) && + ((end_line == NULL) || (end_line - text) == (text_length - 1))) { + // possibly partial content detected + * pRemainingData = Data::dataWithBytes(current_p, (unsigned int)(text_length - (current_p - text))); + break; + } + if (p != NULL) { + while ((size_t) (p - text) < text_length) { + if ((* p != '\r') && (* p != '\n')) { + break; + } + p ++; + } + } + if (p == NULL) { + length = text_length - (current_p - text); + } + else { + length = end_line - current_p; + } + if (length == 0) { + break; + } + decoded_length = uudecode(current_p, length, decoded_buf, sizeof(decoded_buf)); + if (decoded_length != 0 && decoded_length < length) { + data->appendBytes(decoded_buf, (unsigned int) decoded_length); + } + + if (p == NULL) + break; + + current_p = p; + while ((size_t) (current_p - text) < text_length) { + if ((* current_p != '\r') && (* current_p != '\n')) { + break; + } + current_p ++; + } + } + + return data; + } + } +} + +} diff --git a/src/core/basetypes/MCDataDecoderUtils.h b/src/core/basetypes/MCDataDecoderUtils.h new file mode 100644 index 00000000..1481a2b4 --- /dev/null +++ b/src/core/basetypes/MCDataDecoderUtils.h @@ -0,0 +1,25 @@ +// +// MCDataDecoderUtils.h +// mailcore2 +// +// Copyright © 2016 MailCore. All rights reserved. +// + +#ifndef MAILCORE_MCDATADECODERUTILS_H + +#define MAILCORE_MCDATADECODERUTILS_H + +#include <MailCore/MCData.h> +#include <MailCore/MCMessageConstants.h> + +#ifdef __cplusplus + +namespace mailcore { + + Data * MCDecodeData(Data * encodedData, Encoding encoding, bool partialContent, Data ** pRemainingData); + +} + +#endif + +#endif diff --git a/src/core/basetypes/MCDataStreamDecoder.cpp b/src/core/basetypes/MCDataStreamDecoder.cpp new file mode 100644 index 00000000..120cfb65 --- /dev/null +++ b/src/core/basetypes/MCDataStreamDecoder.cpp @@ -0,0 +1,105 @@ +#include "MCDataStreamDecoder.h" + +#include "MCString.h" +#include "MCUtils.h" +#include "MCDataDecoderUtils.h" + +using namespace mailcore; + +DataStreamDecoder::DataStreamDecoder() +{ + mFilename = NULL; + mEncoding = Encoding7Bit; + mRemainingData = NULL; + mFile = NULL; +} + +DataStreamDecoder::~DataStreamDecoder() +{ + MC_SAFE_RELEASE(mRemainingData); + MC_SAFE_RELEASE(mFilename); + if (mFile != NULL) { + fclose(mFile); + mFile = NULL; + } +} + +void DataStreamDecoder::setEncoding(Encoding encoding) +{ + mEncoding = encoding; +} + +void DataStreamDecoder::setFilename(String * filename) +{ + MC_SAFE_REPLACE_COPY(String, mFilename, filename); +} + +ErrorCode DataStreamDecoder::appendData(Data * data) +{ + Data * dataForDecode; + if (mRemainingData && mRemainingData->length()) { + // the data remains from previous append + dataForDecode = (Data *) MC_SAFE_COPY(mRemainingData); + dataForDecode->appendData(data); + } else { + dataForDecode = (Data *) MC_SAFE_RETAIN(data); + } + + Data * remainingData = NULL; + Data * decodedData = MCDecodeData(dataForDecode, mEncoding, true, &remainingData); + + ErrorCode errorCode = appendDecodedData(decodedData); + + if (errorCode == ErrorNone) { + MC_SAFE_REPLACE_RETAIN(Data, mRemainingData, remainingData); + } + + MC_SAFE_RELEASE(dataForDecode); + return errorCode; +} + +ErrorCode DataStreamDecoder::flushData() +{ + if (mRemainingData == NULL || mRemainingData->length() == 0) { + return ErrorNone; + } + + Data * unused = NULL; + Data * decodedData = MCDecodeData(mRemainingData, mEncoding, false, &unused); + + ErrorCode errorCode = appendDecodedData(decodedData); + + if (errorCode == ErrorNone) { + if (mFile != NULL) { + if (fclose(mFile) != 0) { + return ErrorFile; + } + } + + MC_SAFE_RELEASE(mRemainingData); + } + + return errorCode; +} + +ErrorCode DataStreamDecoder::appendDecodedData(Data * decodedData) +{ + if (mFilename == NULL) { + return ErrorFile; + } + + if (mFile == NULL) { + mFile = fopen(mFilename->fileSystemRepresentation(), "wb"); + + if (mFile == NULL) { + return ErrorFile; + } + } + + size_t result = fwrite(decodedData->bytes(), decodedData->length(), 1, mFile); + if (result == 0) { + return ErrorFile; + } + + return ErrorNone; +} diff --git a/src/core/basetypes/MCDataStreamDecoder.h b/src/core/basetypes/MCDataStreamDecoder.h new file mode 100644 index 00000000..9d04f361 --- /dev/null +++ b/src/core/basetypes/MCDataStreamDecoder.h @@ -0,0 +1,51 @@ +// +// DataStreamDecoder.hpp +// mailcore2 +// +// Copyright © 2016 MailCore. All rights reserved. +// + +#ifndef MAILCORE_MCDATASTREAMDECODER_H + +#define MAILCORE_MCDATASTREAMDECODER_H + +#include <stdlib.h> + +#include <MailCore/MCObject.h> +#include <MailCore/MCData.h> +#include <MailCore/MCMessageConstants.h> + +#ifdef __cplusplus + +namespace mailcore { + + class DataStreamDecoder : public Object { + public: + DataStreamDecoder(); + virtual ~DataStreamDecoder(); + + virtual void setEncoding(Encoding encoding); + // output filename + virtual void setFilename(String * filename); + + // when data are received, decode them and add them to the file. + virtual ErrorCode appendData(Data * data); + + // end of data received. + virtual ErrorCode flushData(); + + private: // impl + virtual ErrorCode appendDecodedData(Data * decodedData); + + private: + String * mFilename; + Encoding mEncoding; + Data * mRemainingData; + FILE * mFile; + }; + +} + +#endif + +#endif |