aboutsummaryrefslogtreecommitdiffhomepage
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
parent6dbe79ccf3f085da9a195ee3f9a59cb4449f6505 (diff)
Add possibility of fetching message attachment by chunks and store it to file. (#1438)
-rwxr-xr-xbuild-mac/mailcore2.xcodeproj/project.pbxproj44
-rw-r--r--build-windows/build_headers.list4
-rw-r--r--build-windows/mailcore2/mailcore2/mailcore2.vcxproj6
-rw-r--r--build-windows/mailcore2/mailcore2/mailcore2.vcxproj.filters18
-rw-r--r--src/async/imap/MCAsyncIMAP.h1
-rw-r--r--src/async/imap/MCIMAPAsyncConnection.cpp1
-rw-r--r--src/async/imap/MCIMAPAsyncConnection.h1
-rw-r--r--src/async/imap/MCIMAPAsyncSession.cpp19
-rw-r--r--src/async/imap/MCIMAPAsyncSession.h9
-rw-r--r--src/async/imap/MCIMAPFetchContentToFileOperation.cpp91
-rw-r--r--src/async/imap/MCIMAPFetchContentToFileOperation.h53
-rw-r--r--src/cmake/async.cmake1
-rw-r--r--src/cmake/core.cmake2
-rw-r--r--src/cmake/objc.cmake1
-rw-r--r--src/cmake/public-headers.cmake4
-rw-r--r--src/core/basetypes/MCData.cpp170
-rw-r--r--src/core/basetypes/MCData.h4
-rw-r--r--src/core/basetypes/MCDataDecoderUtils.cpp192
-rw-r--r--src/core/basetypes/MCDataDecoderUtils.h25
-rw-r--r--src/core/basetypes/MCDataStreamDecoder.cpp105
-rw-r--r--src/core/basetypes/MCDataStreamDecoder.h51
-rw-r--r--src/core/imap/MCIMAPSession.cpp162
-rw-r--r--src/core/imap/MCIMAPSession.h13
-rw-r--r--src/core/rfc822/MCAttachment.cpp4
-rw-r--r--src/objc/imap/MCOIMAP.h1
-rw-r--r--src/objc/imap/MCOIMAPFetchContentToFileOperation.h51
-rw-r--r--src/objc/imap/MCOIMAPFetchContentToFileOperation.mm103
-rw-r--r--src/objc/imap/MCOIMAPSession.h32
-rw-r--r--src/objc/imap/MCOIMAPSession.mm16
29 files changed, 1006 insertions, 178 deletions
diff --git a/build-mac/mailcore2.xcodeproj/project.pbxproj b/build-mac/mailcore2.xcodeproj/project.pbxproj
index 3ab90564..5db6ed6b 100755
--- a/build-mac/mailcore2.xcodeproj/project.pbxproj
+++ b/build-mac/mailcore2.xcodeproj/project.pbxproj
@@ -42,6 +42,18 @@
4BE4029217B548D900ECC5E4 /* MCIMAPQuotaOperation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B3C1BE017ABF4BC008BBF4C /* MCIMAPQuotaOperation.h */; };
636F55A01BCFA9A600AA00DB /* MailCore.h in Headers */ = {isa = PBXBuildFile; fileRef = C64EA7A4169F2A3E00778456 /* MailCore.h */; settings = {ATTRIBUTES = (Public, ); }; };
636F55A11BCFA9A600AA00DB /* MailCore.h in Headers */ = {isa = PBXBuildFile; fileRef = C64EA7A4169F2A3E00778456 /* MailCore.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 810DB78D1C68F4E200017B12 /* MCIMAPFetchContentToFileOperation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 810DB78B1C68F4E200017B12 /* MCIMAPFetchContentToFileOperation.cpp */; };
+ 810DB78E1C68F4F000017B12 /* MCIMAPFetchContentToFileOperation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 810DB78B1C68F4E200017B12 /* MCIMAPFetchContentToFileOperation.cpp */; };
+ 810DB7911C68F50600017B12 /* MCOIMAPFetchContentToFileOperation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 810DB7901C68F50600017B12 /* MCOIMAPFetchContentToFileOperation.mm */; };
+ 810DB7921C68F50B00017B12 /* MCOIMAPFetchContentToFileOperation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 810DB7901C68F50600017B12 /* MCOIMAPFetchContentToFileOperation.mm */; };
+ 811320AF1D02388A004B7ECF /* MCDataDecoderUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 811320AE1D02388A004B7ECF /* MCDataDecoderUtils.cpp */; };
+ 811320B01D02388A004B7ECF /* MCDataDecoderUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 811320AE1D02388A004B7ECF /* MCDataDecoderUtils.cpp */; };
+ 81416BDE1CF8BB17000A4299 /* MCDataStreamDecoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 81416BDC1CF8BB17000A4299 /* MCDataStreamDecoder.cpp */; };
+ 81416BDF1CF8BB18000A4299 /* MCDataStreamDecoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 81416BDC1CF8BB17000A4299 /* MCDataStreamDecoder.cpp */; };
+ 817FA5271C69013C006146BD /* MCIMAPFetchContentToFileOperation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 810DB78C1C68F4E200017B12 /* MCIMAPFetchContentToFileOperation.h */; };
+ 817FA5281C69016A006146BD /* MCIMAPFetchContentToFileOperation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 810DB78C1C68F4E200017B12 /* MCIMAPFetchContentToFileOperation.h */; };
+ 817FA5291C69037B006146BD /* MCOIMAPFetchContentToFileOperation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 810DB78F1C68F50600017B12 /* MCOIMAPFetchContentToFileOperation.h */; };
+ 817FA52A1C69038F006146BD /* MCOIMAPFetchContentToFileOperation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 810DB78F1C68F50600017B12 /* MCOIMAPFetchContentToFileOperation.h */; };
8199FBEB19FAEA440040BBC3 /* MCOIMAPFetchParsedContentOperation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8199FBE819FAEA440040BBC3 /* MCOIMAPFetchParsedContentOperation.mm */; };
8199FBEC19FAEA440040BBC3 /* MCOIMAPFetchParsedContentOperation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8199FBE819FAEA440040BBC3 /* MCOIMAPFetchParsedContentOperation.mm */; };
8199FBF119FAF1270040BBC3 /* MCIMAPFetchParsedContentOperation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8199FBEF19FAF1270040BBC3 /* MCIMAPFetchParsedContentOperation.cpp */; };
@@ -902,8 +914,8 @@
C6EFFBCD1833334900CFF656 /* MCOIMAPMultiDisconnectOperation.mm in Sources */ = {isa = PBXBuildFile; fileRef = C6EFFBCB1833334900CFF656 /* MCOIMAPMultiDisconnectOperation.mm */; };
C6F49A8F1C8E96D00087F4B7 /* MCIMAPCheckAccountOperation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA7F716A15A7800778456 /* MCIMAPCheckAccountOperation.h */; };
C6F49A901C8E96D70087F4B7 /* MCIMAPCheckAccountOperation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA7F716A15A7800778456 /* MCIMAPCheckAccountOperation.h */; };
- C6F49A931C8EA1450087F4B7 /* MCOIMAPCheckAccountOperation.mm in Sources */ = {isa = PBXBuildFile; fileRef = C6F49A921C8EA1450087F4B7 /* MCOIMAPCheckAccountOperation.mm */; settings = {ASSET_TAGS = (); }; };
- C6F49A941C8EA1450087F4B7 /* MCOIMAPCheckAccountOperation.mm in Sources */ = {isa = PBXBuildFile; fileRef = C6F49A921C8EA1450087F4B7 /* MCOIMAPCheckAccountOperation.mm */; settings = {ASSET_TAGS = (); }; };
+ C6F49A931C8EA1450087F4B7 /* MCOIMAPCheckAccountOperation.mm in Sources */ = {isa = PBXBuildFile; fileRef = C6F49A921C8EA1450087F4B7 /* MCOIMAPCheckAccountOperation.mm */; };
+ C6F49A941C8EA1450087F4B7 /* MCOIMAPCheckAccountOperation.mm in Sources */ = {isa = PBXBuildFile; fileRef = C6F49A921C8EA1450087F4B7 /* MCOIMAPCheckAccountOperation.mm */; };
C6F5B9E216FEA1E800D9DABD /* MCOIMAPMessage.mm in Sources */ = {isa = PBXBuildFile; fileRef = C6F5B9E116FEA1E800D9DABD /* MCOIMAPMessage.mm */; };
C6F5B9E516FEA27500D9DABD /* MCOIMAPMessagePart.mm in Sources */ = {isa = PBXBuildFile; fileRef = C6F5B9E416FEA27500D9DABD /* MCOIMAPMessagePart.mm */; };
C6F5B9E816FEA28600D9DABD /* MCOIMAPMultipart.mm in Sources */ = {isa = PBXBuildFile; fileRef = C6F5B9E716FEA28600D9DABD /* MCOIMAPMultipart.mm */; };
@@ -1039,6 +1051,8 @@
files = (
F38221A81C7B63E500E00721 /* MCONNTPPostOperation.h in CopyFiles */,
F38221A71C7B638200E00721 /* MCNNTPPostOperation.h in CopyFiles */,
+ 817FA5291C69037B006146BD /* MCOIMAPFetchContentToFileOperation.h in CopyFiles */,
+ 817FA5281C69016A006146BD /* MCIMAPFetchContentToFileOperation.h in CopyFiles */,
C6BEC1AB1B1256C100546519 /* MCHTMLCleaner.h in CopyFiles */,
27E91D601A80D3F4005A3244 /* MCMXRecordResolverOperation.h in CopyFiles */,
27478E861A76475F004AE621 /* MCOAccountValidator.h in CopyFiles */,
@@ -1278,6 +1292,8 @@
files = (
F38221A61C7B62E900E00721 /* MCONNTPPostOperation.h in CopyFiles */,
F38221A51C7B629B00E00721 /* MCNNTPPostOperation.h in CopyFiles */,
+ 817FA52A1C69038F006146BD /* MCOIMAPFetchContentToFileOperation.h in CopyFiles */,
+ 817FA5271C69013C006146BD /* MCIMAPFetchContentToFileOperation.h in CopyFiles */,
C6BEC1AA1B1256BA00546519 /* MCHTMLCleaner.h in CopyFiles */,
276A65D01A7B7E7D008722C2 /* MCMXRecordResolverOperation.h in CopyFiles */,
27478E881A7647AC004AE621 /* MCOAccountValidator.h in CopyFiles */,
@@ -1520,6 +1536,14 @@
4B3C1BDD17ABF307008BBF4C /* MCOIMAPQuotaOperation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MCOIMAPQuotaOperation.mm; sourceTree = "<group>"; };
4B3C1BDF17ABF4BB008BBF4C /* MCIMAPQuotaOperation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCIMAPQuotaOperation.cpp; sourceTree = "<group>"; };
4B3C1BE017ABF4BC008BBF4C /* MCIMAPQuotaOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCIMAPQuotaOperation.h; sourceTree = "<group>"; };
+ 810DB78B1C68F4E200017B12 /* MCIMAPFetchContentToFileOperation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCIMAPFetchContentToFileOperation.cpp; sourceTree = "<group>"; };
+ 810DB78C1C68F4E200017B12 /* MCIMAPFetchContentToFileOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCIMAPFetchContentToFileOperation.h; sourceTree = "<group>"; };
+ 810DB78F1C68F50600017B12 /* MCOIMAPFetchContentToFileOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCOIMAPFetchContentToFileOperation.h; sourceTree = "<group>"; };
+ 810DB7901C68F50600017B12 /* MCOIMAPFetchContentToFileOperation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MCOIMAPFetchContentToFileOperation.mm; sourceTree = "<group>"; };
+ 811320AD1D0235F5004B7ECF /* MCDataDecoderUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MCDataDecoderUtils.h; sourceTree = "<group>"; };
+ 811320AE1D02388A004B7ECF /* MCDataDecoderUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCDataDecoderUtils.cpp; sourceTree = "<group>"; };
+ 81416BDC1CF8BB17000A4299 /* MCDataStreamDecoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCDataStreamDecoder.cpp; sourceTree = "<group>"; };
+ 81416BDD1CF8BB17000A4299 /* MCDataStreamDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCDataStreamDecoder.h; sourceTree = "<group>"; };
8199FBE719FAEA440040BBC3 /* MCOIMAPFetchParsedContentOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCOIMAPFetchParsedContentOperation.h; sourceTree = "<group>"; };
8199FBE819FAEA440040BBC3 /* MCOIMAPFetchParsedContentOperation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MCOIMAPFetchParsedContentOperation.mm; sourceTree = "<group>"; };
8199FBEF19FAF1270040BBC3 /* MCIMAPFetchParsedContentOperation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCIMAPFetchParsedContentOperation.cpp; sourceTree = "<group>"; };
@@ -2594,6 +2618,8 @@
C64EA81916A29ADB00778456 /* MCIMAPFetchMessagesOperation.h */,
C64EA81B16A29DC100778456 /* MCIMAPFetchContentOperation.cpp */,
C64EA81C16A29DC400778456 /* MCIMAPFetchContentOperation.h */,
+ 810DB78B1C68F4E200017B12 /* MCIMAPFetchContentToFileOperation.cpp */,
+ 810DB78C1C68F4E200017B12 /* MCIMAPFetchContentToFileOperation.h */,
8199FBEF19FAF1270040BBC3 /* MCIMAPFetchParsedContentOperation.cpp */,
8199FBF019FAF1270040BBC3 /* MCIMAPFetchParsedContentOperation.h */,
C64EA81E16A29E3D00778456 /* MCIMAPStoreFlagsOperation.cpp */,
@@ -2745,6 +2771,10 @@
C64EA6A9169E847800778456 /* MCData.cpp */,
C64EA6AA169E847800778456 /* MCData.h */,
C6D4FD4219FB7DAA001F7E01 /* MCDataMac.mm */,
+ 811320AE1D02388A004B7ECF /* MCDataDecoderUtils.cpp */,
+ 811320AD1D0235F5004B7ECF /* MCDataDecoderUtils.h */,
+ 81416BDC1CF8BB17000A4299 /* MCDataStreamDecoder.cpp */,
+ 81416BDD1CF8BB17000A4299 /* MCDataStreamDecoder.h */,
C64EA6AB169E847800778456 /* MCHash.cpp */,
C64EA6AC169E847800778456 /* MCHash.h */,
C64EA6AD169E847800778456 /* MCHashMap.cpp */,
@@ -3126,6 +3156,8 @@
C6F61F8317016A200073032E /* MCOIMAPFetchMessagesOperation.mm */,
C6F61F8517016AD60073032E /* MCOIMAPFetchContentOperation.h */,
C6F61F8617016AD60073032E /* MCOIMAPFetchContentOperation.mm */,
+ 810DB78F1C68F50600017B12 /* MCOIMAPFetchContentToFileOperation.h */,
+ 810DB7901C68F50600017B12 /* MCOIMAPFetchContentToFileOperation.mm */,
8199FBE719FAEA440040BBC3 /* MCOIMAPFetchParsedContentOperation.h */,
8199FBE819FAEA440040BBC3 /* MCOIMAPFetchParsedContentOperation.mm */,
C6F61F8817016AE60073032E /* MCOIMAPSearchOperation.h */,
@@ -3542,6 +3574,7 @@
BDCD7CCB1A70771B0001DCC3 /* csrmbcs.cpp in Sources */,
C64EA732169E847800778456 /* MCIMAPSearchExpression.cpp in Sources */,
BDCD7CE11A70771B0001DCC3 /* uinvchar.c in Sources */,
+ 810DB78D1C68F4E200017B12 /* MCIMAPFetchContentToFileOperation.cpp in Sources */,
C64EA734169E847800778456 /* MCIMAPSession.cpp in Sources */,
C68B2AF717797389005E61EF /* MCConnectionLoggerUtils.cpp in Sources */,
C64EA737169E847800778456 /* MCPOPMessageInfo.cpp in Sources */,
@@ -3602,6 +3635,7 @@
BDCD7CD11A70771B0001DCC3 /* csrutf8.cpp in Sources */,
C62C6EEF16A7B67600737497 /* MCPOPAsyncSession.cpp in Sources */,
C62C6EF216A7C6DE00737497 /* MCPOPFetchHeaderOperation.cpp in Sources */,
+ 81416BDE1CF8BB17000A4299 /* MCDataStreamDecoder.cpp in Sources */,
C62C6EF516A7C6EA00737497 /* MCPOPFetchMessageOperation.cpp in Sources */,
C62C6EF816A7C6F500737497 /* MCPOPDeleteMessagesOperation.cpp in Sources */,
C62C6EFB16A7C94000737497 /* MCPOPOperation.cpp in Sources */,
@@ -3644,6 +3678,7 @@
BDCD7CE51A70771B0001DCC3 /* ustring.cpp in Sources */,
C64BB23916EDAA3F000DB34C /* MCOAbstractMessagePart.mm in Sources */,
C64BB23C16EDAAC7000DB34C /* MCOAbstractMultipart.mm in Sources */,
+ 811320AF1D02388A004B7ECF /* MCDataDecoderUtils.cpp in Sources */,
BDCD7CD71A70771B0001DCC3 /* uarrsort.c in Sources */,
8568A41A1C610F6600FF4470 /* MCOIMAPMoveMessagesOperation.mm in Sources */,
C6D4FD4319FB7DAA001F7E01 /* MCDataMac.mm in Sources */,
@@ -3728,6 +3763,7 @@
84D7378F199C02A8005124E5 /* MCONNTPDisconnectOperation.mm in Sources */,
BD7C0F461B545CE2003337DF /* MCZipMac.mm in Sources */,
C6CF62BD175324CE006398B9 /* MCONetService.mm in Sources */,
+ 810DB7911C68F50600017B12 /* MCOIMAPFetchContentToFileOperation.mm in Sources */,
C6EFFBCC1833334900CFF656 /* MCOIMAPMultiDisconnectOperation.mm in Sources */,
C6CF62C6175324F0006398B9 /* MCMailProvider.cpp in Sources */,
C6CF62C8175324F0006398B9 /* MCMailProvidersManager.cpp in Sources */,
@@ -3821,6 +3857,7 @@
BDCD7CCC1A70771B0001DCC3 /* csrmbcs.cpp in Sources */,
C6BA2BB41705F4E6003F0E9E /* MCIMAPPart.cpp in Sources */,
BDCD7CE21A70771B0001DCC3 /* uinvchar.c in Sources */,
+ 810DB78E1C68F4F000017B12 /* MCIMAPFetchContentToFileOperation.cpp in Sources */,
C6BA2BB51705F4E6003F0E9E /* MCIMAPSearchExpression.cpp in Sources */,
C6BA2BB61705F4E6003F0E9E /* MCIMAPSession.cpp in Sources */,
C68B2AF817797389005E61EF /* MCConnectionLoggerUtils.cpp in Sources */,
@@ -3881,6 +3918,7 @@
C6BA2BD51705F4E6003F0E9E /* MCIMAPFolderInfoOperation.cpp in Sources */,
BDCD7CD21A70771B0001DCC3 /* csrutf8.cpp in Sources */,
C6BA2BD61705F4E6003F0E9E /* MCIMAPAsyncConnection.cpp in Sources */,
+ 81416BDF1CF8BB18000A4299 /* MCDataStreamDecoder.cpp in Sources */,
C6BA2BD71705F4E6003F0E9E /* MCPOPAsyncSession.cpp in Sources */,
C6BA2BD81705F4E6003F0E9E /* MCPOPFetchHeaderOperation.cpp in Sources */,
C6BA2BD91705F4E6003F0E9E /* MCPOPFetchMessageOperation.cpp in Sources */,
@@ -3923,6 +3961,7 @@
84D73765199BFFC7005124E5 /* MCONNTPSession.mm in Sources */,
BDCD7CE61A70771B0001DCC3 /* ustring.cpp in Sources */,
C6BA2BF01705F4E6003F0E9E /* MCOAbstractMessage.mm in Sources */,
+ 811320B01D02388A004B7ECF /* MCDataDecoderUtils.cpp in Sources */,
C6BA2BF11705F4E6003F0E9E /* MCOAbstractMessagePart.mm in Sources */,
8568A41B1C610F6600FF4470 /* MCOIMAPMoveMessagesOperation.mm in Sources */,
BDCD7CD81A70771B0001DCC3 /* uarrsort.c in Sources */,
@@ -4007,6 +4046,7 @@
C6CF62BC175324CE006398B9 /* MCOMailProvidersManager.mm in Sources */,
BD7C0F471B545CE2003337DF /* MCZipMac.mm in Sources */,
84D73790199C02A8005124E5 /* MCONNTPDisconnectOperation.mm in Sources */,
+ 810DB7921C68F50B00017B12 /* MCOIMAPFetchContentToFileOperation.mm in Sources */,
C6CF62BE175324CE006398B9 /* MCONetService.mm in Sources */,
C6EFFBCD1833334900CFF656 /* MCOIMAPMultiDisconnectOperation.mm in Sources */,
C6CF62C7175324F0006398B9 /* MCMailProvider.cpp in Sources */,
diff --git a/build-windows/build_headers.list b/build-windows/build_headers.list
index 3d5a92e2..4662e54c 100644
--- a/build-windows/build_headers.list
+++ b/build-windows/build_headers.list
@@ -11,6 +11,8 @@ src\core\basetypes\MCString.h
src\core\basetypes\MCRange.h
src\core\basetypes\MCICUTypes.h
src\core\basetypes\MCData.h
+src\core\basetypes\MCDataDecoderUtils.h
+src\core\basetypes\MCDataStreamDecoder.h
src\core\abstract\MCMessageConstants.h
src\core\basetypes\MCArray.h
src\core\basetypes\MCHashMap.h
@@ -88,6 +90,7 @@ src\async\imap\MCIMAPCopyMessagesOperation.h
src\async\imap\MCIMAPMoveMessagesOperation.h
src\async\imap\MCIMAPFetchMessagesOperation.h
src\async\imap\MCIMAPFetchContentOperation.h
+src\async\imap\MCIMAPFetchContentToFileOperation.h
src\async\imap\MCIMAPFetchParsedContentOperation.h
src\async\imap\MCIMAPIdleOperation.h
src\async\imap\MCIMAPFolderInfo.h
@@ -164,6 +167,7 @@ src\objc\imap\MCOIMAPCopyMessagesOperation.h
src\objc\imap\MCOIMAPMoveMessagesOperation.h
src\objc\imap\MCOIMAPFetchMessagesOperation.h
src\objc\imap\MCOIMAPFetchContentOperation.h
+src\objc\imap\MCOIMAPFetchContentToFileOperation.h
src\objc\imap\MCOIMAPFetchParsedContentOperation.h
src\objc\imap\MCOIMAPSearchOperation.h
src\objc\imap\MCOIMAPIdleOperation.h
diff --git a/build-windows/mailcore2/mailcore2/mailcore2.vcxproj b/build-windows/mailcore2/mailcore2/mailcore2.vcxproj
index 7fd762c2..040d7fe4 100644
--- a/build-windows/mailcore2/mailcore2/mailcore2.vcxproj
+++ b/build-windows/mailcore2/mailcore2/mailcore2.vcxproj
@@ -33,6 +33,7 @@
<ClInclude Include="..\..\..\src\async\imap\MCIMAPDisconnectOperation.h" />
<ClInclude Include="..\..\..\src\async\imap\MCIMAPExpungeOperation.h" />
<ClInclude Include="..\..\..\src\async\imap\MCIMAPFetchContentOperation.h" />
+ <ClInclude Include="..\..\..\src\async\imap\MCIMAPFetchContentToFileOperation.h" />
<ClInclude Include="..\..\..\src\async\imap\MCIMAPFetchFoldersOperation.h" />
<ClInclude Include="..\..\..\src\async\imap\MCIMAPFetchMessagesOperation.h" />
<ClInclude Include="..\..\..\src\async\imap\MCIMAPFetchNamespaceOperation.h" />
@@ -103,6 +104,8 @@
<ClInclude Include="..\..\..\src\core\basetypes\MCConnectionLogger.h" />
<ClInclude Include="..\..\..\src\core\basetypes\MCConnectionLoggerUtils.h" />
<ClInclude Include="..\..\..\src\core\basetypes\MCData.h" />
+ <ClInclude Include="..\..\..\src\core\basetypes\MCDataDecoderUtils.h" />
+ <ClInclude Include="..\..\..\src\core\basetypes\MCDataStreamDecoder.h" />
<ClInclude Include="..\..\..\src\core\basetypes\MCDefines.h" />
<ClInclude Include="..\..\..\src\core\basetypes\MCHash.h" />
<ClInclude Include="..\..\..\src\core\basetypes\MCHashMap.h" />
@@ -196,6 +199,7 @@
<ClCompile Include="..\..\..\src\async\imap\MCIMAPDisconnectOperation.cpp" />
<ClCompile Include="..\..\..\src\async\imap\MCIMAPExpungeOperation.cpp" />
<ClCompile Include="..\..\..\src\async\imap\MCIMAPFetchContentOperation.cpp" />
+ <ClCompile Include="..\..\..\src\async\imap\MCIMAPFetchContentToFileOperation.cpp" />
<ClCompile Include="..\..\..\src\async\imap\MCIMAPFetchFoldersOperation.cpp" />
<ClCompile Include="..\..\..\src\async\imap\MCIMAPFetchMessagesOperation.cpp" />
<ClCompile Include="..\..\..\src\async\imap\MCIMAPFetchNamespaceOperation.cpp" />
@@ -255,6 +259,8 @@
<ClCompile Include="..\..\..\src\core\basetypes\MCBase64.c" />
<ClCompile Include="..\..\..\src\core\basetypes\MCConnectionLoggerUtils.cpp" />
<ClCompile Include="..\..\..\src\core\basetypes\MCData.cpp" />
+ <ClCompile Include="..\..\..\src\core\basetypes\MCDataDecoderUtils.cpp" />
+ <ClCompile Include="..\..\..\src\core\basetypes\MCDataStreamDecoder.cpp" />
<ClCompile Include="..\..\..\src\core\basetypes\MCHash.cpp" />
<ClCompile Include="..\..\..\src\core\basetypes\MCHashMap.cpp" />
<ClCompile Include="..\..\..\src\core\basetypes\MCHTMLCleaner.cpp" />
diff --git a/build-windows/mailcore2/mailcore2/mailcore2.vcxproj.filters b/build-windows/mailcore2/mailcore2/mailcore2.vcxproj.filters
index 77e0f971..8354e6bd 100644
--- a/build-windows/mailcore2/mailcore2/mailcore2.vcxproj.filters
+++ b/build-windows/mailcore2/mailcore2/mailcore2.vcxproj.filters
@@ -120,6 +120,12 @@
<ClInclude Include="..\..\..\src\core\basetypes\MCData.h">
<Filter>Source Files\core\basetypes</Filter>
</ClInclude>
+ <ClInclude Include="..\..\..\src\core\basetypes\MCDataDecoderUtils.h">
+ <Filter>Source Files\core\basetypes</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\core\basetypes\MCDataStreamDecoder.h">
+ <Filter>Source Files\core\basetypes</Filter>
+ </ClInclude>
<ClInclude Include="..\..\..\src\core\basetypes\MCDefines.h">
<Filter>Source Files\core\basetypes</Filter>
</ClInclude>
@@ -393,6 +399,9 @@
<ClInclude Include="..\..\..\src\async\imap\MCIMAPFetchContentOperation.h">
<Filter>Source Files\async\imap</Filter>
</ClInclude>
+ <ClInclude Include="..\..\..\src\async\imap\MCIMAPFetchContentToFileOperation.h">
+ <Filter>Source Files\async\imap</Filter>
+ </ClInclude>
<ClInclude Include="..\..\..\src\async\imap\MCIMAPFetchFoldersOperation.h">
<Filter>Source Files\async\imap</Filter>
</ClInclude>
@@ -593,6 +602,12 @@
<ClCompile Include="..\..\..\src\core\basetypes\MCData.cpp">
<Filter>Source Files\core\basetypes</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\src\core\basetypes\MCDataDecoderUtils.cpp">
+ <Filter>Source Files\core\basetypes</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\core\basetypes\MCDataStreamDecoder.cpp">
+ <Filter>Source Files\core\basetypes</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\src\core\basetypes\MCHash.cpp">
<Filter>Source Files\core\basetypes</Filter>
</ClCompile>
@@ -806,6 +821,9 @@
<ClCompile Include="..\..\..\src\async\imap\MCIMAPFetchContentOperation.cpp">
<Filter>Source Files\async\imap</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\src\async\imap\MCIMAPFetchContentToFileOperation.cpp">
+ <Filter>Source Files\async\imap</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\src\async\imap\MCIMAPFetchFoldersOperation.cpp">
<Filter>Source Files\async\imap</Filter>
</ClCompile>
diff --git a/src/async/imap/MCAsyncIMAP.h b/src/async/imap/MCAsyncIMAP.h
index e6d6d367..effa0947 100644
--- a/src/async/imap/MCAsyncIMAP.h
+++ b/src/async/imap/MCAsyncIMAP.h
@@ -18,6 +18,7 @@
#include <MailCore/MCIMAPMoveMessagesOperation.h>
#include <MailCore/MCIMAPFetchMessagesOperation.h>
#include <MailCore/MCIMAPFetchContentOperation.h>
+#include <MailCore/MCIMAPFetchContentToFileOperation.h>
#include <MailCore/MCIMAPFetchParsedContentOperation.h>
#include <MailCore/MCIMAPIdleOperation.h>
#include <MailCore/MCIMAPFolderInfo.h>
diff --git a/src/async/imap/MCIMAPAsyncConnection.cpp b/src/async/imap/MCIMAPAsyncConnection.cpp
index ff12c881..4ae633ec 100644
--- a/src/async/imap/MCIMAPAsyncConnection.cpp
+++ b/src/async/imap/MCIMAPAsyncConnection.cpp
@@ -21,6 +21,7 @@
#include "MCIMAPCopyMessagesOperation.h"
#include "MCIMAPFetchMessagesOperation.h"
#include "MCIMAPFetchContentOperation.h"
+#include "MCIMAPFetchContentToFileOperation.h"
#include "MCIMAPFetchParsedContentOperation.h"
#include "MCIMAPStoreFlagsOperation.h"
#include "MCIMAPStoreLabelsOperation.h"
diff --git a/src/async/imap/MCIMAPAsyncConnection.h b/src/async/imap/MCIMAPAsyncConnection.h
index 40b11b90..c665b26d 100644
--- a/src/async/imap/MCIMAPAsyncConnection.h
+++ b/src/async/imap/MCIMAPAsyncConnection.h
@@ -15,6 +15,7 @@ namespace mailcore {
class IMAPCopyMessagesOperation;
class IMAPFetchMessagesOperation;
class IMAPFetchContentOperation;
+ class IMAPFetchContentToFileOperation;
class IMAPFetchParsedContentOperation;
class IMAPIdleOperation;
class IMAPFolderInfoOperation;
diff --git a/src/async/imap/MCIMAPAsyncSession.cpp b/src/async/imap/MCIMAPAsyncSession.cpp
index 5c599558..58dc0dbb 100644
--- a/src/async/imap/MCIMAPAsyncSession.cpp
+++ b/src/async/imap/MCIMAPAsyncSession.cpp
@@ -29,6 +29,7 @@
#include "MCIMAPMoveMessagesOperation.h"
#include "MCIMAPFetchMessagesOperation.h"
#include "MCIMAPFetchContentOperation.h"
+#include "MCIMAPFetchContentToFileOperation.h"
#include "MCIMAPFetchParsedContentOperation.h"
#include "MCIMAPStoreFlagsOperation.h"
#include "MCIMAPStoreLabelsOperation.h"
@@ -588,6 +589,24 @@ IMAPFetchContentOperation * IMAPAsyncSession::fetchMessageAttachmentByUIDOperati
return op;
}
+IMAPFetchContentToFileOperation * IMAPAsyncSession::fetchMessageAttachmentToFileByUIDOperation(
+ String * folder, uint32_t uid, String * partID,
+ Encoding encoding,
+ String * filename,
+ bool urgent)
+{
+ IMAPFetchContentToFileOperation * op = new IMAPFetchContentToFileOperation();
+ op->setMainSession(this);
+ op->setFolder(folder);
+ op->setUid(uid);
+ op->setPartID(partID);
+ op->setEncoding(encoding);
+ op->setFilename(filename);
+ op->setUrgent(urgent);
+ op->autorelease();
+ return op;
+}
+
IMAPFetchContentOperation * IMAPAsyncSession::fetchMessageByNumberOperation(String * folder, uint32_t number, bool urgent)
{
IMAPFetchContentOperation * op = new IMAPFetchContentOperation();
diff --git a/src/async/imap/MCIMAPAsyncSession.h b/src/async/imap/MCIMAPAsyncSession.h
index 0230deda..05437207 100644
--- a/src/async/imap/MCIMAPAsyncSession.h
+++ b/src/async/imap/MCIMAPAsyncSession.h
@@ -24,6 +24,7 @@ namespace mailcore {
class IMAPMoveMessagesOperation;
class IMAPFetchMessagesOperation;
class IMAPFetchContentOperation;
+ class IMAPFetchContentToFileOperation;
class IMAPFetchParsedContentOperation;
class IMAPIdleOperation;
class IMAPFolderInfoOperation;
@@ -142,7 +143,13 @@ namespace mailcore {
virtual IMAPFetchContentOperation * fetchMessageByUIDOperation(String * folder, uint32_t uid, bool urgent = false);
virtual IMAPFetchContentOperation * fetchMessageAttachmentByUIDOperation(String * folder, uint32_t uid, String * partID,
Encoding encoding, bool urgent = false);
-
+
+ virtual IMAPFetchContentToFileOperation * fetchMessageAttachmentToFileByUIDOperation(
+ String * folder, uint32_t uid, String * partID,
+ Encoding encoding,
+ String * filename,
+ bool urgent = false);
+
virtual IMAPFetchContentOperation * fetchMessageByNumberOperation(String * folder, uint32_t number, bool urgent = false);
virtual IMAPCustomCommandOperation * customCommand(String *command, bool urgent);
virtual IMAPFetchContentOperation * fetchMessageAttachmentByNumberOperation(String * folder, uint32_t number, String * partID,
diff --git a/src/async/imap/MCIMAPFetchContentToFileOperation.cpp b/src/async/imap/MCIMAPFetchContentToFileOperation.cpp
new file mode 100644
index 00000000..82a1fa23
--- /dev/null
+++ b/src/async/imap/MCIMAPFetchContentToFileOperation.cpp
@@ -0,0 +1,91 @@
+//
+// IMAPFetchContentToFileOperation.cpp
+// mailcore2
+//
+// Created by Dmitry Isaikin on 2/08/16.
+// Copyright (c) 2016 MailCore. All rights reserved.
+//
+
+#include "MCIMAPFetchContentToFileOperation.h"
+
+#include "MCIMAPSession.h"
+#include "MCIMAPAsyncConnection.h"
+
+using namespace mailcore;
+
+IMAPFetchContentToFileOperation::IMAPFetchContentToFileOperation()
+{
+ mUid = 0;
+ mPartID = NULL;
+ mEncoding = Encoding7Bit;
+ mFilename = NULL;
+ mLoadingByChunksEnabled = true;
+ mChunksSize = 2*1024*1024;
+ mEstimatedSize = 0;
+}
+
+IMAPFetchContentToFileOperation::~IMAPFetchContentToFileOperation()
+{
+ MC_SAFE_RELEASE(mPartID);
+ MC_SAFE_RELEASE(mFilename);
+}
+
+void IMAPFetchContentToFileOperation::setUid(uint32_t uid)
+{
+ mUid = uid;
+}
+
+void IMAPFetchContentToFileOperation::setPartID(String * partID)
+{
+ MC_SAFE_REPLACE_COPY(String, mPartID, partID);
+}
+
+void IMAPFetchContentToFileOperation::setEncoding(Encoding encoding)
+{
+ mEncoding = encoding;
+}
+
+void IMAPFetchContentToFileOperation::setFilename(String * filename)
+{
+ MC_SAFE_REPLACE_COPY(String, mFilename, filename);
+}
+
+void IMAPFetchContentToFileOperation::setLoadingByChunksEnabled(bool loadingByChunksEnabled)
+{
+ mLoadingByChunksEnabled = loadingByChunksEnabled;
+}
+
+bool IMAPFetchContentToFileOperation::isLoadingByChunksEnabled()
+{
+ return mLoadingByChunksEnabled;
+}
+
+void IMAPFetchContentToFileOperation::setChunksSize(uint32_t chunksSize)
+{
+ mChunksSize = chunksSize;
+}
+
+uint32_t IMAPFetchContentToFileOperation::chunksSize()
+{
+ return mChunksSize;
+}
+
+void IMAPFetchContentToFileOperation::setEstimatedSize(uint32_t estimatedSize)
+{
+ mEstimatedSize = estimatedSize;
+}
+
+uint32_t IMAPFetchContentToFileOperation::estimatedSize()
+{
+ return mEstimatedSize;
+}
+
+void IMAPFetchContentToFileOperation::main()
+{
+ ErrorCode error = ErrorNone;
+ session()->session()->fetchMessageAttachmentToFileByUID(folder(), mUid, mPartID,
+ mEstimatedSize, mEncoding,
+ mFilename, mChunksSize,
+ this, &error);
+ setError(error);
+}
diff --git a/src/async/imap/MCIMAPFetchContentToFileOperation.h b/src/async/imap/MCIMAPFetchContentToFileOperation.h
new file mode 100644
index 00000000..35d7026f
--- /dev/null
+++ b/src/async/imap/MCIMAPFetchContentToFileOperation.h
@@ -0,0 +1,53 @@
+//
+// IMAPFetchContentToFileOperation.h
+// mailcore2
+//
+// Created by Dmitry Isaikin on 2/08/16.
+// Copyright (c) 2016 MailCore. All rights reserved.
+//
+
+#ifndef MAILCORE_IMAPFETCHCONTENTTOFILEOPERATION_H
+
+#define MAILCORE_IMAPFETCHCONTENTTOFILEOPERATION_H
+
+#include <MailCore/MCIMAPOperation.h>
+
+#ifdef __cplusplus
+
+namespace mailcore {
+
+ class MAILCORE_EXPORT IMAPFetchContentToFileOperation : public IMAPOperation {
+ public:
+ IMAPFetchContentToFileOperation();
+ virtual ~IMAPFetchContentToFileOperation();
+
+ virtual void setUid(uint32_t uid);
+ virtual void setPartID(String * partID);
+ virtual void setEncoding(Encoding encoding);
+ virtual void setFilename(String * filename);
+
+ virtual void setLoadingByChunksEnabled(bool loadingByChunksEnabled);
+ virtual bool isLoadingByChunksEnabled();
+ virtual void setChunksSize(uint32_t chunksSize);
+ virtual uint32_t chunksSize();
+ virtual void setEstimatedSize(uint32_t estimatedSize);
+ virtual uint32_t estimatedSize();
+
+ public: // subclass behavior
+ virtual void main();
+
+ private:
+ uint32_t mUid;
+ String * mPartID;
+ Encoding mEncoding;
+ String * mFilename;
+ bool mLoadingByChunksEnabled;
+ uint32_t mChunksSize;
+ uint32_t mEstimatedSize;
+ };
+
+}
+
+#endif
+
+#endif
diff --git a/src/cmake/async.cmake b/src/cmake/async.cmake
index 1c213a33..b71068fd 100644
--- a/src/cmake/async.cmake
+++ b/src/cmake/async.cmake
@@ -14,6 +14,7 @@ set(async_imap_files
async/imap/MCIMAPDisconnectOperation.cpp
async/imap/MCIMAPExpungeOperation.cpp
async/imap/MCIMAPFetchContentOperation.cpp
+ async/imap/MCIMAPFetchContentToFileOperation.cpp
async/imap/MCIMAPFetchParsedContentOperation.cpp
async/imap/MCIMAPFetchFoldersOperation.cpp
async/imap/MCIMAPFetchMessagesOperation.cpp
diff --git a/src/cmake/core.cmake b/src/cmake/core.cmake
index 963b02ce..63a041fc 100644
--- a/src/cmake/core.cmake
+++ b/src/cmake/core.cmake
@@ -43,6 +43,8 @@ set(basetypes_files
core/basetypes/MCBase64.c
core/basetypes/MCConnectionLoggerUtils.cpp
core/basetypes/MCData.cpp
+ core/basetypes/MCDataDecoderUtils.cpp
+ core/basetypes/MCDataStreamDecoder.cpp
core/basetypes/MCHash.cpp
core/basetypes/MCHashMap.cpp
core/basetypes/MCHTMLCleaner.cpp
diff --git a/src/cmake/objc.cmake b/src/cmake/objc.cmake
index f4e10b28..7b272111 100644
--- a/src/cmake/objc.cmake
+++ b/src/cmake/objc.cmake
@@ -17,6 +17,7 @@ set(objc_imap_files
objc/imap/MCOIMAPCopyMessagesOperation.mm
objc/imap/MCOIMAPMoveMessagesOperation.mm
objc/imap/MCOIMAPFetchContentOperation.mm
+ objc/imap/MCOIMAPFetchContentToFileOperation.mm
objc/imap/MCOIMAPFetchParsedContentOperation.mm
objc/imap/MCOIMAPFetchFoldersOperation.mm
objc/imap/MCOIMAPFetchMessagesOperation.mm
diff --git a/src/cmake/public-headers.cmake b/src/cmake/public-headers.cmake
index a6bd7f93..2907f9cc 100644
--- a/src/cmake/public-headers.cmake
+++ b/src/cmake/public-headers.cmake
@@ -12,6 +12,8 @@ core/basetypes/MCString.h
core/basetypes/MCRange.h
core/basetypes/MCICUTypes.h
core/basetypes/MCData.h
+core/basetypes/MCDataDecoderUtils.h
+core/basetypes/MCDataStreamDecoder.h
core/abstract/MCMessageConstants.h
core/basetypes/MCArray.h
core/basetypes/MCHashMap.h
@@ -89,6 +91,7 @@ async/imap/MCIMAPCopyMessagesOperation.h
async/imap/MCIMAPMoveMessagesOperation.h
async/imap/MCIMAPFetchMessagesOperation.h
async/imap/MCIMAPFetchContentOperation.h
+async/imap/MCIMAPFetchContentToFileOperation.h
async/imap/MCIMAPFetchParsedContentOperation.h
async/imap/MCIMAPIdleOperation.h
async/imap/MCIMAPFolderInfo.h
@@ -167,6 +170,7 @@ objc/imap/MCOIMAPCopyMessagesOperation.h
objc/imap/MCOIMAPMoveMessagesOperation.h
objc/imap/MCOIMAPFetchMessagesOperation.h
objc/imap/MCOIMAPFetchContentOperation.h
+objc/imap/MCOIMAPFetchContentToFileOperation.h
objc/imap/MCOIMAPFetchParsedContentOperation.h
objc/imap/MCOIMAPSearchOperation.h
objc/imap/MCOIMAPIdleOperation.h
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
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
diff --git a/src/core/rfc822/MCAttachment.cpp b/src/core/rfc822/MCAttachment.cpp
index e6ebc9c9..0881c9a8 100644
--- a/src/core/rfc822/MCAttachment.cpp
+++ b/src/core/rfc822/MCAttachment.cpp
@@ -548,12 +548,12 @@ Attachment * Attachment::attachmentWithSingleMIME(struct mailmime * mime)
mailmime_single_fields_init(&single_fields, mime->mm_mime_fields, mime->mm_content_type);
encoding = encodingForMIMEEncoding(single_fields.fld_encoding, data->dt_encoding);
-
+
Data * mimeData;
mimeData = Data::dataWithBytes(bytes, (unsigned int) length);
mimeData = mimeData->decodedDataUsingEncoding(encoding);
result->setData(mimeData);
-
+
str = get_content_type_str(mime->mm_content_type);
result->setMimeType(String::stringWithUTF8Characters(str));
free(str);
diff --git a/src/objc/imap/MCOIMAP.h b/src/objc/imap/MCOIMAP.h
index 11cbc2ae..4de8f18e 100644
--- a/src/objc/imap/MCOIMAP.h
+++ b/src/objc/imap/MCOIMAP.h
@@ -30,6 +30,7 @@
#import <MailCore/MCOIMAPMoveMessagesOperation.h>
#import <MailCore/MCOIMAPFetchMessagesOperation.h>
#import <MailCore/MCOIMAPFetchContentOperation.h>
+#import <MailCore/MCOIMAPFetchContentToFileOperation.h>
#import <MailCore/MCOIMAPFetchParsedContentOperation.h>
#import <MailCore/MCOIMAPSearchOperation.h>
#import <MailCore/MCOIMAPIdleOperation.h>
diff --git a/src/objc/imap/MCOIMAPFetchContentToFileOperation.h b/src/objc/imap/MCOIMAPFetchContentToFileOperation.h
new file mode 100644
index 00000000..4d06e94d
--- /dev/null
+++ b/src/objc/imap/MCOIMAPFetchContentToFileOperation.h
@@ -0,0 +1,51 @@
+//
+// MCOIMAPFetchContentToFileOperation.h
+// mailcore2
+//
+// Created by Dmitry Isaikin on 2/08/16.
+// Copyright (c) 2016 MailCore. All rights reserved.
+//
+
+#ifndef MAILCORE_MCOIMAPFETCHCONTENTTOFILEOPERATION_H
+
+#define MAILCORE_MCOIMAPFETCHCONTENTTOFILEOPERATION_H
+
+/**
+ This class implements an operation to fetch the content of a message to the file.
+ It can be a part or a full message.
+*/
+
+#import <MailCore/MCOIMAPBaseOperation.h>
+#import <MailCore/MCOConstants.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MCOIMAPFetchContentToFileOperation : MCOIMAPBaseOperation
+
+/**
+ This block will be called as bytes are received from the network
+*/
+@property (nonatomic, copy, nullable) MCOIMAPBaseOperationProgressBlock progress;
+
+@property (nonatomic, assign, getter=isLoadingByChunksEnabled) BOOL loadingByChunksEnabled;
+@property (nonatomic, assign) uint32_t chunksSize;
+@property (nonatomic, assign) uint32_t estimatedSize;
+
+/**
+ Starts the asynchronous fetch operation.
+
+ @param completionBlock Called when the operation is finished.
+
+ - On success `error` will be nil
+
+ - On failure, `error` will be set with `MCOErrorDomain` as domain and an
+ error code available in `MCOConstants.h`
+*/
+
+- (void) start:(void (^)(NSError * __nullable error))completionBlock;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif
diff --git a/src/objc/imap/MCOIMAPFetchContentToFileOperation.mm b/src/objc/imap/MCOIMAPFetchContentToFileOperation.mm
new file mode 100644
index 00000000..4f2bbfcf
--- /dev/null
+++ b/src/objc/imap/MCOIMAPFetchContentToFileOperation.mm
@@ -0,0 +1,103 @@
+//
+// MCOIMAPFetchContentToFileOperation.mm
+// mailcore2
+//
+// Created by Dmitry Isaikin on 2/08/16.
+// Copyright (c) 2016 MailCore. All rights reserved.
+//
+
+#import "MCOIMAPFetchContentToFileOperation.h"
+
+#include "MCAsyncIMAP.h"
+
+#import "MCOOperation+Private.h"
+#import "MCOUtils.h"
+
+typedef void (^CompletionType)(NSError *error);
+
+@implementation MCOIMAPFetchContentToFileOperation {
+ CompletionType _completionBlock;
+ MCOIMAPBaseOperationProgressBlock _progress;
+}
+
+@synthesize progress = _progress;
+
+#define nativeType mailcore::IMAPFetchContentToFileOperation
+
++ (void) load
+{
+ MCORegisterClass(self, &typeid(nativeType));
+}
+
++ (NSObject *) mco_objectWithMCObject:(mailcore::Object *)object
+{
+ nativeType * op = (nativeType *) object;
+ return [[[self alloc] initWithMCOperation:op] autorelease];
+}
+
+- (void)setLoadingByChunksEnabled:(BOOL)loadingByChunksEnabled {
+ MCO_NATIVE_INSTANCE->setLoadingByChunksEnabled(loadingByChunksEnabled);
+}
+
+- (BOOL)isLoadingByChunksEnabled {
+ return MCO_NATIVE_INSTANCE->isLoadingByChunksEnabled();
+}
+
+- (void)setChunksSize:(uint32_t)chunksSize {
+ MCO_NATIVE_INSTANCE->setChunksSize(chunksSize);
+}
+
+- (uint32_t)chunksSize {
+ return MCO_NATIVE_INSTANCE->chunksSize();
+}
+
+- (void)setEstimatedSize:(uint32_t)estimatedSize {
+ MCO_NATIVE_INSTANCE->setEstimatedSize(estimatedSize);
+}
+
+- (uint32_t)estimatedSize {
+ return MCO_NATIVE_INSTANCE->estimatedSize();
+}
+
+- (void) dealloc
+{
+ [_progress release];
+ [_completionBlock release];
+ [super dealloc];
+}
+
+- (void) start:(void (^)(NSError *error))completionBlock {
+ _completionBlock = [completionBlock copy];
+ [self start];
+}
+
+- (void) cancel
+{
+ [_completionBlock release];
+ _completionBlock = nil;
+ [super cancel];
+}
+
+- (void) operationCompleted
+{
+ if (_completionBlock == NULL)
+ return;
+
+ nativeType *op = MCO_NATIVE_INSTANCE;
+ if (op->error() == mailcore::ErrorNone) {
+ _completionBlock(nil);
+ } else {
+ _completionBlock([NSError mco_errorWithErrorCode:op->error()]);
+ }
+ [_completionBlock release];
+ _completionBlock = nil;
+}
+
+- (void) bodyProgress:(unsigned int)current maximum:(unsigned int)maximum
+{
+ if (_progress != NULL) {
+ _progress(current, maximum);
+ }
+}
+
+@end
diff --git a/src/objc/imap/MCOIMAPSession.h b/src/objc/imap/MCOIMAPSession.h
index 7674e9db..12a1e651 100644
--- a/src/objc/imap/MCOIMAPSession.h
+++ b/src/objc/imap/MCOIMAPSession.h
@@ -24,6 +24,7 @@
@class MCOIndexSet;
@class MCOIMAPFetchMessagesOperation;
@class MCOIMAPFetchContentOperation;
+@class MCOIMAPFetchContentToFileOperation;
@class MCOIMAPFetchParsedContentOperation;
@class MCOIMAPSearchOperation;
@class MCOIMAPIdleOperation;
@@ -848,6 +849,37 @@ vanishedMessages will be set only for servers that support QRESYNC. See [RFC5162
partID:(NSString *)partID
encoding:(MCOEncoding)encoding;
+/**
+ Returns an operation to fetch an attachment to a file.
+ @param urgent is set to YES, an additional connection to the same folder might be opened to fetch the content.
+ Operation will be perform in a memory efficient manner.
+
+ MCOIMAPFetchContentToFileOperation * op = [session fetchMessageAttachmentToFileOperationWithFolder:@"INBOX"
+ uid:456
+ partID:@"1.2"
+ encoding:MCOEncodingBase64
+ filename:filename
+ urgent:YES];
+
+ // Optionally, explicitly enable chunked mode
+ [op setLoadingByChunksEnabled:YES];
+ [op setChunksSize:1024*1024];
+ // need in chunked mode for correct progress indication
+ [op setEstimatedSize:sizeOfAttachFromBodystructure];
+
+ [op start:^(NSError * __nullable error) {
+ ...
+ }];
+
+ */
+- (MCOIMAPFetchContentToFileOperation *) fetchMessageAttachmentToFileOperationWithFolder:(NSString *)folder
+ uid:(uint32_t)uid
+ partID:(NSString *)partID
+ encoding:(MCOEncoding)encoding
+ filename:(NSString *)filename
+ urgent:(BOOL)urgent;
+
+
/** @name General IMAP Actions */
/**
diff --git a/src/objc/imap/MCOIMAPSession.mm b/src/objc/imap/MCOIMAPSession.mm
index 2eba5cc0..94a3020b 100644
--- a/src/objc/imap/MCOIMAPSession.mm
+++ b/src/objc/imap/MCOIMAPSession.mm
@@ -498,6 +498,22 @@ MCO_OBJC_SYNTHESIZE_SCALAR(dispatch_queue_t, dispatch_queue_t, setDispatchQueue,
return [self fetchMessageAttachmentOperationWithFolder:folder number:number partID:partID encoding:encoding urgent:NO];
}
+- (MCOIMAPFetchContentToFileOperation *) fetchMessageAttachmentToFileOperationWithFolder:(NSString *)folder
+ uid:(uint32_t)uid
+ partID:(NSString *)partID
+ encoding:(MCOEncoding)encoding
+ filename:(NSString *)filename
+ urgent:(BOOL)urgent
+{
+ IMAPFetchContentToFileOperation * coreOp = MCO_NATIVE_INSTANCE->fetchMessageAttachmentToFileByUIDOperation([folder mco_mcString],
+ uid,
+ [partID mco_mcString],
+ (Encoding) encoding,
+ [filename mco_mcString],
+ urgent);
+ return MCO_TO_OBJC_OP(coreOp);
+}
+
- (MCOIMAPOperation *) storeFlagsOperationWithFolder:(NSString *)folder
uids:(MCOIndexSet *)uids
kind:(MCOIMAPStoreFlagsRequestKind)kind