diff options
34 files changed, 1571 insertions, 15 deletions
diff --git a/build-mac/mailcore2.xcodeproj/project.pbxproj b/build-mac/mailcore2.xcodeproj/project.pbxproj index 9c797b14..e345b82d 100644 --- a/build-mac/mailcore2.xcodeproj/project.pbxproj +++ b/build-mac/mailcore2.xcodeproj/project.pbxproj @@ -47,6 +47,17 @@ C62C6F0716A7E7CC00737497 /* MCPOPFetchMessagesOperation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C62C6F0516A7E54400737497 /* MCPOPFetchMessagesOperation.h */; }; C62C6F0A16A8F58000737497 /* MCIMAPAsyncSession.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C62C6F0816A8F57000737497 /* MCIMAPAsyncSession.cpp */; }; C62C6F0B16A936CA00737497 /* MCIMAPAsyncSession.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C62C6F0916A8F57700737497 /* MCIMAPAsyncSession.h */; }; + C63CD67F16BDCDD400DB18F1 /* MCAddressDisplay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C63CD67716BDCDD400DB18F1 /* MCAddressDisplay.cpp */; }; + C63CD68016BDCDD400DB18F1 /* MCDateFormatter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C63CD67916BDCDD400DB18F1 /* MCDateFormatter.cpp */; }; + C63CD68116BDCDD400DB18F1 /* MCHTMLRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C63CD67B16BDCDD400DB18F1 /* MCHTMLRenderer.cpp */; }; + C63CD68216BDCDD400DB18F1 /* MCSizeFormatter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C63CD67D16BDCDD400DB18F1 /* MCSizeFormatter.cpp */; }; + C63CD68616BE148B00DB18F1 /* MCHTMLRendererCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C63CD68416BE148B00DB18F1 /* MCHTMLRendererCallback.cpp */; }; + C63CD68816BE1BBF00DB18F1 /* MCAddressDisplay.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C63CD67816BDCDD400DB18F1 /* MCAddressDisplay.h */; }; + C63CD68916BE1BC100DB18F1 /* MCDateFormatter.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C63CD67A16BDCDD400DB18F1 /* MCDateFormatter.h */; }; + C63CD68A16BE1BC400DB18F1 /* MCSizeFormatter.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C63CD67E16BDCDD400DB18F1 /* MCSizeFormatter.h */; }; + C63CD68B16BE1BC600DB18F1 /* MCHTMLRenderer.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C63CD67C16BDCDD400DB18F1 /* MCHTMLRenderer.h */; }; + C63CD68C16BE1BC800DB18F1 /* MCHTMLRendererCallback.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C63CD68516BE148B00DB18F1 /* MCHTMLRendererCallback.h */; }; + C63CD68D16BE1BCA00DB18F1 /* MCRenderer.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C63CD68716BE1AB600DB18F1 /* MCRenderer.h */; }; C64EA6F4169E847800778456 /* MCAbstractMessage.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA694169E847800778456 /* MCAbstractMessage.cc */; }; C64EA6F6169E847800778456 /* MCAbstractMessagePart.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA696169E847800778456 /* MCAbstractMessagePart.cc */; }; C64EA6F8169E847800778456 /* MCAbstractMultipart.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA698169E847800778456 /* MCAbstractMultipart.cc */; }; @@ -174,14 +185,14 @@ C6D42C2A16AE0507002BB4F9 /* NSData+MCO.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6D42C1916AE03D6002BB4F9 /* NSData+MCO.h */; }; C6D42C2C16AE0509002BB4F9 /* NSString+MCO.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6D42C1B16AE03D6002BB4F9 /* NSString+MCO.h */; }; C6EB30DE16B5B8050091F4F1 /* MCObjC.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6EB30DC16B5B7770091F4F1 /* MCObjC.h */; }; - F87F190C16BB62B00012652F /* MCOFetchFoldersOperation.mm in Sources */ = {isa = PBXBuildFile; fileRef = F87F190B16BB62B00012652F /* MCOFetchFoldersOperation.mm */; }; - F8EA941716BB1C9D0011AC6F /* MCOIMAPSession.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = F8EA941416BAED6E0011AC6F /* MCOIMAPSession.h */; }; C6EB30F716B8C9480091F4F1 /* NSDictionary+MCO.mm in Sources */ = {isa = PBXBuildFile; fileRef = C6EB30F616B8C9480091F4F1 /* NSDictionary+MCO.mm */; }; C6EB30F816B8DED30091F4F1 /* NSDictionary+MCO.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6EB30F516B8C9480091F4F1 /* NSDictionary+MCO.h */; }; C6EB30FE16B8E50F0091F4F1 /* NSArray+MCO.mm in Sources */ = {isa = PBXBuildFile; fileRef = C6EB30FC16B8E50F0091F4F1 /* NSArray+MCO.mm */; }; C6EB310116B8E6E60091F4F1 /* NSObject+MCO.mm in Sources */ = {isa = PBXBuildFile; fileRef = C6EB310016B8E6E50091F4F1 /* NSObject+MCO.mm */; }; C6EB310216B8E7D60091F4F1 /* NSObject+MCO.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6EB30FF16B8E6E50091F4F1 /* NSObject+MCO.h */; }; C6EB310316B8E7D80091F4F1 /* NSArray+MCO.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6EB30FD16B8E50F0091F4F1 /* NSArray+MCO.h */; }; + F87F190C16BB62B00012652F /* MCOFetchFoldersOperation.mm in Sources */ = {isa = PBXBuildFile; fileRef = F87F190B16BB62B00012652F /* MCOFetchFoldersOperation.mm */; }; + F8EA941716BB1C9D0011AC6F /* MCOIMAPSession.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = F8EA941416BAED6E0011AC6F /* MCOIMAPSession.h */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -201,7 +212,13 @@ dstPath = include/mailcore; dstSubfolderSpec = 16; files = ( + C63CD68C16BE1BC800DB18F1 /* MCHTMLRendererCallback.h in CopyFiles */, + C63CD68816BE1BBF00DB18F1 /* MCAddressDisplay.h in CopyFiles */, + C63CD68D16BE1BCA00DB18F1 /* MCRenderer.h in CopyFiles */, C62C6EE016A696AB00737497 /* MCAsyncIMAP.h in CopyFiles */, + C63CD68B16BE1BC600DB18F1 /* MCHTMLRenderer.h in CopyFiles */, + C63CD68A16BE1BC400DB18F1 /* MCSizeFormatter.h in CopyFiles */, + C63CD68916BE1BC100DB18F1 /* MCDateFormatter.h in CopyFiles */, C6EB30DE16B5B8050091F4F1 /* MCObjC.h in CopyFiles */, C6EB310216B8E7D60091F4F1 /* NSObject+MCO.h in CopyFiles */, C6EB310316B8E7D80091F4F1 /* NSArray+MCO.h in CopyFiles */, @@ -336,6 +353,17 @@ C62C6F0516A7E54400737497 /* MCPOPFetchMessagesOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCPOPFetchMessagesOperation.h; sourceTree = "<group>"; }; C62C6F0816A8F57000737497 /* MCIMAPAsyncSession.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCIMAPAsyncSession.cpp; sourceTree = "<group>"; }; C62C6F0916A8F57700737497 /* MCIMAPAsyncSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCIMAPAsyncSession.h; sourceTree = "<group>"; }; + C63CD67716BDCDD400DB18F1 /* MCAddressDisplay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCAddressDisplay.cpp; sourceTree = "<group>"; }; + C63CD67816BDCDD400DB18F1 /* MCAddressDisplay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCAddressDisplay.h; sourceTree = "<group>"; }; + C63CD67916BDCDD400DB18F1 /* MCDateFormatter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCDateFormatter.cpp; sourceTree = "<group>"; }; + C63CD67A16BDCDD400DB18F1 /* MCDateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCDateFormatter.h; sourceTree = "<group>"; }; + C63CD67B16BDCDD400DB18F1 /* MCHTMLRenderer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCHTMLRenderer.cpp; sourceTree = "<group>"; }; + C63CD67C16BDCDD400DB18F1 /* MCHTMLRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCHTMLRenderer.h; sourceTree = "<group>"; }; + C63CD67D16BDCDD400DB18F1 /* MCSizeFormatter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCSizeFormatter.cpp; sourceTree = "<group>"; }; + C63CD67E16BDCDD400DB18F1 /* MCSizeFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCSizeFormatter.h; sourceTree = "<group>"; }; + C63CD68416BE148B00DB18F1 /* MCHTMLRendererCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCHTMLRendererCallback.cpp; sourceTree = "<group>"; }; + C63CD68516BE148B00DB18F1 /* MCHTMLRendererCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCHTMLRendererCallback.h; sourceTree = "<group>"; }; + C63CD68716BE1AB600DB18F1 /* MCRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCRenderer.h; sourceTree = "<group>"; }; C64EA537169E772200778456 /* libmailcore2.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libmailcore2.a; sourceTree = BUILT_PRODUCTS_DIR; }; C64EA68C169E847800778456 /* MCIMAPAsyncConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCIMAPAsyncConnection.h; sourceTree = "<group>"; }; C64EA68F169E847800778456 /* MCSMTPAsyncSession.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCSMTPAsyncSession.cc; sourceTree = "<group>"; }; @@ -487,15 +515,15 @@ C6D42C1B16AE03D6002BB4F9 /* NSString+MCO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+MCO.h"; sourceTree = "<group>"; }; C6D42C1C16AE03D6002BB4F9 /* NSString+MCO.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSString+MCO.mm"; sourceTree = "<group>"; }; C6EB30DC16B5B7770091F4F1 /* MCObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCObjC.h; sourceTree = "<group>"; }; - F87F190816BB62690012652F /* MCOFetchFoldersOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCOFetchFoldersOperation.h; sourceTree = "<group>"; }; - F87F190B16BB62B00012652F /* MCOFetchFoldersOperation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MCOFetchFoldersOperation.mm; sourceTree = "<group>"; }; - F8EA941416BAED6E0011AC6F /* MCOIMAPSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCOIMAPSession.h; sourceTree = "<group>"; }; C6EB30F516B8C9480091F4F1 /* NSDictionary+MCO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+MCO.h"; sourceTree = "<group>"; }; C6EB30F616B8C9480091F4F1 /* NSDictionary+MCO.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSDictionary+MCO.mm"; sourceTree = "<group>"; }; C6EB30FC16B8E50F0091F4F1 /* NSArray+MCO.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSArray+MCO.mm"; sourceTree = "<group>"; }; C6EB30FD16B8E50F0091F4F1 /* NSArray+MCO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+MCO.h"; sourceTree = "<group>"; }; C6EB30FF16B8E6E50091F4F1 /* NSObject+MCO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+MCO.h"; sourceTree = "<group>"; }; C6EB310016B8E6E50091F4F1 /* NSObject+MCO.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSObject+MCO.mm"; sourceTree = "<group>"; }; + F87F190816BB62690012652F /* MCOFetchFoldersOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCOFetchFoldersOperation.h; sourceTree = "<group>"; }; + F87F190B16BB62B00012652F /* MCOFetchFoldersOperation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MCOFetchFoldersOperation.mm; sourceTree = "<group>"; }; + F8EA941416BAED6E0011AC6F /* MCOIMAPSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCOIMAPSession.h; sourceTree = "<group>"; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -519,6 +547,24 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + C63CD67616BDCDD300DB18F1 /* renderer */ = { + isa = PBXGroup; + children = ( + C63CD67716BDCDD400DB18F1 /* MCAddressDisplay.cpp */, + C63CD67816BDCDD400DB18F1 /* MCAddressDisplay.h */, + C63CD67916BDCDD400DB18F1 /* MCDateFormatter.cpp */, + C63CD67A16BDCDD400DB18F1 /* MCDateFormatter.h */, + C63CD67D16BDCDD400DB18F1 /* MCSizeFormatter.cpp */, + C63CD67E16BDCDD400DB18F1 /* MCSizeFormatter.h */, + C63CD67B16BDCDD400DB18F1 /* MCHTMLRenderer.cpp */, + C63CD67C16BDCDD400DB18F1 /* MCHTMLRenderer.h */, + C63CD68416BE148B00DB18F1 /* MCHTMLRendererCallback.cpp */, + C63CD68516BE148B00DB18F1 /* MCHTMLRendererCallback.h */, + C63CD68716BE1AB600DB18F1 /* MCRenderer.h */, + ); + path = renderer; + sourceTree = "<group>"; + }; C64EA52C169E772200778456 = { isa = PBXGroup; children = ( @@ -653,6 +699,7 @@ C64EA691169E847800778456 /* core */ = { isa = PBXGroup; children = ( + C63CD67616BDCDD300DB18F1 /* renderer */, C64EA692169E847800778456 /* abstract */, C64EA6A1169E847800778456 /* basetypes */, C64EA6C3169E847800778456 /* imap */, @@ -1027,6 +1074,11 @@ C6EB30F716B8C9480091F4F1 /* NSDictionary+MCO.mm in Sources */, C6EB30FE16B8E50F0091F4F1 /* NSArray+MCO.mm in Sources */, C6EB310116B8E6E60091F4F1 /* NSObject+MCO.mm in Sources */, + C63CD67F16BDCDD400DB18F1 /* MCAddressDisplay.cpp in Sources */, + C63CD68016BDCDD400DB18F1 /* MCDateFormatter.cpp in Sources */, + C63CD68116BDCDD400DB18F1 /* MCHTMLRenderer.cpp in Sources */, + C63CD68216BDCDD400DB18F1 /* MCSizeFormatter.cpp in Sources */, + C63CD68616BE148B00DB18F1 /* MCHTMLRendererCallback.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1076,11 +1128,13 @@ HEADER_SEARCH_PATHS = ( "$(SRCROOT)/../Externals/libetpan/include", "$(SRCROOT)/../Externals/icu4c/include", + "$(SRCROOT)/../Externals/ctemplate/include", /usr/include/libxml2, ); LIBRARY_SEARCH_PATHS = ( "$(SRCROOT)/../Externals/libetpan/lib", "$(SRCROOT)/../Externals/icu4c/lib", + "$(SRCROOT)/../Externals/ctemplate/lib", ); MACOSX_DEPLOYMENT_TARGET = 10.8; ONLY_ACTIVE_ARCH = YES; @@ -1109,11 +1163,13 @@ HEADER_SEARCH_PATHS = ( "$(SRCROOT)/../Externals/libetpan/include", "$(SRCROOT)/../Externals/icu4c/include", + "$(SRCROOT)/../Externals/ctemplate/include", /usr/include/libxml2, ); LIBRARY_SEARCH_PATHS = ( "$(SRCROOT)/../Externals/libetpan/lib", "$(SRCROOT)/../Externals/icu4c/lib", + "$(SRCROOT)/../Externals/ctemplate/lib", ); MACOSX_DEPLOYMENT_TARGET = 10.8; SDKROOT = macosx; @@ -1141,7 +1197,9 @@ C64EA799169F259300778456 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_CXX_LIBRARY = "libstdc++"; OTHER_LDFLAGS = ( + "-lctemplate", "-letpan", "-licudata", "-licui18n", @@ -1160,7 +1218,9 @@ C64EA79A169F259300778456 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_CXX_LIBRARY = "libstdc++"; OTHER_LDFLAGS = ( + "-lctemplate", "-letpan", "-licudata", "-licui18n", diff --git a/scripts/prepare.sh b/scripts/prepare.sh index 3e3cb9b1..11b41a24 100755 --- a/scripts/prepare.sh +++ b/scripts/prepare.sh @@ -1,3 +1,4 @@ #!/bin/sh ./prepare-icu4c-macos.sh ./prepare-libetpan-macos.sh +./prepare-ctemplate-macos.sh diff --git a/src/core/abstract/MCAbstractMessage.cc b/src/core/abstract/MCAbstractMessage.cc index f1768aec..b7d9b9af 100644 --- a/src/core/abstract/MCAbstractMessage.cc +++ b/src/core/abstract/MCAbstractMessage.cc @@ -56,3 +56,15 @@ void AbstractMessage::setHeader(MessageHeader * header) { MC_SAFE_REPLACE_RETAIN(MessageHeader, mHeader, header); } + +AbstractPart * AbstractMessage::partForContentID(String * contentID) +{ + MCAssert(0); + return NULL; +} + +AbstractPart * AbstractMessage::partForUniqueID(String * uniqueID) +{ + MCAssert(0); + return NULL; +} diff --git a/src/core/abstract/MCAbstractMessage.h b/src/core/abstract/MCAbstractMessage.h index 9f327cad..9dccdbb8 100644 --- a/src/core/abstract/MCAbstractMessage.h +++ b/src/core/abstract/MCAbstractMessage.h @@ -7,6 +7,7 @@ namespace mailcore { + class AbstractPart; class MessageHeader; class AbstractMessage : public Object { @@ -17,6 +18,9 @@ namespace mailcore { virtual MessageHeader * header(); virtual void setHeader(MessageHeader * header); + virtual AbstractPart * partForContentID(String * contentID); + virtual AbstractPart * partForUniqueID(String * uniqueID); + public: //subclass behavior AbstractMessage(AbstractMessage * other); virtual String * description(); diff --git a/src/core/abstract/MCAbstractMessagePart.cc b/src/core/abstract/MCAbstractMessagePart.cc index 98acec98..a52d2196 100644 --- a/src/core/abstract/MCAbstractMessagePart.cc +++ b/src/core/abstract/MCAbstractMessagePart.cc @@ -79,3 +79,13 @@ void AbstractMessagePart::setMessage(AbstractMessage * message) AbstractPart::setMessage(message); applyMessage(); } + +AbstractPart * AbstractMessagePart::partForContentID(String * contentID) +{ + return mainPart()->partForContentID(contentID); +} + +AbstractPart * AbstractMessagePart::partForUniqueID(String * contentID) +{ + return mainPart()->partForContentID(contentID); +} diff --git a/src/core/abstract/MCAbstractMessagePart.h b/src/core/abstract/MCAbstractMessagePart.h index bfbd00be..789f7676 100644 --- a/src/core/abstract/MCAbstractMessagePart.h +++ b/src/core/abstract/MCAbstractMessagePart.h @@ -24,6 +24,9 @@ namespace mailcore { virtual void setMessage(AbstractMessage * message); + virtual AbstractPart * partForContentID(String * contentID); + virtual AbstractPart * partForUniqueID(String * uniqueID); + public: //subclass behavior AbstractMessagePart(AbstractMessagePart * other); virtual String * description(); diff --git a/src/core/abstract/MCAbstractMultipart.cc b/src/core/abstract/MCAbstractMultipart.cc index 207b2962..2604bcac 100644 --- a/src/core/abstract/MCAbstractMultipart.cc +++ b/src/core/abstract/MCAbstractMultipart.cc @@ -86,3 +86,27 @@ void AbstractMultipart::setMessage(AbstractMessage * message) AbstractPart::setMessage(message); applyMessage(); } + +AbstractPart * AbstractMultipart::partForContentID(String * contentID) +{ + for(unsigned int i = 0 ; i < parts()->count() ; i ++) { + mailcore::AbstractPart * subpart = (mailcore::AbstractPart *) parts()->objectAtIndex(i); + mailcore::AbstractPart * result = subpart->partForContentID(contentID); + if (result != NULL) + return result; + } + return NULL; +} + + +AbstractPart * AbstractMultipart::partForUniqueID(String * uniqueID) +{ + for(unsigned int i = 0 ; i < parts()->count() ; i ++) { + mailcore::AbstractPart * subpart = (mailcore::AbstractPart *) parts()->objectAtIndex(i); + mailcore::AbstractPart * result = subpart->partForUniqueID(uniqueID); + if (result != NULL) + return result; + } + return NULL; +} + diff --git a/src/core/abstract/MCAbstractMultipart.h b/src/core/abstract/MCAbstractMultipart.h index 411e8af0..d5d5f343 100644 --- a/src/core/abstract/MCAbstractMultipart.h +++ b/src/core/abstract/MCAbstractMultipart.h @@ -19,6 +19,9 @@ namespace mailcore { virtual void setMessage(AbstractMessage * message); + virtual AbstractPart * partForContentID(String * contentID); + virtual AbstractPart * partForUniqueID(String * uniqueID); + public: //subclass behavior AbstractMultipart(AbstractMultipart * other); virtual String * description(); diff --git a/src/core/abstract/MCAbstractPart.cc b/src/core/abstract/MCAbstractPart.cc index b2e6281d..78e2e365 100644 --- a/src/core/abstract/MCAbstractPart.cc +++ b/src/core/abstract/MCAbstractPart.cc @@ -227,3 +227,24 @@ void AbstractPart::importIMAPFields(struct mailimap_body_fields * fields, } } } + +AbstractPart * AbstractPart::partForContentID(String * contentID) +{ + if (contentID->isEqual(mContentID)) { + return this; + } + else { + return NULL; + } +} + +AbstractPart * AbstractPart::partForUniqueID(String * uniqueID) +{ + if (uniqueID->isEqual(mUniqueID)) { + return this; + } + else { + return NULL; + } +} + diff --git a/src/core/abstract/MCAbstractPart.h b/src/core/abstract/MCAbstractPart.h index db034654..49360089 100644 --- a/src/core/abstract/MCAbstractPart.h +++ b/src/core/abstract/MCAbstractPart.h @@ -43,14 +43,19 @@ namespace mailcore { virtual AbstractMessage * message(); virtual void setMessage(AbstractMessage * message); - virtual void importIMAPFields(struct mailimap_body_fields * fields, - struct mailimap_body_ext_1part * extension); + virtual AbstractPart * partForContentID(String * contentID); + virtual AbstractPart * partForUniqueID(String * uniqueID); public: // subclass behavior AbstractPart(AbstractPart * other); virtual String * description(); virtual Object * copy(); + public: // private + virtual void importIMAPFields(struct mailimap_body_fields * fields, + struct mailimap_body_ext_1part * extension); + + private: String * mUniqueID; String * mFilename; diff --git a/src/core/basetypes/MCString.cc b/src/core/basetypes/MCString.cc index 97b6d7d4..d57e70ed 100644 --- a/src/core/basetypes/MCString.cc +++ b/src/core/basetypes/MCString.cc @@ -1722,7 +1722,9 @@ String * String::flattenHTMLAndShowBlockquoteAndLink(bool showBlockquote, bool s state.linkStack = new Array(); state.paragraphSpacingStack = new Array(); - htmlSAXParseDoc((xmlChar*) UTF8Characters(), "utf-8", &handler, &state); + const char * characters = cleanedHTMLString()->UTF8Characters(); + + htmlSAXParseDoc((xmlChar*) characters, "utf-8", &handler, &state); if (mem_base != xmlMemBlocks()) { MCLog("Leak of %d blocks found in htmlSAXParseDoc", @@ -2011,3 +2013,9 @@ String * String::cleanedHTMLString() #warning implement HTML cleaning with tidy return (String *) copy()->autorelease(); } + +bool String::isEqualCaseInsensitive(String * otherString) +{ + return caseInsensitiveCompare(otherString) == 0; +} + diff --git a/src/core/basetypes/MCString.h b/src/core/basetypes/MCString.h index 97db50da..521291d3 100644 --- a/src/core/basetypes/MCString.h +++ b/src/core/basetypes/MCString.h @@ -61,6 +61,8 @@ namespace mailcore { virtual Array * componentsSeparatedByString(String * separator); + virtual bool isEqualCaseInsensitive(String * otherString); + // Additions static String * stringByDecodingMIMEHeaderValue(const char * phrase); virtual Data * encodedAddressDisplayNameValue(); diff --git a/src/core/imap/MCIMAPMessage.cc b/src/core/imap/MCIMAPMessage.cc index 6d8311ed..7f5f4427 100644 --- a/src/core/imap/MCIMAPMessage.cc +++ b/src/core/imap/MCIMAPMessage.cc @@ -1,9 +1,17 @@ #include "MCIMAPMessage.h" #include "MCMessageHeader.h" +#include "MCIMAPPart.h" +#include "MCIMAPMessagePart.h" +#include "MCIMAPMultipart.h" +#include "MCHTMLRenderer.h" using namespace mailcore; +static AbstractPart * partForPartIDInPart(AbstractPart * part, String * partID); +static AbstractPart * partForPartIDInMultipart(AbstractMultipart * part, String * partID); +static AbstractPart * partForPartIDInMessagePart(AbstractMessagePart * part, String * partID); + void IMAPMessage::init() { mUid = NULL; @@ -102,3 +110,66 @@ Array * IMAPMessage::gmailLabels() return mLabels; } +AbstractPart * IMAPMessage::partForPartID(String * partID) +{ + return partForPartIDInPart(mainPart(), partID); +} + +static AbstractPart * partForPartIDInPart(AbstractPart * part, String * partID) +{ + switch (part->partType()) { + case PartTypeSingle: + if (partID->isEqual(((IMAPPart *) part)->partID())) { + return part; + } + return NULL; + case mailcore::PartTypeMultipartMixed: + case mailcore::PartTypeMultipartRelated: + case mailcore::PartTypeMultipartAlternative: + if (partID->isEqual(((IMAPMultipart *) part)->partID())) { + return part; + } + return partForPartIDInMultipart((AbstractMultipart *) part, partID); + case mailcore::PartTypeMessage: + if (partID->isEqual(((IMAPMessagePart *) part)->partID())) { + return part; + } + return partForPartIDInMessagePart((AbstractMessagePart *) part, partID); + default: + return NULL; + } +} + +static AbstractPart * partForPartIDInMessagePart(AbstractMessagePart * part, String * partID) +{ + return partForPartIDInPart(part->mainPart(), partID); +} + +static AbstractPart * partForPartIDInMultipart(AbstractMultipart * part, String * partID) +{ + for(unsigned int i = 0 ; i < part->parts()->count() ; i ++) { + mailcore::AbstractPart * subpart = (mailcore::AbstractPart *) part->parts()->objectAtIndex(i); + mailcore::AbstractPart * result = partForPartIDInPart(subpart, partID); + if (result != NULL) + return result; + } + return NULL; +} + +AbstractPart * IMAPMessage::partForContentID(String * contentID) +{ + return mainPart()->partForContentID(contentID); +} + +AbstractPart * IMAPMessage::partForUniqueID(String * uniqueID) +{ + return mainPart()->partForUniqueID(uniqueID); +} + +String * IMAPMessage::htmlRendering(String * folder, + HTMLRendererIMAPCallback * dataCallback, + HTMLRendererTemplateCallback * htmlCallback) +{ + return HTMLRenderer::htmlForIMAPMessage(folder, this, dataCallback, htmlCallback); +} + diff --git a/src/core/imap/MCIMAPMessage.h b/src/core/imap/MCIMAPMessage.h index 692ddc49..38d25ea4 100644 --- a/src/core/imap/MCIMAPMessage.h +++ b/src/core/imap/MCIMAPMessage.h @@ -11,6 +11,10 @@ namespace mailcore { + class IMAPPart; + class HTMLRendererIMAPCallback; + class HTMLRendererTemplateCallback; + class IMAPMessage : public AbstractMessage { public: IMAPMessage(); @@ -31,6 +35,15 @@ namespace mailcore { virtual void setGmailLabels(Array * labels); virtual Array * gmailLabels(); + virtual AbstractPart * partForPartID(String * partID); + + virtual AbstractPart * partForContentID(String * contentID); + virtual AbstractPart * partForUniqueID(String * uniqueID); + + virtual String * htmlRendering(String * folder, + HTMLRendererIMAPCallback * dataCallback, + HTMLRendererTemplateCallback * htmlCallback); + public: // subclass behavior IMAPMessage(IMAPMessage * other); virtual Object * copy(); diff --git a/src/core/imap/MCIMAPMessagePart.cc b/src/core/imap/MCIMAPMessagePart.cc index b250ef4b..bd97657c 100644 --- a/src/core/imap/MCIMAPMessagePart.cc +++ b/src/core/imap/MCIMAPMessagePart.cc @@ -4,17 +4,36 @@ using namespace mailcore; IMAPMessagePart::IMAPMessagePart() { + init(); } IMAPMessagePart::IMAPMessagePart(IMAPMessagePart * other) : AbstractMessagePart(other) { + init(); + MC_SAFE_REPLACE_COPY(String, mPartID, other->mPartID); } IMAPMessagePart::~IMAPMessagePart() { + MC_SAFE_RELEASE(mPartID); } Object * IMAPMessagePart::copy() { return new IMAPMessagePart(this); } + +void IMAPMessagePart::init() +{ + mPartID = NULL; +} + +void IMAPMessagePart::setPartID(String * partID) +{ + MC_SAFE_REPLACE_COPY(String, mPartID, partID); +} + +String * IMAPMessagePart::partID() +{ + return mPartID; +} diff --git a/src/core/imap/MCIMAPMessagePart.h b/src/core/imap/MCIMAPMessagePart.h index 03747ac0..8e23eff2 100644 --- a/src/core/imap/MCIMAPMessagePart.h +++ b/src/core/imap/MCIMAPMessagePart.h @@ -13,9 +13,16 @@ namespace mailcore { IMAPMessagePart(); virtual ~IMAPMessagePart(); + virtual void setPartID(String * partID); + virtual String * partID(); + public: // subclass behavior IMAPMessagePart(IMAPMessagePart * other); virtual Object * copy(); + + private: + String * mPartID; + void init(); }; } diff --git a/src/core/imap/MCIMAPMultipart.cc b/src/core/imap/MCIMAPMultipart.cc index 63a3384f..be0b2c8e 100644 --- a/src/core/imap/MCIMAPMultipart.cc +++ b/src/core/imap/MCIMAPMultipart.cc @@ -4,14 +4,18 @@ using namespace mailcore; IMAPMultipart::IMAPMultipart() { + init(); } IMAPMultipart::IMAPMultipart(IMAPMultipart * other) : AbstractMultipart(other) { + init(); + MC_SAFE_REPLACE_COPY(String, mPartID, other->mPartID); } IMAPMultipart::~IMAPMultipart() { + MC_SAFE_RELEASE(mPartID); } Object * IMAPMultipart::copy() @@ -19,3 +23,17 @@ Object * IMAPMultipart::copy() return new IMAPMultipart(this); } +void IMAPMultipart::init() +{ + mPartID = NULL; +} + +void IMAPMultipart::setPartID(String * partID) +{ + MC_SAFE_REPLACE_COPY(String, mPartID, partID); +} + +String * IMAPMultipart::partID() +{ + return mPartID; +} diff --git a/src/core/imap/MCIMAPMultipart.h b/src/core/imap/MCIMAPMultipart.h index 9a768d0a..02ee5cf8 100644 --- a/src/core/imap/MCIMAPMultipart.h +++ b/src/core/imap/MCIMAPMultipart.h @@ -13,9 +13,16 @@ namespace mailcore { IMAPMultipart(); virtual ~IMAPMultipart(); + virtual void setPartID(String * partID); + virtual String * partID(); + public: // subclass behavior IMAPMultipart(IMAPMultipart * other); virtual Object * copy(); + + private: + String * mPartID; + void init(); }; } diff --git a/src/core/imap/MCIMAPPart.cc b/src/core/imap/MCIMAPPart.cc index 787c0257..dc1a687f 100644 --- a/src/core/imap/MCIMAPPart.cc +++ b/src/core/imap/MCIMAPPart.cc @@ -154,6 +154,7 @@ IMAPMessagePart * IMAPPart::attachmentWithIMAPBody1PartMessage(struct mailimap_b } attachment = new IMAPMessagePart(); + attachment->setPartID(partID); attachment->header()->importIMAPEnvelope(message->bd_envelope); attachment->importIMAPFields(message->bd_fields, extension); @@ -267,6 +268,7 @@ IMAPMultipart * IMAPPart::attachmentWithIMAPBodyMultipart(struct mailimap_body_t } attachment = new IMAPMultipart(); + attachment->setPartID(partID); if (strcasecmp(body_mpart->bd_media_subtype, "alternative") == 0) { attachment->setPartType(PartTypeMultipartAlternative); } diff --git a/src/core/imap/MCIMAPPart.h b/src/core/imap/MCIMAPPart.h index e93b644e..44d03b2f 100644 --- a/src/core/imap/MCIMAPPart.h +++ b/src/core/imap/MCIMAPPart.h @@ -29,15 +29,16 @@ namespace mailcore { virtual void setEncoding(Encoding encoding); virtual Encoding encoding(); - static AbstractPart * attachmentWithIMAPBody(struct mailimap_body * body); - - virtual void importIMAPFields(struct mailimap_body_fields * fields, - struct mailimap_body_ext_1part * extension); - public: // subclass behavior IMAPPart(IMAPPart * other); virtual Object * copy(); + public: // private + static AbstractPart * attachmentWithIMAPBody(struct mailimap_body * body); + + virtual void importIMAPFields(struct mailimap_body_fields * fields, + struct mailimap_body_ext_1part * extension); + private: String * mPartID; Encoding mEncoding; diff --git a/src/core/renderer/MCAddressDisplay.cpp b/src/core/renderer/MCAddressDisplay.cpp new file mode 100644 index 00000000..842dd0df --- /dev/null +++ b/src/core/renderer/MCAddressDisplay.cpp @@ -0,0 +1,94 @@ +// +// MCAddressUI.cpp +// testUI +// +// Created by DINH Viêt Hoà on 1/27/13. +// Copyright (c) 2013 MailCore. All rights reserved. +// + +#include "MCAddressDisplay.h" + +using namespace mailcore; + +String * AddressDisplay::displayStringForAddress(Address * address) +{ + return address->nonEncodedRFC822String(); +} + +String * AddressDisplay::shortDisplayStringForAddress(Address * address) +{ + if ((address->displayName() != NULL) && (address->displayName()->length() > 0)) { + return address->displayName(); + } + else if (address->mailbox()) { + return address->mailbox(); + } + else { + return MCSTR("invalid"); + } +} + +String * AddressDisplay::veryShortDisplayStringForAddress(Address * address) +{ + if ((address->displayName() != NULL) && (address->displayName()->length() > 0)) { + Array * components; + String * senderName; + + senderName = address->displayName(); + senderName = (String *) senderName->copy()->autorelease(); + + senderName->replaceOccurrencesOfString(MCSTR(","), MCSTR(" ")); + senderName->replaceOccurrencesOfString(MCSTR("'"), MCSTR(" ")); + senderName->replaceOccurrencesOfString(MCSTR("\""), MCSTR(" ")); + components = senderName->componentsSeparatedByString(MCSTR(" ")); + if (components->count() == 0) { + return MCLOCALIZEDSTRING(MCSTR("invalid")); + } + return (String *) components->objectAtIndex(0); + } + else if (address->mailbox()) { + return address->mailbox(); + } + else { + return MCLOCALIZEDSTRING(MCSTR("invalid")); + } +} + +String * AddressDisplay::displayStringForAddresses(Array * addresses) +{ + String * result = String::string(); + for(unsigned int i = 0 ; i < addresses->count() ; i ++) { + Address * address = (Address *) addresses->objectAtIndex(i); + if (i != 0) { + result->appendString(MCSTR(", ")); + } + result->appendString(displayStringForAddress(address)); + } + return result; +} + +String * AddressDisplay::shortDisplayStringForAddresses(Array * addresses) +{ + String * result = String::string(); + for(unsigned int i = 0 ; i < addresses->count() ; i ++) { + Address * address = (Address *) addresses->objectAtIndex(i); + if (i != 0) { + result->appendString(MCSTR(", ")); + } + result->appendString(shortDisplayStringForAddress(address)); + } + return result; +} + +String * AddressDisplay::veryShortDisplayStringForAddresses(Array * addresses) +{ + String * result = String::string(); + for(unsigned int i = 0 ; i < addresses->count() ; i ++) { + Address * address = (Address *) addresses->objectAtIndex(i); + if (i != 0) { + result->appendString(MCSTR(", ")); + } + result->appendString(veryShortDisplayStringForAddress(address)); + } + return result; +} diff --git a/src/core/renderer/MCAddressDisplay.h b/src/core/renderer/MCAddressDisplay.h new file mode 100644 index 00000000..153ad245 --- /dev/null +++ b/src/core/renderer/MCAddressDisplay.h @@ -0,0 +1,34 @@ +// +// MCAddressUI.h +// testUI +// +// Created by DINH Viêt Hoà on 1/27/13. +// Copyright (c) 2013 MailCore. All rights reserved. +// + +#ifndef __MCAddressDisplay__ +#define __MCAddressDisplay__ + +#include <mailcore/MCAbstract.h> + +#ifdef __cplusplus + +namespace mailcore { + + class AddressDisplay { + + public: + static String * displayStringForAddress(Address * address); + static String * shortDisplayStringForAddress(Address * address); + static String * veryShortDisplayStringForAddress(Address * address); + + static String * displayStringForAddresses(Array * addresses); + static String * shortDisplayStringForAddresses(Array * addresses); + static String * veryShortDisplayStringForAddresses(Array * addresses); + }; + +}; + +#endif + +#endif /* defined(__MCAddressDisplay__) */ diff --git a/src/core/renderer/MCDateFormatter.cpp b/src/core/renderer/MCDateFormatter.cpp new file mode 100644 index 00000000..0fa86699 --- /dev/null +++ b/src/core/renderer/MCDateFormatter.cpp @@ -0,0 +1,160 @@ +// +// MCDateFormatter.cpp +// testUI +// +// Created by DINH Viêt Hoà on 1/28/13. +// Copyright (c) 2013 MailCore. All rights reserved. +// + +#include "MCDateFormatter.h" + +using namespace mailcore; + +DateFormatter::DateFormatter() +{ + mDateFormatter = NULL; + mDateStyle = DateFormatStyleMedium; + mTimeStyle = DateFormatStyleMedium; + mDateFormat = NULL; + mTimezone = NULL; + mLocale = NULL; +} + +DateFormatter::~DateFormatter() +{ + if (mDateFormatter != NULL) { + udat_close(mDateFormatter); + } + MC_SAFE_RELEASE(mDateFormat); + MC_SAFE_RELEASE(mTimezone); + MC_SAFE_RELEASE(mLocale); +} + +DateFormatter * DateFormatter::dateFormatter() +{ + DateFormatter * result = new DateFormatter(); + result->autorelease(); + return result; +} + + +void DateFormatter::setDateStyle(DateFormatStyle style) +{ + mDateStyle = style; +} + +DateFormatStyle DateFormatter::dateStyle() +{ + return mDateStyle; +} + +void DateFormatter::setTimeStyle(DateFormatStyle style) +{ + mTimeStyle = style; +} + +DateFormatStyle DateFormatter::timeStyle() +{ + return mTimeStyle; +} + +void DateFormatter::setLocale(String * locale) +{ + MC_SAFE_REPLACE_COPY(String, mLocale, locale); +} + +String * DateFormatter::locale() +{ + return mLocale; +} + +void DateFormatter::setTimezone(String * timezone) +{ + MC_SAFE_REPLACE_COPY(String, mTimezone, timezone); +} + +String * DateFormatter::timezone() +{ + return mTimezone; +} + +void DateFormatter::setDateFormat(String * dateFormat) +{ + MC_SAFE_REPLACE_COPY(String, mDateFormat, dateFormat); +} + +String * DateFormatter::dateFormat() +{ + return mDateFormat; +} + +String * DateFormatter::stringFromDate(time_t date) +{ + prepare(); + if (mDateFormatter == NULL) + return NULL; + + UErrorCode err = U_ZERO_ERROR; + int32_t len = udat_format(mDateFormatter, ((double) date) * 1000., NULL, 0, NULL, &err); + if(err != U_BUFFER_OVERFLOW_ERROR) { + return NULL; + } + + String * result; + + err = U_ZERO_ERROR; + UChar * unichars = (UChar *) malloc((len + 1) * sizeof(unichars)); + udat_format(mDateFormatter, ((double) date) * 1000., unichars, len + 1, NULL, &err); + result = new String(unichars, len); + free(unichars); + + result->autorelease(); + return result; +} + +time_t DateFormatter::dateFromString(String * dateString) +{ + prepare(); + if (mDateFormatter == NULL) + return (time_t) -1; + + UErrorCode err = U_ZERO_ERROR; + UDate date = udat_parse(mDateFormatter, dateString->unicodeCharacters(), dateString->length(), + NULL, &err); + if (err != U_ZERO_ERROR) { + return (time_t) -1; + } + + return date / 1000.; +} + +void DateFormatter::prepare() +{ + if (mDateFormatter != NULL) + return; + + const UChar * tzID = NULL; + int32_t tzIDLength = -1; + const UChar * pattern = NULL; + int32_t patternLength = -1; + UErrorCode err = U_ZERO_ERROR; + const char * locale = NULL; + + if (mTimezone != NULL) { + tzID = mTimezone->unicodeCharacters(); + tzIDLength = mTimezone->length(); + } + if (mDateFormat != NULL) { + pattern = mDateFormat->unicodeCharacters(); + patternLength = mDateFormat->length(); + } + if (mLocale != NULL) { + locale = mLocale->UTF8Characters(); + } + + mDateFormatter = udat_open((UDateFormatStyle) mTimeStyle, (UDateFormatStyle) mDateStyle, + locale, + tzID, tzIDLength, + pattern, patternLength, + &err); +} diff --git a/src/core/renderer/MCDateFormatter.h b/src/core/renderer/MCDateFormatter.h new file mode 100644 index 00000000..6467aae6 --- /dev/null +++ b/src/core/renderer/MCDateFormatter.h @@ -0,0 +1,69 @@ +// +// MCDateFormatter.h +// testUI +// +// Created by DINH Viêt Hoà on 1/28/13. +// Copyright (c) 2013 MailCore. All rights reserved. +// + +#ifndef __testUI__MCDateFormatter__ +#define __testUI__MCDateFormatter__ + +#include <mailcore/MCBaseTypes.h> +#include <unicode/udat.h> + +#ifdef __cplusplus + +namespace mailcore { + + class String; + + enum DateFormatStyle { + DateFormatStyleFull = UDAT_FULL, + DateFormatStyleLong = UDAT_LONG, + DateFormatStyleMedium = UDAT_MEDIUM, + DateFormatStyleShort = UDAT_SHORT, + DateFormatStyleNone = UDAT_NONE, + }; + + class DateFormatter : public Object { + public: + DateFormatter(); + virtual ~DateFormatter(); + + static DateFormatter * dateFormatter(); + + virtual void setDateStyle(DateFormatStyle style); + virtual DateFormatStyle dateStyle(); + + virtual void setTimeStyle(DateFormatStyle style); + virtual DateFormatStyle timeStyle(); + + virtual void setLocale(String * locale); + virtual String * locale(); + + virtual void setTimezone(String * timezone); + virtual String * timezone(); + + virtual void setDateFormat(String * dateFormat); + virtual String * dateFormat(); + + virtual String * stringFromDate(time_t date); + virtual time_t dateFromString(String * dateString); + + private: + UDateFormat * mDateFormatter; + DateFormatStyle mDateStyle; + DateFormatStyle mTimeStyle; + String * mDateFormat; + String * mTimezone; + String * mLocale; + + void prepare(); + }; + +} + +#endif + +#endif /* defined(__testUI__MCDateFormatter__) */ diff --git a/src/core/renderer/MCHTMLRenderer.cpp b/src/core/renderer/MCHTMLRenderer.cpp new file mode 100644 index 00000000..10066fc4 --- /dev/null +++ b/src/core/renderer/MCHTMLRenderer.cpp @@ -0,0 +1,446 @@ +// +// MCHTMLRenderer.cpp +// testUI +// +// Created by DINH Viêt Hoà on 1/23/13. +// Copyright (c) 2013 MailCore. All rights reserved. +// + +#include "MCHTMLRenderer.h" + +#include <ctemplate/template.h> +#include "MCAddressDisplay.h" +#include "MCDateFormatter.h" +#include "MCSizeFormatter.h" +#include "MCHTMLRendererCallback.h" + +using namespace mailcore; + +enum { + RENDER_STATE_NONE, + RENDER_STATE_HAD_ATTACHMENT, + RENDER_STATE_HAD_ATTACHMENT_THEN_TEXT, +}; + +struct htmlRendererContext { + HTMLRendererIMAPCallback * dataCallback; + HTMLRendererTemplateCallback * htmlCallback; + int firstRendered; + String * folder; + int state; + int pass; + bool hasMixedTextAndAttachments; + bool firstAttachment; + bool hasTextPart; +}; + +class DefaultTemplateCallback : public Object, public HTMLRendererTemplateCallback { +}; + +static bool partContainsMimeType(AbstractPart * part, String * mimeType); +static bool singlePartContainsMimeType(AbstractPart * part, String * mimeType); +static bool multipartContainsMimeType(AbstractMultipart * part, String * mimeType); +static bool messagePartContainsMimeType(AbstractMessagePart * part, String * mimeType); + +static String * htmlForAbstractPart(AbstractPart * part, htmlRendererContext * context); + +static String * renderTemplate(String * templateContent, HashMap * values); + +static String * htmlForAbstractMessage(String * folder, AbstractMessage * message, + HTMLRendererIMAPCallback * dataCallback, + HTMLRendererTemplateCallback * htmlCallback); + +static bool isTextPart(AbstractPart * part, htmlRendererContext * context) +{ + String * mimeType = part->mimeType()->lowercaseString(); + MCAssert(mimeType != NULL); + + if (!part->isInlineAttachment()) { + if ((part->filename() != NULL) && context->firstRendered) { + return false; + } + } + + if (mimeType->isEqual(MCSTR("text/plain"))) { + return true; + } + else if (mimeType->isEqual(MCSTR("text/html"))) { + return true; + } + else { + return false; + } +} + + +static AbstractPart * preferredPartInMultipartAlternative(AbstractMultipart * part) +{ + int htmlPart = -1; + int textPart = -1; + + for(unsigned int i = 0 ; i < part->parts()->count() ; i ++) { + AbstractPart * subpart = (AbstractPart *) part->parts()->objectAtIndex(i); + if (partContainsMimeType(subpart, MCSTR("text/html"))) { + htmlPart = i; + } + else if (partContainsMimeType(subpart, MCSTR("text/plain"))) { + textPart = i; + } + } + if (htmlPart != -1) { + return (AbstractPart *) part->parts()->objectAtIndex(htmlPart); + } + else if (textPart != -1) { + return (AbstractPart *) part->parts()->objectAtIndex(textPart); + } + else if (part->parts()->count() > 0) { + return (AbstractPart *) part->parts()->objectAtIndex(0); + } + else { + return NULL; + } +} + +static bool partContainsMimeType(AbstractPart * part, String * mimeType) +{ + switch (part->partType()) { + case PartTypeSingle: + return singlePartContainsMimeType(part, mimeType); + case PartTypeMessage: + return messagePartContainsMimeType((AbstractMessagePart *) part, mimeType); + case PartTypeMultipartMixed: + case PartTypeMultipartRelated: + case PartTypeMultipartAlternative: + return multipartContainsMimeType((AbstractMultipart *) part, mimeType); + default: + return false; + } +} + +static bool singlePartContainsMimeType(AbstractPart * part, String * mimeType) +{ + return part->mimeType()->lowercaseString()->isEqual(mimeType); +} + +static bool multipartContainsMimeType(AbstractMultipart * part, String * mimeType) +{ + for(unsigned int i = 0 ; i < part->parts()->count() ; i ++) { + AbstractPart * subpart = (AbstractPart *) part->parts()->objectAtIndex(i); + if (partContainsMimeType(subpart, mimeType)) { + return true; + } + } + return false; +} + +static bool messagePartContainsMimeType(AbstractMessagePart * part, String * mimeType) +{ + return partContainsMimeType(part->mainPart(), mimeType); +} + +static String * htmlForAbstractMessage(String * folder, AbstractMessage * message, + HTMLRendererIMAPCallback * dataCallback, + HTMLRendererTemplateCallback * htmlCallback) +{ + AbstractPart * mainPart = NULL; + + if (htmlCallback == NULL) { + htmlCallback = new DefaultTemplateCallback(); + ((DefaultTemplateCallback *) htmlCallback)->autorelease(); + } + + if (message->className()->isEqual(MCSTR("mailcore::IMAPMessage"))) { + mainPart = ((IMAPMessage *) message)->mainPart(); + } + else if (message->className()->isEqual(MCSTR("mailcore::MessageParser"))) { + mainPart = ((MessageParser *) message)->mainPart(); + } + MCAssert(mainPart != NULL); + + htmlRendererContext context; + context.dataCallback = dataCallback; + context.htmlCallback = htmlCallback; + context.firstRendered = 0; + context.folder = folder; + context.state = RENDER_STATE_NONE; + + context.hasMixedTextAndAttachments = false; + context.pass = 0; + context.firstAttachment = false; + context.hasTextPart = false; + htmlForAbstractPart(mainPart, &context); + + context.hasMixedTextAndAttachments = (context.state == RENDER_STATE_HAD_ATTACHMENT_THEN_TEXT); + context.pass = 1; + context.firstAttachment = false; + context.hasTextPart = false; + String * content = htmlForAbstractPart(mainPart, &context); + if (content == NULL) + return NULL; + + content = htmlCallback->filterHTMLForMessage(content); + + HashMap * values = htmlCallback->templateValuesForHeader(message->header()); + String * headerString = renderTemplate(htmlCallback->templateForMainHeader(), values); + + HashMap * msgValues = new HashMap(); + msgValues->setObjectForKey(MCSTR("HEADER"), headerString); + msgValues->setObjectForKey(MCSTR("BODY"), content); + String * result = renderTemplate(htmlCallback->templateForMessage(), msgValues); + msgValues->release(); + + return result; +} + +String * htmlForAbstractSinglePart(AbstractPart * part, htmlRendererContext * context); +String * htmlForAbstractMessagePart(AbstractMessagePart * part, htmlRendererContext * context); +String * htmlForAbstractMultipartRelated(AbstractMultipart * part, htmlRendererContext * context); +String * htmlForAbstractMultipartMixed(AbstractMultipart * part, htmlRendererContext * context); +String * htmlForAbstractMultipartAlternative(AbstractMultipart * part, htmlRendererContext * context); + +String * htmlForAbstractPart(AbstractPart * part, htmlRendererContext * context) +{ + switch (part->partType()) { + case PartTypeSingle: + return htmlForAbstractSinglePart((AbstractPart *) part, context); + case PartTypeMessage: + return htmlForAbstractMessagePart((AbstractMessagePart *) part, context); + case PartTypeMultipartMixed: + return htmlForAbstractMultipartMixed((AbstractMultipart *) part, context); + case PartTypeMultipartRelated: + return htmlForAbstractMultipartRelated((AbstractMultipart *) part, context); + case PartTypeMultipartAlternative: + return htmlForAbstractMultipartAlternative((AbstractMultipart *) part, context); + default: + MCAssert(0); + } + return NULL; +} + +String * htmlForAbstractSinglePart(AbstractPart * part, htmlRendererContext * context) +{ + String * mimeType = part->mimeType()->lowercaseString(); + MCAssert(mimeType != NULL); + + if (isTextPart(part, context)) { + if (context->pass == 0) { + if (context->state == RENDER_STATE_HAD_ATTACHMENT) { + context->state = RENDER_STATE_HAD_ATTACHMENT_THEN_TEXT; + } + return NULL; + } + + context->hasTextPart = true; + + if (mimeType->isEqual(MCSTR("text/plain"))) { + String * charset = part->charset(); + Data * data = NULL; + if (part->className()->isEqual(MCSTR("mailcore::IMAPPart"))) { + data = context->dataCallback->dataForIMAPPart(context->folder, (IMAPPart *) part); + } + else if (part->className()->isEqual(MCSTR("mailcore::Attachment"))) { + data = ((Attachment *) part)->data(); + MCAssert(data != NULL); + } + if (data == NULL) + return NULL; + + String * str = data->stringWithDetectedCharset(charset, false); + context->firstRendered = true; + return str->htmlEncodedString(); + } + else if (mimeType->isEqual(MCSTR("text/html"))) { + String * charset = part->charset(); + Data * data = NULL; + if (part->className()->isEqual(MCSTR("mailcore::IMAPPart"))) { + data = context->dataCallback->dataForIMAPPart(context->folder, (IMAPPart *) part); + } + else if (part->className()->isEqual(MCSTR("mailcore::Attachment"))) { + data = ((Attachment *) part)->data(); + MCAssert(data != NULL); + } + if (data == NULL) + return NULL; + + String * str = data->stringWithDetectedCharset(charset, true); + str = str->cleanedHTMLString(); + str = context->htmlCallback->filterHTMLForPart(str); + context->firstRendered = true; + return str; + } + else { + MCAssert(0); + return NULL; + } + } + else { + if (context->pass == 0) { + if (context->state == RENDER_STATE_NONE) { + context->state = RENDER_STATE_HAD_ATTACHMENT; + } + return NULL; + } + + if (part->uniqueID() == NULL) { + part->setUniqueID(String::uuidString()); + } + + String * result = String::string(); + String * separatorString; + String * content; + + if (!context->firstAttachment && context->hasTextPart) { + separatorString = context->htmlCallback->templateForAttachmentSeparator(); + } + else { + separatorString = MCSTR(""); + } + + context->firstAttachment = true; + + if (context->htmlCallback->canPreviewPart(part)) { + if (part->className()->isEqual(MCSTR("mailcore::IMAPPart"))) { + context->dataCallback->prefetchImageIMAPPart(context->folder, (IMAPPart *) part); + } + String * url = String::stringWithUTF8Format("x-mailcore-image:%s", + part->uniqueID()->UTF8Characters()); + HashMap * values = context->htmlCallback->templateValuesForPart(part); + values->setObjectForKey(MCSTR("URL"), url); + content = renderTemplate(context->htmlCallback->templateForImage(), values); + } + else { + if (part->className()->isEqual(MCSTR("mailcore::IMAPPart"))) { + context->dataCallback->prefetchAttachmentIMAPPart(context->folder, (IMAPPart *) part); + } + HashMap * values = context->htmlCallback->templateValuesForPart(part); + content = renderTemplate(context->htmlCallback->templateForAttachment(), values); + } + + result->appendString(separatorString); + result->appendString(content); + + return result; + } +} + +String * htmlForAbstractMessagePart(AbstractMessagePart * part, htmlRendererContext * context) +{ + String * substring = htmlForAbstractPart(part->mainPart(), context); + if (context->pass == 0) { + return NULL; + } + MCAssert(substring != NULL); + + String * result = String::string(); + HashMap * values = context->htmlCallback->templateValuesForHeader(part->header()); + String * headerString = renderTemplate(context->htmlCallback->templateForMainHeader(), values); + result->appendString(headerString); + result->appendString(substring); + return result; +} + +String * htmlForAbstractMultipartAlternative(AbstractMultipart * part, htmlRendererContext * context) +{ + AbstractPart * preferredAlternative = preferredPartInMultipartAlternative(part); + if (preferredAlternative == NULL) + return MCSTR(""); + + return htmlForAbstractPart(preferredAlternative, context); +} + +String * htmlForAbstractMultipartMixed(AbstractMultipart * part, htmlRendererContext * context) +{ + String * result = String::string(); + for(unsigned int i = 0 ; i < part->parts()->count() ; i ++) { + AbstractPart * subpart = (AbstractPart *) part->parts()->objectAtIndex(i); + String * substring = htmlForAbstractPart(subpart, context); + if (context->pass != 0) { + if (substring == NULL) + return NULL; + + result->appendString(substring); + } + } + return result; +} + +String * htmlForAbstractMultipartRelated(AbstractMultipart * part, htmlRendererContext * context) +{ + if (part->parts()->count() == 0) { + if (context->pass == 0) { + return NULL; + } + else { + return MCSTR(""); + } + } + + AbstractPart * subpart = (AbstractPart *) part->parts()->objectAtIndex(0); + return htmlForAbstractPart(subpart, context); +} + +void fillTemplateDictionaryFromMCHashMap(ctemplate::TemplateDictionary * dict, HashMap * mcHashMap) +{ + Array * keys = mcHashMap->allKeys(); + + for(unsigned int i = 0 ; i < keys->count() ; i ++) { + String * key = (String *) keys->objectAtIndex(i); + Object * value; + + value = mcHashMap->objectForKey(key); + if (value->className()->isEqual(MCSTR("mailcore::String"))) { + String * str; + + str = (String *) value; + dict->SetValue(key->UTF8Characters(), str->UTF8Characters()); + } + else if (value->className()->isEqual(MCSTR("mailcore::Array"))) { + Array * array; + + array = (Array *) value; + for(unsigned int k = 0 ; k < array->count() ; k ++) { + HashMap * item = (HashMap *) array->objectAtIndex(k); + ctemplate::TemplateDictionary * subDict = dict->AddSectionDictionary(key->UTF8Characters()); + fillTemplateDictionaryFromMCHashMap(subDict, item); + } + } + else if (value->className()->isEqual(MCSTR("mailcore::HashMap"))) { + ctemplate::TemplateDictionary * subDict; + HashMap * item; + + item = (HashMap *) value; + subDict = dict->AddSectionDictionary(key->UTF8Characters()); + fillTemplateDictionaryFromMCHashMap(subDict, item); + } + } +} + +String * renderTemplate(String * templateContent, HashMap * values) +{ + ctemplate::TemplateDictionary dict("template dict"); + std::string output; + Data * data; + + fillTemplateDictionaryFromMCHashMap(&dict, values); + data = templateContent->dataUsingEncoding("utf-8"); + ctemplate::Template * tpl = ctemplate::Template::StringToTemplate(data->bytes(), data->length(), ctemplate::DO_NOT_STRIP); + if (!tpl->Expand(&output, &dict)) + return NULL; + delete tpl; + + return String::stringWithUTF8Characters(output.c_str()); +} + +String * HTMLRenderer::htmlForRFC822Message(MessageParser * message, + HTMLRendererTemplateCallback * htmlCallback) +{ + return htmlForAbstractMessage(NULL, message, NULL, htmlCallback); +} + +String * HTMLRenderer::htmlForIMAPMessage(String * folder, + IMAPMessage * message, + HTMLRendererIMAPCallback * dataCallback, + HTMLRendererTemplateCallback * htmlCallback) +{ + return htmlForAbstractMessage(folder, message, dataCallback, htmlCallback); +} diff --git a/src/core/renderer/MCHTMLRenderer.h b/src/core/renderer/MCHTMLRenderer.h new file mode 100644 index 00000000..042625cf --- /dev/null +++ b/src/core/renderer/MCHTMLRenderer.h @@ -0,0 +1,38 @@ +// +// MCHTMLRenderer.h +// testUI +// +// Created by DINH Viêt Hoà on 1/23/13. +// Copyright (c) 2013 MailCore. All rights reserved. +// + +#ifndef __testUI__MCHTMLRenderer__ +#define __testUI__MCHTMLRenderer__ + +#include <mailcore/MCAbstract.h> +#include <mailcore/MCIMAP.h> +#include <mailcore/MCRFC822.h> + +#ifdef __cplusplus + +namespace mailcore { + + class MessageParser; + class HTMLRendererTemplateCallback; + class HTMLRendererIMAPCallback; + + class HTMLRenderer { + public: + static String * htmlForRFC822Message(MessageParser * message, + HTMLRendererTemplateCallback * htmlCallback); + + static String * htmlForIMAPMessage(String * folder, + IMAPMessage * message, + HTMLRendererIMAPCallback * dataCallback, + HTMLRendererTemplateCallback * htmlCallback); + }; +}; + +#endif + +#endif /* defined(__testUI__MCHTMLRenderer__) */ diff --git a/src/core/renderer/MCHTMLRendererCallback.cpp b/src/core/renderer/MCHTMLRendererCallback.cpp new file mode 100644 index 00000000..10b704d6 --- /dev/null +++ b/src/core/renderer/MCHTMLRendererCallback.cpp @@ -0,0 +1,259 @@ +// +// MCHTMLRendererCallback.cpp +// mailcore2 +// +// Created by DINH Viêt Hoà on 2/2/13. +// Copyright (c) 2013 MailCore. All rights reserved. +// + +#include "MCHTMLRendererCallback.h" + +#include "MCAddressDisplay.h" +#include "MCDateFormatter.h" +#include "MCSizeFormatter.h" +#include "MCAttachment.h" + +using namespace mailcore; + +mailcore::HashMap * HTMLRendererTemplateCallback::templateValuesForHeader(mailcore::MessageHeader * header) +{ + mailcore::HashMap * result = mailcore::HashMap::hashMap(); + + if (header->from() != NULL) { + result->setObjectForKey(MCSTR("HASFROM"), mailcore::HashMap::hashMap()); + result->setObjectForKey(MCSTR("FROM"), mailcore::AddressDisplay::displayStringForAddress(header->from())->htmlEncodedString()); + result->setObjectForKey(MCSTR("SHORTFROM"), mailcore::AddressDisplay::shortDisplayStringForAddress(header->from())->htmlEncodedString()); + result->setObjectForKey(MCSTR("VERYSHORTFROM"), mailcore::AddressDisplay::veryShortDisplayStringForAddress(header->from())->htmlEncodedString()); + } + else { + result->setObjectForKey(MCSTR("NOFROM"), mailcore::HashMap::hashMap()); + } + + if ((header->to() != NULL) && (header->to()->count() > 0)) { + result->setObjectForKey(MCSTR("HASTO"), mailcore::HashMap::hashMap()); + result->setObjectForKey(MCSTR("TO"), mailcore::AddressDisplay::displayStringForAddresses(header->to())->htmlEncodedString()); + result->setObjectForKey(MCSTR("SHORTTO"), mailcore::AddressDisplay::shortDisplayStringForAddresses(header->to())->htmlEncodedString()); + result->setObjectForKey(MCSTR("VERYSHORTTO"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(header->to())->htmlEncodedString()); + } + else { + result->setObjectForKey(MCSTR("NOTO"), mailcore::HashMap::hashMap()); + } + + if ((header->cc() != NULL) && (header->cc()->count() > 0)) { + result->setObjectForKey(MCSTR("HASCC"), mailcore::HashMap::hashMap()); + result->setObjectForKey(MCSTR("CC"), mailcore::AddressDisplay::displayStringForAddresses(header->cc())->htmlEncodedString()); + result->setObjectForKey(MCSTR("SHORTCC"), mailcore::AddressDisplay::shortDisplayStringForAddresses(header->cc())->htmlEncodedString()); + result->setObjectForKey(MCSTR("VERYSHORTCC"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(header->cc())->htmlEncodedString()); + } + else { + result->setObjectForKey(MCSTR("NOCC"), mailcore::HashMap::hashMap()); + } + + if ((header->bcc() != NULL) && (header->bcc()->count() > 0)) { + result->setObjectForKey(MCSTR("HASBCC"), mailcore::HashMap::hashMap()); + result->setObjectForKey(MCSTR("BCC"), mailcore::AddressDisplay::displayStringForAddresses(header->bcc())->htmlEncodedString()); + result->setObjectForKey(MCSTR("SHORTBCC"), mailcore::AddressDisplay::shortDisplayStringForAddresses(header->bcc())->htmlEncodedString()); + result->setObjectForKey(MCSTR("VERYSHORTBCC"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(header->bcc())->htmlEncodedString()); + } + else { + result->setObjectForKey(MCSTR("NOBCC"), mailcore::HashMap::hashMap()); + } + + mailcore::Array * recipient = new mailcore::Array(); + recipient->addObjectsFromArray(header->to()); + recipient->addObjectsFromArray(header->cc()); + recipient->addObjectsFromArray(header->bcc()); + + if (recipient->count() > 0) { + result->setObjectForKey(MCSTR("HASRECIPIENT"), mailcore::HashMap::hashMap()); + result->setObjectForKey(MCSTR("RECIPIENT"), mailcore::AddressDisplay::displayStringForAddresses(recipient)->htmlEncodedString()); + result->setObjectForKey(MCSTR("SHORTRECIPIENT"), mailcore::AddressDisplay::shortDisplayStringForAddresses(recipient)->htmlEncodedString()); + result->setObjectForKey(MCSTR("VERYSHORTRECIPIENT"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(recipient)->htmlEncodedString()); + } + else { + result->setObjectForKey(MCSTR("NORECIPIENT"), mailcore::HashMap::hashMap()); + } + recipient->release(); + + if ((header->replyTo() != NULL) && (header->replyTo()->count() > 0)) { + result->setObjectForKey(MCSTR("HASREPLYTO"), mailcore::HashMap::hashMap()); + result->setObjectForKey(MCSTR("REPLYTO"), mailcore::AddressDisplay::displayStringForAddresses(header->replyTo())->htmlEncodedString()); + result->setObjectForKey(MCSTR("SHORTREPLYTO"), mailcore::AddressDisplay::shortDisplayStringForAddresses(header->replyTo())->htmlEncodedString()); + result->setObjectForKey(MCSTR("VERYSHORTREPLYTO"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(header->replyTo())->htmlEncodedString()); + } + else { + result->setObjectForKey(MCSTR("NOREPLYTO"), mailcore::HashMap::hashMap()); + } + + if ((header->subject() != NULL) && (header->subject()->length() > 0)) { + result->setObjectForKey(MCSTR("EXTRACTEDSUBJECT"), header->partialExtractedSubject()->htmlEncodedString()); + result->setObjectForKey(MCSTR("SUBJECT"), header->subject()->htmlEncodedString()); + result->setObjectForKey(MCSTR("HASSUBJECT"), mailcore::HashMap::hashMap()); + } + else { + result->setObjectForKey(MCSTR("NOSUBJECT"), mailcore::HashMap::hashMap()); + } + + mailcore::String * dateString; + static mailcore::DateFormatter * fullFormatter = NULL; + if (fullFormatter == NULL) { + fullFormatter = new mailcore::DateFormatter(); + fullFormatter->setDateStyle(mailcore::DateFormatStyleFull); + fullFormatter->setTimeStyle(mailcore::DateFormatStyleFull); + } + dateString = fullFormatter->stringFromDate(header->date()); + if (dateString != NULL) { + result->setObjectForKey(MCSTR("FULLDATE"), dateString->htmlEncodedString()); + } + static mailcore::DateFormatter * longFormatter = NULL; + if (longFormatter == NULL) { + longFormatter = new mailcore::DateFormatter(); + longFormatter->setDateStyle(mailcore::DateFormatStyleLong); + longFormatter->setTimeStyle(mailcore::DateFormatStyleLong); + } + dateString = longFormatter->stringFromDate(header->date()); + if (dateString != NULL) { + result->setObjectForKey(MCSTR("LONGDATE"), dateString->htmlEncodedString()); + } + static mailcore::DateFormatter * mediumFormatter = NULL; + if (mediumFormatter == NULL) { + mediumFormatter = new mailcore::DateFormatter(); + mediumFormatter->setDateStyle(mailcore::DateFormatStyleMedium); + mediumFormatter->setTimeStyle(mailcore::DateFormatStyleMedium); + } + dateString = mediumFormatter->stringFromDate(header->date()); + if (dateString != NULL) { + result->setObjectForKey(MCSTR("MEDIUMDATE"), dateString->htmlEncodedString()); + } + static mailcore::DateFormatter * shortFormatter = NULL; + if (shortFormatter == NULL) { + shortFormatter = new mailcore::DateFormatter(); + shortFormatter->setDateStyle(mailcore::DateFormatStyleShort); + shortFormatter->setTimeStyle(mailcore::DateFormatStyleShort); + } + dateString = shortFormatter->stringFromDate(header->date()); + if (dateString != NULL) { + result->setObjectForKey(MCSTR("SHORTDATE"), dateString->htmlEncodedString()); + } + + return result; +} + +mailcore::HashMap * HTMLRendererTemplateCallback::templateValuesForPart(mailcore::AbstractPart * part) +{ + mailcore::HashMap * result = mailcore::HashMap::hashMap(); + mailcore::String * filename = NULL; + + if (part->filename() != NULL) { + filename = part->filename()->lastPathComponent(); + } + + if (filename != NULL) { + result->setObjectForKey(MCSTR("FILENAME"), filename->htmlEncodedString()); + } + + if (part->className()->isEqual(MCSTR("mailcore::IMAPPart"))) { + mailcore::IMAPPart * imapPart = (mailcore::IMAPPart *) part; + mailcore::String * value = mailcore::SizeFormatter::stringWithSize(imapPart->size()); + result->setObjectForKey(MCSTR("SIZE"), value); + result->setObjectForKey(MCSTR("HASSIZE"), mailcore::HashMap::hashMap()); + } + else if (part->className()->isEqual(MCSTR("mailcore::Attachment"))) { + mailcore::Attachment * attachment = (mailcore::Attachment *) part; + mailcore::String * value = mailcore::SizeFormatter::stringWithSize(attachment->data()->length()); + result->setObjectForKey(MCSTR("SIZE"), value); + result->setObjectForKey(MCSTR("HASSIZE"), mailcore::HashMap::hashMap()); + } + else { + result->setObjectForKey(MCSTR("NOSIZE"), mailcore::HashMap::hashMap()); + } + + if (part->contentID() != NULL) { + result->setObjectForKey(MCSTR("CONTENTID"), part->contentID()); + } + if (part->uniqueID() != NULL) { + result->setObjectForKey(MCSTR("UNIQUEID"), part->uniqueID()); + } + + return result; +} + +mailcore::String * HTMLRendererTemplateCallback::templateForMainHeader() +{ + return MCSTR("<div style=\"background-color:#eee\">\ + {{#HASFROM}}\ + <div><b>From:</b> {{FROM}}</div>\ + {{/HASFROM}}\ + {{#HASTO}}\ + <div><b>To:</b> {{TO}}</div>\ + {{/HASTO}}\ + {{#HASCC}}\ + <div><b>Cc:</b> {{CC}}</div>\ + {{/HASCC}}\ + {{#HASBCC}}\ + <div><b>Bcc:</b> {{BCC}}</div>\ + {{/HASBCC}}\ + {{#NORECIPIENT}}\ + <div><b>To:</b> <i>Undisclosed recipient</i></div>\ + {{/NORECIPIENT}}\ + {{#HASSUBJECT}}\ + <div><b>Subject:</b> {{EXTRACTEDSUBJECT}}</div>\ + {{/HASSUBJECT}}\ + {{#NOSUBJECT}}\ + <div><b>Subject:</b> <i>No Subject</i></div>\ + {{/NOSUBJECT}}\ + <div><b>Date:</b> {{LONGDATE}}</div>\ + </div>"); +} + +mailcore::String * HTMLRendererTemplateCallback::templateForHeader() +{ + return templateForMainHeader(); +} + +mailcore::String * HTMLRendererTemplateCallback::templateForImage() +{ + return MCSTR(""); +} + +mailcore::String * HTMLRendererTemplateCallback::templateForAttachment() +{ + return MCSTR("{{#HASSIZE}}\ + <div>- {{FILENAME}}, {{SIZE}}</div>\ + {{/HASSIZE}}\ + {{#HASSIZE}}\ + <div>- {{FILENAME}}</div>\ + {{/NOSIZE}}\ + "); +} + +mailcore::String * HTMLRendererTemplateCallback::templateForMessage() +{ + return MCSTR("<div style=\"padding-bottom: 20px;\">{{HEADER}}</div><div>{{BODY}}</div>"); +} + + +mailcore::String * HTMLRendererTemplateCallback::templateForEmbeddedMessage() +{ + return templateForMessage(); +} + +mailcore::String * HTMLRendererTemplateCallback::templateForAttachmentSeparator() +{ + return MCSTR("<hr/>"); +} + +mailcore::String * HTMLRendererTemplateCallback::filterHTMLForMessage(mailcore::String * html) +{ + return html; +} + +mailcore::String * HTMLRendererTemplateCallback::filterHTMLForPart(mailcore::String * html) +{ + return html; +} + +bool HTMLRendererTemplateCallback::canPreviewPart(AbstractPart * part) +{ + return false; +} diff --git a/src/core/renderer/MCHTMLRendererCallback.h b/src/core/renderer/MCHTMLRendererCallback.h new file mode 100644 index 00000000..2972249e --- /dev/null +++ b/src/core/renderer/MCHTMLRendererCallback.h @@ -0,0 +1,51 @@ +// +// MCHTMLRendererCallback.h +// mailcore2 +// +// Created by DINH Viêt Hoà on 2/2/13. +// Copyright (c) 2013 MailCore. All rights reserved. +// + +#ifndef __mailcore2__MCHTMLRendererCallback__ +#define __mailcore2__MCHTMLRendererCallback__ + +#include <mailcore/MCAbstract.h> +#include <mailcore/MCIMAP.h> + +#ifdef __cplusplus + +namespace mailcore { + + class MessageParser; + + class HTMLRendererIMAPCallback { + public: + virtual Data * dataForIMAPPart(String * folder, IMAPPart * part) { return NULL; } + virtual void prefetchAttachmentIMAPPart(String * folder, IMAPPart * part) {} + virtual void prefetchImageIMAPPart(String * folder, IMAPPart * part) {} + }; + + class HTMLRendererTemplateCallback { + public: + virtual bool canPreviewPart(AbstractPart * part); + + virtual HashMap * templateValuesForHeader(MessageHeader * header); + virtual HashMap * templateValuesForPart(AbstractPart * part); + + virtual String * templateForMainHeader(); + virtual String * templateForHeader(); + virtual String * templateForImage(); + virtual String * templateForAttachment(); + virtual String * templateForMessage(); + virtual String * templateForEmbeddedMessage(); + virtual String * templateForAttachmentSeparator(); + + virtual String * filterHTMLForPart(String * html); + virtual String * filterHTMLForMessage(String * html); + }; + +} + +#endif + +#endif /* defined(__mailcore2__MCHTMLRendererCallback__) */ diff --git a/src/core/renderer/MCRenderer.h b/src/core/renderer/MCRenderer.h new file mode 100644 index 00000000..a03b5be9 --- /dev/null +++ b/src/core/renderer/MCRenderer.h @@ -0,0 +1,18 @@ +// +// MCRenderer.h +// mailcore2 +// +// Created by DINH Viêt Hoà on 2/2/13. +// Copyright (c) 2013 MailCore. All rights reserved. +// + +#ifndef mailcore2_MCRenderer_h +#define mailcore2_MCRenderer_h + +#include <mailcore/MCAddressDisplay.h> +#include <mailcore/MCDateFormatter.h> +#include <mailcore/MCSizeFormatter.h> +#include <mailcore/MCHTMLRenderer.h> +#include <mailcore/MCHTMLRendererCallback.h> + +#endif diff --git a/src/core/renderer/MCSizeFormatter.cpp b/src/core/renderer/MCSizeFormatter.cpp new file mode 100644 index 00000000..c3795c63 --- /dev/null +++ b/src/core/renderer/MCSizeFormatter.cpp @@ -0,0 +1,43 @@ +// +// MCSizeFormatter.cpp +// testUI +// +// Created by DINH Viêt Hoà on 1/29/13. +// Copyright (c) 2013 MailCore. All rights reserved. +// + +#include "MCSizeFormatter.h" + +#include <math.h> + +using namespace mailcore; + +String * SizeFormatter::stringWithSize(unsigned int size) +{ + double divider; + String * unit; + + if (size >= 1024 * 1024 * 1024) { + divider = 1024 * 1024 * 1024; + unit = MCLOCALIZEDSTRING(MCSTR("GB")); + } + else if (size >= 1024 * 1024) { + divider = 1024 * 1024; + unit = MCLOCALIZEDSTRING(MCSTR("MB")); + } + else if (size >= 1024) { + divider = 1024; + unit = MCLOCALIZEDSTRING(MCSTR("KB")); + } + else { + divider = 1; + unit = MCLOCALIZEDSTRING(MCSTR("bytes")); + } + + if ((size / divider) - round(size / divider) < 0.1) { + return String::stringWithUTF8Format("%.0f %s", size / divider, unit->UTF8Characters()); + } + else { + return String::stringWithUTF8Format("%.1f %@", size / divider, unit->UTF8Characters()); + } +} diff --git a/src/core/renderer/MCSizeFormatter.h b/src/core/renderer/MCSizeFormatter.h new file mode 100644 index 00000000..a6c74010 --- /dev/null +++ b/src/core/renderer/MCSizeFormatter.h @@ -0,0 +1,28 @@ +// +// MCSizeFormatter.h +// testUI +// +// Created by DINH Viêt Hoà on 1/29/13. +// Copyright (c) 2013 MailCore. All rights reserved. +// + +#ifndef __testUI__MCSizeFormatter__ +#define __testUI__MCSizeFormatter__ + +#include <mailcore/MCBaseTypes.h> + +#ifdef __cplusplus + +namespace mailcore { + class String; + + class SizeFormatter : public Object { + public: + static String * stringWithSize(unsigned int size); + }; + +} + +#endif + +#endif /* defined(__testUI__MCSizeFormatter__) */ diff --git a/src/core/rfc822/MCAttachment.h b/src/core/rfc822/MCAttachment.h index 0be168aa..ac12a5b5 100644 --- a/src/core/rfc822/MCAttachment.h +++ b/src/core/rfc822/MCAttachment.h @@ -27,13 +27,14 @@ namespace mailcore { virtual void setData(Data * data); virtual Data * data(); - static AbstractPart * attachmentsWithMIME(struct mailmime * mime); - public: // subclass behavior Attachment(Attachment * other); virtual String * description(); virtual Object * copy(); + public: // private + static AbstractPart * attachmentsWithMIME(struct mailmime * mime); + private: Data * mData; void init(); diff --git a/src/core/rfc822/MCMessageParser.cc b/src/core/rfc822/MCMessageParser.cc index bdf2a87d..a0dcf142 100644 --- a/src/core/rfc822/MCMessageParser.cc +++ b/src/core/rfc822/MCMessageParser.cc @@ -2,6 +2,7 @@ #include "MCAttachment.h" #include "MCMessageHeader.h" +#include "MCHTMLRenderer.h" using namespace mailcore; @@ -73,3 +74,19 @@ Object * MessageParser::copy() { return new MessageParser(this); } + +AbstractPart * MessageParser::partForContentID(String * contentID) +{ + return mainPart()->partForContentID(contentID); +} + +AbstractPart * MessageParser::partForUniqueID(String * uniqueID) +{ + return mainPart()->partForUniqueID(uniqueID); +} + +String * MessageParser::htmlRendering(HTMLRendererTemplateCallback * htmlCallback) +{ + return HTMLRenderer::htmlForRFC822Message(this, htmlCallback); +} + diff --git a/src/core/rfc822/MCMessageParser.h b/src/core/rfc822/MCMessageParser.h index 06673ec4..5737920d 100644 --- a/src/core/rfc822/MCMessageParser.h +++ b/src/core/rfc822/MCMessageParser.h @@ -10,6 +10,8 @@ namespace mailcore { + class HTMLRendererTemplateCallback; + class MessageParser : public AbstractMessage { public: static MessageParser * messageParserWithData(Data * data); @@ -20,6 +22,11 @@ namespace mailcore { virtual AbstractPart * mainPart(); virtual Data * data(); + virtual AbstractPart * partForContentID(String * contentID); + virtual AbstractPart * partForUniqueID(String * uniqueID); + + virtual String * htmlRendering(HTMLRendererTemplateCallback * htmlCallback); + public: // subclass behavior MessageParser(MessageParser * other); virtual String * description(); |