aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--build-mac/mailcore2.xcodeproj/project.pbxproj872
-rw-r--r--scripts/.DS_Storebin0 -> 6148 bytes
-rwxr-xr-xscripts/prepare-icu4c-macos.sh123
-rwxr-xr-xscripts/prepare-libetpan-macos.sh83
-rwxr-xr-xscripts/prepare.sh3
-rw-r--r--src/async/imap/IMAPAsyncSession.h122
-rw-r--r--src/async/smtp/MCSMTPAsyncSession.cc147
-rw-r--r--src/async/smtp/MCSMTPAsyncSession.h73
-rw-r--r--src/async/smtp/MCSMTPSendWithBuilderOperation.cc9
-rw-r--r--src/async/smtp/MCSMTPSendWithBuilderOperation.h14
-rw-r--r--src/async/smtp/MCSMTPSendWithDataOperation.cc9
-rw-r--r--src/async/smtp/MCSMTPSendWithDataOperation.h14
-rw-r--r--src/async/smtp/MCSMTPSendWithRecipientOperation.cc9
-rw-r--r--src/async/smtp/MCSMTPSendWithRecipientOperation.h13
-rw-r--r--src/core/MCCore.h19
-rw-r--r--src/core/abstract/.DS_Storebin0 -> 6148 bytes
-rw-r--r--src/core/abstract/MCAbstract.h13
-rw-r--r--src/core/abstract/MCAbstractMessage.cc65
-rw-r--r--src/core/abstract/MCAbstractMessage.h29
-rw-r--r--src/core/abstract/MCAbstractMessagePart.cc88
-rw-r--r--src/core/abstract/MCAbstractMessagePart.h39
-rw-r--r--src/core/abstract/MCAbstractMultipart.cc95
-rw-r--r--src/core/abstract/MCAbstractMultipart.h32
-rw-r--r--src/core/abstract/MCAbstractPart.cc223
-rw-r--r--src/core/abstract/MCAbstractPart.h63
-rw-r--r--src/core/abstract/MCAddress.cc364
-rw-r--r--src/core/abstract/MCAddress.h55
-rw-r--r--src/core/abstract/MCMessageConstants.h208
-rw-r--r--src/core/abstract/MCMessageHeader.cc1054
-rw-r--r--src/core/abstract/MCMessageHeader.h90
-rw-r--r--src/core/basetypes/.DS_Storebin0 -> 6148 bytes
-rw-r--r--src/core/basetypes/MCArray.cc229
-rw-r--r--src/core/basetypes/MCArray.h49
-rw-r--r--src/core/basetypes/MCAssert.cc12
-rw-r--r--src/core/basetypes/MCAssert.h13
-rw-r--r--src/core/basetypes/MCAutoreleasePool.cc119
-rw-r--r--src/core/basetypes/MCAutoreleasePool.h34
-rw-r--r--src/core/basetypes/MCBaseTypes.h21
-rw-r--r--src/core/basetypes/MCData.cc526
-rw-r--r--src/core/basetypes/MCData.h58
-rw-r--r--src/core/basetypes/MCHash.cc12
-rw-r--r--src/core/basetypes/MCHash.h11
-rw-r--r--src/core/basetypes/MCHashMap.cc283
-rw-r--r--src/core/basetypes/MCHashMap.h45
-rw-r--r--src/core/basetypes/MCLog.cc30
-rw-r--r--src/core/basetypes/MCLog.h19
-rw-r--r--src/core/basetypes/MCMainThread.h11
-rw-r--r--src/core/basetypes/MCMainThread.mm60
-rw-r--r--src/core/basetypes/MCObject.cc180
-rw-r--r--src/core/basetypes/MCObject.h41
-rw-r--r--src/core/basetypes/MCOperation.cc45
-rw-r--r--src/core/basetypes/MCOperation.h33
-rw-r--r--src/core/basetypes/MCOperationCallback.h16
-rw-r--r--src/core/basetypes/MCOperationQueue.cc179
-rw-r--r--src/core/basetypes/MCOperationQueue.h45
-rw-r--r--src/core/basetypes/MCRange.cc12
-rw-r--r--src/core/basetypes/MCRange.h15
-rw-r--r--src/core/basetypes/MCSet.cc106
-rw-r--r--src/core/basetypes/MCSet.h42
-rw-r--r--src/core/basetypes/MCString.cc1958
-rw-r--r--src/core/basetypes/MCString.h123
-rw-r--r--src/core/basetypes/MCUtils.h34
-rw-r--r--src/core/basetypes/MCValue.cc314
-rw-r--r--src/core/basetypes/MCValue.h81
-rw-r--r--src/core/imap/.DS_Storebin0 -> 6148 bytes
-rw-r--r--src/core/imap/MCIMAP.h16
-rw-r--r--src/core/imap/MCIMAPFolder.cc71
-rw-r--r--src/core/imap/MCIMAPFolder.h36
-rw-r--r--src/core/imap/MCIMAPMessage.cc111
-rw-r--r--src/core/imap/MCIMAPMessage.h47
-rw-r--r--src/core/imap/MCIMAPMessagePart.cc27
-rw-r--r--src/core/imap/MCIMAPMessagePart.h23
-rw-r--r--src/core/imap/MCIMAPMultipart.cc28
-rw-r--r--src/core/imap/MCIMAPMultipart.h22
-rw-r--r--src/core/imap/MCIMAPNamespace.cc144
-rw-r--r--src/core/imap/MCIMAPNamespace.h44
-rw-r--r--src/core/imap/MCIMAPNamespaceItem.cc147
-rw-r--r--src/core/imap/MCIMAPNamespaceItem.h39
-rw-r--r--src/core/imap/MCIMAPPart.cc285
-rw-r--r--src/core/imap/MCIMAPPart.h58
-rw-r--r--src/core/imap/MCIMAPProgressCallback.h16
-rw-r--r--src/core/imap/MCIMAPSearchExpression.cc163
-rw-r--r--src/core/imap/MCIMAPSearchExpression.h45
-rw-r--r--src/core/imap/MCIMAPSession.cc2559
-rw-r--r--src/core/imap/MCIMAPSession.h162
-rw-r--r--src/core/pop/.DS_Storebin0 -> 6148 bytes
-rw-r--r--src/core/pop/MCPOP.h9
-rw-r--r--src/core/pop/MCPOPMessageInfo.cc76
-rw-r--r--src/core/pop/MCPOPMessageInfo.h38
-rw-r--r--src/core/pop/MCPOPProgressCallback.h15
-rw-r--r--src/core/pop/MCPOPSession.cc545
-rw-r--r--src/core/pop/MCPOPSession.h90
-rw-r--r--src/core/rfc822/.DS_Storebin0 -> 6148 bytes
-rw-r--r--src/core/rfc822/MCAttachment.cc444
-rw-r--r--src/core/rfc822/MCAttachment.h47
-rw-r--r--src/core/rfc822/MCMessageBuilder.cc706
-rw-r--r--src/core/rfc822/MCMessageBuilder.h55
-rw-r--r--src/core/rfc822/MCMessageParser.cc82
-rw-r--r--src/core/rfc822/MCMessageParser.h34
-rw-r--r--src/core/rfc822/MCMessagePart.cc27
-rw-r--r--src/core/rfc822/MCMessagePart.h22
-rw-r--r--src/core/rfc822/MCMultipart.cc28
-rw-r--r--src/core/rfc822/MCMultipart.h21
-rw-r--r--src/core/rfc822/MCRFC822.h11
-rw-r--r--src/core/smtp/.DS_Storebin0 -> 6148 bytes
-rw-r--r--src/core/smtp/MCSMTP.h8
-rw-r--r--src/core/smtp/MCSMTPProgressCallback.h15
-rw-r--r--src/core/smtp/MCSMTPSession.cc656
-rw-r--r--src/core/smtp/MCSMTPSession.h90
-rw-r--r--src/mailcore.h14
-rw-r--r--tests/main.mm187
111 files changed, 15947 insertions, 0 deletions
diff --git a/build-mac/mailcore2.xcodeproj/project.pbxproj b/build-mac/mailcore2.xcodeproj/project.pbxproj
new file mode 100644
index 00000000..13472734
--- /dev/null
+++ b/build-mac/mailcore2.xcodeproj/project.pbxproj
@@ -0,0 +1,872 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 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 */; };
+ C64EA6FA169E847800778456 /* MCAbstractPart.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA69A169E847800778456 /* MCAbstractPart.cc */; };
+ C64EA6FC169E847800778456 /* MCAddress.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA69C169E847800778456 /* MCAddress.cc */; };
+ C64EA6FF169E847800778456 /* MCMessageHeader.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA69F169E847800778456 /* MCMessageHeader.cc */; };
+ C64EA701169E847800778456 /* MCAutoreleasePool.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6A2169E847800778456 /* MCAutoreleasePool.cc */; };
+ C64EA704169E847800778456 /* MCArray.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6A5169E847800778456 /* MCArray.cc */; };
+ C64EA706169E847800778456 /* MCAssert.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6A7169E847800778456 /* MCAssert.cc */; };
+ C64EA708169E847800778456 /* MCData.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6A9169E847800778456 /* MCData.cc */; };
+ C64EA70A169E847800778456 /* MCHash.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6AB169E847800778456 /* MCHash.cc */; };
+ C64EA70C169E847800778456 /* MCHashMap.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6AD169E847800778456 /* MCHashMap.cc */; };
+ C64EA70E169E847800778456 /* MCLog.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6AF169E847800778456 /* MCLog.cc */; };
+ C64EA710169E847800778456 /* MCObject.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6B1169E847800778456 /* MCObject.cc */; };
+ C64EA712169E847800778456 /* MCRange.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6B3169E847800778456 /* MCRange.cc */; };
+ C64EA714169E847800778456 /* MCSet.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6B5169E847800778456 /* MCSet.cc */; };
+ C64EA716169E847800778456 /* MCString.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6B7169E847800778456 /* MCString.cc */; };
+ C64EA719169E847800778456 /* MCValue.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6BA169E847800778456 /* MCValue.cc */; };
+ C64EA71C169E847800778456 /* MCMainThread.mm in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6BD169E847800778456 /* MCMainThread.mm */; };
+ C64EA71D169E847800778456 /* MCOperation.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6BE169E847800778456 /* MCOperation.cc */; };
+ C64EA720169E847800778456 /* MCOperationQueue.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6C1169E847800778456 /* MCOperationQueue.cc */; };
+ C64EA723169E847800778456 /* MCIMAPFolder.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6C5169E847800778456 /* MCIMAPFolder.cc */; };
+ C64EA725169E847800778456 /* MCIMAPMessage.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6C7169E847800778456 /* MCIMAPMessage.cc */; };
+ C64EA727169E847800778456 /* MCIMAPMessagePart.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6C9169E847800778456 /* MCIMAPMessagePart.cc */; };
+ C64EA729169E847800778456 /* MCIMAPMultipart.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6CB169E847800778456 /* MCIMAPMultipart.cc */; };
+ C64EA72B169E847800778456 /* MCIMAPNamespace.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6CD169E847800778456 /* MCIMAPNamespace.cc */; };
+ C64EA72D169E847800778456 /* MCIMAPNamespaceItem.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6CF169E847800778456 /* MCIMAPNamespaceItem.cc */; };
+ C64EA72F169E847800778456 /* MCIMAPPart.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6D1169E847800778456 /* MCIMAPPart.cc */; };
+ C64EA732169E847800778456 /* MCIMAPSearchExpression.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6D4169E847800778456 /* MCIMAPSearchExpression.cc */; };
+ C64EA734169E847800778456 /* MCIMAPSession.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6D6169E847800778456 /* MCIMAPSession.cc */; };
+ C64EA737169E847800778456 /* MCPOPMessageInfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6DA169E847800778456 /* MCPOPMessageInfo.cc */; };
+ C64EA73A169E847800778456 /* MCPOPSession.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6DD169E847800778456 /* MCPOPSession.cc */; };
+ C64EA73C169E847800778456 /* MCAttachment.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6E0169E847800778456 /* MCAttachment.cc */; };
+ C64EA73E169E847800778456 /* MCMessageBuilder.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6E2169E847800778456 /* MCMessageBuilder.cc */; };
+ C64EA740169E847800778456 /* MCMessageParser.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6E4169E847800778456 /* MCMessageParser.cc */; };
+ C64EA742169E847800778456 /* MCMessagePart.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6E6169E847800778456 /* MCMessagePart.cc */; };
+ C64EA744169E847800778456 /* MCMultipart.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6E8169E847800778456 /* MCMultipart.cc */; };
+ C64EA74C169E859600778456 /* IMAPAsyncSession.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA68C169E847800778456 /* IMAPAsyncSession.h */; };
+ C64EA74D169E859600778456 /* MCSMTPAsyncSession.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA690169E847800778456 /* MCSMTPAsyncSession.h */; };
+ C64EA74E169E859600778456 /* MCAbstract.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA693169E847800778456 /* MCAbstract.h */; };
+ C64EA74F169E859600778456 /* MCAbstractMessage.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA695169E847800778456 /* MCAbstractMessage.h */; };
+ C64EA750169E859600778456 /* MCAbstractMessagePart.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA697169E847800778456 /* MCAbstractMessagePart.h */; };
+ C64EA751169E859600778456 /* MCAbstractMultipart.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA699169E847800778456 /* MCAbstractMultipart.h */; };
+ C64EA752169E859600778456 /* MCAbstractPart.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA69B169E847800778456 /* MCAbstractPart.h */; };
+ C64EA753169E859600778456 /* MCAddress.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA69D169E847800778456 /* MCAddress.h */; };
+ C64EA754169E859600778456 /* MCMessageConstants.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA69E169E847800778456 /* MCMessageConstants.h */; };
+ C64EA755169E859600778456 /* MCMessageHeader.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6A0169E847800778456 /* MCMessageHeader.h */; };
+ C64EA756169E859600778456 /* MCAutoreleasePool.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6A3169E847800778456 /* MCAutoreleasePool.h */; };
+ C64EA757169E859600778456 /* MCBaseTypes.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6A4169E847800778456 /* MCBaseTypes.h */; };
+ C64EA758169E859600778456 /* MCArray.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6A6169E847800778456 /* MCArray.h */; };
+ C64EA759169E859600778456 /* MCAssert.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6A8169E847800778456 /* MCAssert.h */; };
+ C64EA75A169E859600778456 /* MCData.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6AA169E847800778456 /* MCData.h */; };
+ C64EA75B169E859600778456 /* MCHash.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6AC169E847800778456 /* MCHash.h */; };
+ C64EA75C169E859600778456 /* MCHashMap.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6AE169E847800778456 /* MCHashMap.h */; };
+ C64EA75D169E859600778456 /* MCLog.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6B0169E847800778456 /* MCLog.h */; };
+ C64EA75E169E859600778456 /* MCObject.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6B2169E847800778456 /* MCObject.h */; };
+ C64EA75F169E859600778456 /* MCRange.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6B4169E847800778456 /* MCRange.h */; };
+ C64EA760169E859600778456 /* MCSet.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6B6169E847800778456 /* MCSet.h */; };
+ C64EA761169E859600778456 /* MCString.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6B8169E847800778456 /* MCString.h */; };
+ C64EA762169E859600778456 /* MCUtils.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6B9169E847800778456 /* MCUtils.h */; };
+ C64EA763169E859600778456 /* MCValue.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6BB169E847800778456 /* MCValue.h */; };
+ C64EA764169E859600778456 /* MCMainThread.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6BC169E847800778456 /* MCMainThread.h */; };
+ C64EA765169E859600778456 /* MCOperation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6BF169E847800778456 /* MCOperation.h */; };
+ C64EA766169E859600778456 /* MCOperationCallback.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6C0169E847800778456 /* MCOperationCallback.h */; };
+ C64EA767169E859600778456 /* MCOperationQueue.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6C2169E847800778456 /* MCOperationQueue.h */; };
+ C64EA768169E859600778456 /* MCIMAP.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6C4169E847800778456 /* MCIMAP.h */; };
+ C64EA769169E859600778456 /* MCIMAPFolder.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6C6169E847800778456 /* MCIMAPFolder.h */; };
+ C64EA76A169E859600778456 /* MCIMAPMessage.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6C8169E847800778456 /* MCIMAPMessage.h */; };
+ C64EA76B169E859600778456 /* MCIMAPMessagePart.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6CA169E847800778456 /* MCIMAPMessagePart.h */; };
+ C64EA76C169E859600778456 /* MCIMAPMultipart.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6CC169E847800778456 /* MCIMAPMultipart.h */; };
+ C64EA76D169E859600778456 /* MCIMAPNamespace.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6CE169E847800778456 /* MCIMAPNamespace.h */; };
+ C64EA76E169E859600778456 /* MCIMAPNamespaceItem.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6D0169E847800778456 /* MCIMAPNamespaceItem.h */; };
+ C64EA76F169E859600778456 /* MCIMAPPart.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6D2169E847800778456 /* MCIMAPPart.h */; };
+ C64EA770169E859600778456 /* MCIMAPProgressCallback.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6D3169E847800778456 /* MCIMAPProgressCallback.h */; };
+ C64EA771169E859600778456 /* MCIMAPSearchExpression.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6D5169E847800778456 /* MCIMAPSearchExpression.h */; };
+ C64EA772169E859600778456 /* MCIMAPSession.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6D7169E847800778456 /* MCIMAPSession.h */; };
+ C64EA773169E859600778456 /* MCPOP.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6D9169E847800778456 /* MCPOP.h */; };
+ C64EA774169E859600778456 /* MCPOPMessageInfo.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6DB169E847800778456 /* MCPOPMessageInfo.h */; };
+ C64EA775169E859600778456 /* MCPOPProgressCallback.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6DC169E847800778456 /* MCPOPProgressCallback.h */; };
+ C64EA776169E859600778456 /* MCPOPSession.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6DE169E847800778456 /* MCPOPSession.h */; };
+ C64EA777169E859600778456 /* MCAttachment.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6E1169E847800778456 /* MCAttachment.h */; };
+ C64EA778169E859600778456 /* MCMessageBuilder.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6E3169E847800778456 /* MCMessageBuilder.h */; };
+ C64EA779169E859600778456 /* MCMessageParser.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6E5169E847800778456 /* MCMessageParser.h */; };
+ C64EA77A169E859600778456 /* MCMessagePart.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6E7169E847800778456 /* MCMessagePart.h */; };
+ C64EA77B169E859600778456 /* MCMultipart.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6E9169E847800778456 /* MCMultipart.h */; };
+ C64EA77C169E859600778456 /* MCRFC822.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6EA169E847800778456 /* MCRFC822.h */; };
+ C64EA77D169E859600778456 /* MCSMTP.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6EC169E847800778456 /* MCSMTP.h */; };
+ C64EA77E169E859600778456 /* MCSMTPProgressCallback.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6ED169E847800778456 /* MCSMTPProgressCallback.h */; };
+ C64EA77F169E859600778456 /* MCSMTPSession.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA6EF169E847800778456 /* MCSMTPSession.h */; };
+ C64EA781169E89F600778456 /* MCSMTPSession.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA6EE169E847800778456 /* MCSMTPSession.cc */; };
+ C64EA783169F241300778456 /* MCCore.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA782169F23AB00778456 /* MCCore.h */; };
+ C64EA784169F24E400778456 /* MCSMTPAsyncSession.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA68F169E847800778456 /* MCSMTPAsyncSession.cc */; };
+ C64EA787169F252C00778456 /* MCSMTPSendWithRecipientOperation.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA785169F252C00778456 /* MCSMTPSendWithRecipientOperation.cc */; };
+ C64EA790169F259200778456 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C64EA78F169F259200778456 /* Foundation.framework */; };
+ C64EA79B169F259F00778456 /* libmailcore2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C64EA537169E772200778456 /* libmailcore2.a */; };
+ C64EA79E169F29A700778456 /* MCSMTPSendWithDataOperation.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA79C169F29A700778456 /* MCSMTPSendWithDataOperation.cc */; };
+ C64EA7A1169F29D900778456 /* MCSMTPSendWithBuilderOperation.cc in Sources */ = {isa = PBXBuildFile; fileRef = C64EA79F169F29D900778456 /* MCSMTPSendWithBuilderOperation.cc */; };
+ C64EA7A5169F2A6100778456 /* mailcore.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C64EA7A4169F2A3E00778456 /* mailcore.h */; };
+ C64EA7AB16A00AF600778456 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = C64EA7AA16A00AF600778456 /* main.mm */; };
+ C64EA7B116A00BBB00778456 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C64EA7B016A00BBB00778456 /* CoreServices.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ C64EA7A2169F2A1D00778456 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C64EA52E169E772200778456 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C64EA536169E772200778456;
+ remoteInfo = mailcore2;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ C64EA74B169E854B00778456 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = include/mailcore;
+ dstSubfolderSpec = 16;
+ files = (
+ C64EA74C169E859600778456 /* IMAPAsyncSession.h in CopyFiles */,
+ C64EA74D169E859600778456 /* MCSMTPAsyncSession.h in CopyFiles */,
+ C64EA74E169E859600778456 /* MCAbstract.h in CopyFiles */,
+ C64EA74F169E859600778456 /* MCAbstractMessage.h in CopyFiles */,
+ C64EA750169E859600778456 /* MCAbstractMessagePart.h in CopyFiles */,
+ C64EA751169E859600778456 /* MCAbstractMultipart.h in CopyFiles */,
+ C64EA752169E859600778456 /* MCAbstractPart.h in CopyFiles */,
+ C64EA7A5169F2A6100778456 /* mailcore.h in CopyFiles */,
+ C64EA753169E859600778456 /* MCAddress.h in CopyFiles */,
+ C64EA754169E859600778456 /* MCMessageConstants.h in CopyFiles */,
+ C64EA755169E859600778456 /* MCMessageHeader.h in CopyFiles */,
+ C64EA756169E859600778456 /* MCAutoreleasePool.h in CopyFiles */,
+ C64EA757169E859600778456 /* MCBaseTypes.h in CopyFiles */,
+ C64EA758169E859600778456 /* MCArray.h in CopyFiles */,
+ C64EA759169E859600778456 /* MCAssert.h in CopyFiles */,
+ C64EA75A169E859600778456 /* MCData.h in CopyFiles */,
+ C64EA75B169E859600778456 /* MCHash.h in CopyFiles */,
+ C64EA75C169E859600778456 /* MCHashMap.h in CopyFiles */,
+ C64EA75D169E859600778456 /* MCLog.h in CopyFiles */,
+ C64EA75E169E859600778456 /* MCObject.h in CopyFiles */,
+ C64EA75F169E859600778456 /* MCRange.h in CopyFiles */,
+ C64EA760169E859600778456 /* MCSet.h in CopyFiles */,
+ C64EA761169E859600778456 /* MCString.h in CopyFiles */,
+ C64EA762169E859600778456 /* MCUtils.h in CopyFiles */,
+ C64EA763169E859600778456 /* MCValue.h in CopyFiles */,
+ C64EA783169F241300778456 /* MCCore.h in CopyFiles */,
+ C64EA764169E859600778456 /* MCMainThread.h in CopyFiles */,
+ C64EA765169E859600778456 /* MCOperation.h in CopyFiles */,
+ C64EA766169E859600778456 /* MCOperationCallback.h in CopyFiles */,
+ C64EA767169E859600778456 /* MCOperationQueue.h in CopyFiles */,
+ C64EA768169E859600778456 /* MCIMAP.h in CopyFiles */,
+ C64EA769169E859600778456 /* MCIMAPFolder.h in CopyFiles */,
+ C64EA76A169E859600778456 /* MCIMAPMessage.h in CopyFiles */,
+ C64EA76B169E859600778456 /* MCIMAPMessagePart.h in CopyFiles */,
+ C64EA76C169E859600778456 /* MCIMAPMultipart.h in CopyFiles */,
+ C64EA76D169E859600778456 /* MCIMAPNamespace.h in CopyFiles */,
+ C64EA76E169E859600778456 /* MCIMAPNamespaceItem.h in CopyFiles */,
+ C64EA76F169E859600778456 /* MCIMAPPart.h in CopyFiles */,
+ C64EA770169E859600778456 /* MCIMAPProgressCallback.h in CopyFiles */,
+ C64EA771169E859600778456 /* MCIMAPSearchExpression.h in CopyFiles */,
+ C64EA772169E859600778456 /* MCIMAPSession.h in CopyFiles */,
+ C64EA773169E859600778456 /* MCPOP.h in CopyFiles */,
+ C64EA774169E859600778456 /* MCPOPMessageInfo.h in CopyFiles */,
+ C64EA775169E859600778456 /* MCPOPProgressCallback.h in CopyFiles */,
+ C64EA776169E859600778456 /* MCPOPSession.h in CopyFiles */,
+ C64EA777169E859600778456 /* MCAttachment.h in CopyFiles */,
+ C64EA778169E859600778456 /* MCMessageBuilder.h in CopyFiles */,
+ C64EA779169E859600778456 /* MCMessageParser.h in CopyFiles */,
+ C64EA77A169E859600778456 /* MCMessagePart.h in CopyFiles */,
+ C64EA77B169E859600778456 /* MCMultipart.h in CopyFiles */,
+ C64EA77C169E859600778456 /* MCRFC822.h in CopyFiles */,
+ C64EA77D169E859600778456 /* MCSMTP.h in CopyFiles */,
+ C64EA77E169E859600778456 /* MCSMTPProgressCallback.h in CopyFiles */,
+ C64EA77F169E859600778456 /* MCSMTPSession.h in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C64EA78A169F259200778456 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ C64EA537169E772200778456 /* libmailcore2.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libmailcore2.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ C64EA68C169E847800778456 /* IMAPAsyncSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IMAPAsyncSession.h; sourceTree = "<group>"; };
+ C64EA68F169E847800778456 /* MCSMTPAsyncSession.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCSMTPAsyncSession.cc; sourceTree = "<group>"; };
+ C64EA690169E847800778456 /* MCSMTPAsyncSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCSMTPAsyncSession.h; sourceTree = "<group>"; };
+ C64EA693169E847800778456 /* MCAbstract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCAbstract.h; sourceTree = "<group>"; };
+ C64EA694169E847800778456 /* MCAbstractMessage.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = MCAbstractMessage.cc; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+ C64EA695169E847800778456 /* MCAbstractMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = MCAbstractMessage.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
+ C64EA696169E847800778456 /* MCAbstractMessagePart.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = MCAbstractMessagePart.cc; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+ C64EA697169E847800778456 /* MCAbstractMessagePart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCAbstractMessagePart.h; sourceTree = "<group>"; };
+ C64EA698169E847800778456 /* MCAbstractMultipart.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCAbstractMultipart.cc; sourceTree = "<group>"; };
+ C64EA699169E847800778456 /* MCAbstractMultipart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCAbstractMultipart.h; sourceTree = "<group>"; };
+ C64EA69A169E847800778456 /* MCAbstractPart.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCAbstractPart.cc; sourceTree = "<group>"; };
+ C64EA69B169E847800778456 /* MCAbstractPart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCAbstractPart.h; sourceTree = "<group>"; };
+ C64EA69C169E847800778456 /* MCAddress.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCAddress.cc; sourceTree = "<group>"; };
+ C64EA69D169E847800778456 /* MCAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCAddress.h; sourceTree = "<group>"; };
+ C64EA69E169E847800778456 /* MCMessageConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCMessageConstants.h; sourceTree = "<group>"; };
+ C64EA69F169E847800778456 /* MCMessageHeader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCMessageHeader.cc; sourceTree = "<group>"; };
+ C64EA6A0169E847800778456 /* MCMessageHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCMessageHeader.h; sourceTree = "<group>"; };
+ C64EA6A2169E847800778456 /* MCAutoreleasePool.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCAutoreleasePool.cc; sourceTree = "<group>"; };
+ C64EA6A3169E847800778456 /* MCAutoreleasePool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCAutoreleasePool.h; sourceTree = "<group>"; };
+ C64EA6A4169E847800778456 /* MCBaseTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCBaseTypes.h; sourceTree = "<group>"; };
+ C64EA6A5169E847800778456 /* MCArray.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCArray.cc; sourceTree = "<group>"; };
+ C64EA6A6169E847800778456 /* MCArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCArray.h; sourceTree = "<group>"; };
+ C64EA6A7169E847800778456 /* MCAssert.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCAssert.cc; sourceTree = "<group>"; };
+ C64EA6A8169E847800778456 /* MCAssert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCAssert.h; sourceTree = "<group>"; };
+ C64EA6A9169E847800778456 /* MCData.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCData.cc; sourceTree = "<group>"; };
+ C64EA6AA169E847800778456 /* MCData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCData.h; sourceTree = "<group>"; };
+ C64EA6AB169E847800778456 /* MCHash.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCHash.cc; sourceTree = "<group>"; };
+ C64EA6AC169E847800778456 /* MCHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCHash.h; sourceTree = "<group>"; };
+ C64EA6AD169E847800778456 /* MCHashMap.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCHashMap.cc; sourceTree = "<group>"; };
+ C64EA6AE169E847800778456 /* MCHashMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCHashMap.h; sourceTree = "<group>"; };
+ C64EA6AF169E847800778456 /* MCLog.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCLog.cc; sourceTree = "<group>"; };
+ C64EA6B0169E847800778456 /* MCLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCLog.h; sourceTree = "<group>"; };
+ C64EA6B1169E847800778456 /* MCObject.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCObject.cc; sourceTree = "<group>"; };
+ C64EA6B2169E847800778456 /* MCObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCObject.h; sourceTree = "<group>"; };
+ C64EA6B3169E847800778456 /* MCRange.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCRange.cc; sourceTree = "<group>"; };
+ C64EA6B4169E847800778456 /* MCRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCRange.h; sourceTree = "<group>"; };
+ C64EA6B5169E847800778456 /* MCSet.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCSet.cc; sourceTree = "<group>"; };
+ C64EA6B6169E847800778456 /* MCSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCSet.h; sourceTree = "<group>"; };
+ C64EA6B7169E847800778456 /* MCString.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCString.cc; sourceTree = "<group>"; };
+ C64EA6B8169E847800778456 /* MCString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCString.h; sourceTree = "<group>"; };
+ C64EA6B9169E847800778456 /* MCUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCUtils.h; sourceTree = "<group>"; };
+ C64EA6BA169E847800778456 /* MCValue.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCValue.cc; sourceTree = "<group>"; };
+ C64EA6BB169E847800778456 /* MCValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCValue.h; sourceTree = "<group>"; };
+ C64EA6BC169E847800778456 /* MCMainThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCMainThread.h; sourceTree = "<group>"; };
+ C64EA6BD169E847800778456 /* MCMainThread.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MCMainThread.mm; sourceTree = "<group>"; };
+ C64EA6BE169E847800778456 /* MCOperation.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCOperation.cc; sourceTree = "<group>"; };
+ C64EA6BF169E847800778456 /* MCOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCOperation.h; sourceTree = "<group>"; };
+ C64EA6C0169E847800778456 /* MCOperationCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCOperationCallback.h; sourceTree = "<group>"; };
+ C64EA6C1169E847800778456 /* MCOperationQueue.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCOperationQueue.cc; sourceTree = "<group>"; };
+ C64EA6C2169E847800778456 /* MCOperationQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCOperationQueue.h; sourceTree = "<group>"; };
+ C64EA6C4169E847800778456 /* MCIMAP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCIMAP.h; sourceTree = "<group>"; };
+ C64EA6C5169E847800778456 /* MCIMAPFolder.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCIMAPFolder.cc; sourceTree = "<group>"; };
+ C64EA6C6169E847800778456 /* MCIMAPFolder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCIMAPFolder.h; sourceTree = "<group>"; };
+ C64EA6C7169E847800778456 /* MCIMAPMessage.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCIMAPMessage.cc; sourceTree = "<group>"; };
+ C64EA6C8169E847800778456 /* MCIMAPMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCIMAPMessage.h; sourceTree = "<group>"; };
+ C64EA6C9169E847800778456 /* MCIMAPMessagePart.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCIMAPMessagePart.cc; sourceTree = "<group>"; };
+ C64EA6CA169E847800778456 /* MCIMAPMessagePart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCIMAPMessagePart.h; sourceTree = "<group>"; };
+ C64EA6CB169E847800778456 /* MCIMAPMultipart.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCIMAPMultipart.cc; sourceTree = "<group>"; };
+ C64EA6CC169E847800778456 /* MCIMAPMultipart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCIMAPMultipart.h; sourceTree = "<group>"; };
+ C64EA6CD169E847800778456 /* MCIMAPNamespace.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCIMAPNamespace.cc; sourceTree = "<group>"; };
+ C64EA6CE169E847800778456 /* MCIMAPNamespace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCIMAPNamespace.h; sourceTree = "<group>"; };
+ C64EA6CF169E847800778456 /* MCIMAPNamespaceItem.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCIMAPNamespaceItem.cc; sourceTree = "<group>"; };
+ C64EA6D0169E847800778456 /* MCIMAPNamespaceItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCIMAPNamespaceItem.h; sourceTree = "<group>"; };
+ C64EA6D1169E847800778456 /* MCIMAPPart.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCIMAPPart.cc; sourceTree = "<group>"; };
+ C64EA6D2169E847800778456 /* MCIMAPPart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCIMAPPart.h; sourceTree = "<group>"; };
+ C64EA6D3169E847800778456 /* MCIMAPProgressCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCIMAPProgressCallback.h; sourceTree = "<group>"; };
+ C64EA6D4169E847800778456 /* MCIMAPSearchExpression.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCIMAPSearchExpression.cc; sourceTree = "<group>"; };
+ C64EA6D5169E847800778456 /* MCIMAPSearchExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCIMAPSearchExpression.h; sourceTree = "<group>"; };
+ C64EA6D6169E847800778456 /* MCIMAPSession.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCIMAPSession.cc; sourceTree = "<group>"; };
+ C64EA6D7169E847800778456 /* MCIMAPSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCIMAPSession.h; sourceTree = "<group>"; };
+ C64EA6D9169E847800778456 /* MCPOP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCPOP.h; sourceTree = "<group>"; };
+ C64EA6DA169E847800778456 /* MCPOPMessageInfo.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCPOPMessageInfo.cc; sourceTree = "<group>"; };
+ C64EA6DB169E847800778456 /* MCPOPMessageInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCPOPMessageInfo.h; sourceTree = "<group>"; };
+ C64EA6DC169E847800778456 /* MCPOPProgressCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCPOPProgressCallback.h; sourceTree = "<group>"; };
+ C64EA6DD169E847800778456 /* MCPOPSession.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCPOPSession.cc; sourceTree = "<group>"; };
+ C64EA6DE169E847800778456 /* MCPOPSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCPOPSession.h; sourceTree = "<group>"; };
+ C64EA6E0169E847800778456 /* MCAttachment.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCAttachment.cc; sourceTree = "<group>"; };
+ C64EA6E1169E847800778456 /* MCAttachment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCAttachment.h; sourceTree = "<group>"; };
+ C64EA6E2169E847800778456 /* MCMessageBuilder.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCMessageBuilder.cc; sourceTree = "<group>"; };
+ C64EA6E3169E847800778456 /* MCMessageBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCMessageBuilder.h; sourceTree = "<group>"; };
+ C64EA6E4169E847800778456 /* MCMessageParser.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCMessageParser.cc; sourceTree = "<group>"; };
+ C64EA6E5169E847800778456 /* MCMessageParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCMessageParser.h; sourceTree = "<group>"; };
+ C64EA6E6169E847800778456 /* MCMessagePart.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCMessagePart.cc; sourceTree = "<group>"; };
+ C64EA6E7169E847800778456 /* MCMessagePart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCMessagePart.h; sourceTree = "<group>"; };
+ C64EA6E8169E847800778456 /* MCMultipart.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCMultipart.cc; sourceTree = "<group>"; };
+ C64EA6E9169E847800778456 /* MCMultipart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCMultipart.h; sourceTree = "<group>"; };
+ C64EA6EA169E847800778456 /* MCRFC822.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCRFC822.h; sourceTree = "<group>"; };
+ C64EA6EC169E847800778456 /* MCSMTP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCSMTP.h; sourceTree = "<group>"; };
+ C64EA6ED169E847800778456 /* MCSMTPProgressCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCSMTPProgressCallback.h; sourceTree = "<group>"; };
+ C64EA6EE169E847800778456 /* MCSMTPSession.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCSMTPSession.cc; sourceTree = "<group>"; };
+ C64EA6EF169E847800778456 /* MCSMTPSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCSMTPSession.h; sourceTree = "<group>"; };
+ C64EA782169F23AB00778456 /* MCCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCCore.h; sourceTree = "<group>"; };
+ C64EA785169F252C00778456 /* MCSMTPSendWithRecipientOperation.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCSMTPSendWithRecipientOperation.cc; sourceTree = "<group>"; };
+ C64EA786169F252C00778456 /* MCSMTPSendWithRecipientOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCSMTPSendWithRecipientOperation.h; sourceTree = "<group>"; };
+ C64EA78C169F259200778456 /* tests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tests; sourceTree = BUILT_PRODUCTS_DIR; };
+ C64EA78F169F259200778456 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ C64EA79C169F29A700778456 /* MCSMTPSendWithDataOperation.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCSMTPSendWithDataOperation.cc; sourceTree = "<group>"; };
+ C64EA79D169F29A700778456 /* MCSMTPSendWithDataOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCSMTPSendWithDataOperation.h; sourceTree = "<group>"; };
+ C64EA79F169F29D900778456 /* MCSMTPSendWithBuilderOperation.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCSMTPSendWithBuilderOperation.cc; sourceTree = "<group>"; };
+ C64EA7A0169F29D900778456 /* MCSMTPSendWithBuilderOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCSMTPSendWithBuilderOperation.h; sourceTree = "<group>"; };
+ C64EA7A4169F2A3E00778456 /* mailcore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mailcore.h; sourceTree = "<group>"; };
+ C64EA7AA16A00AF600778456 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
+ C64EA7B016A00BBB00778456 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ C64EA534169E772200778456 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C64EA789169F259200778456 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C64EA7B116A00BBB00778456 /* CoreServices.framework in Frameworks */,
+ C64EA790169F259200778456 /* Foundation.framework in Frameworks */,
+ C64EA79B169F259F00778456 /* libmailcore2.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ C64EA52C169E772200778456 = {
+ isa = PBXGroup;
+ children = (
+ C64EA7B016A00BBB00778456 /* CoreServices.framework */,
+ C64EA545169E78B100778456 /* src */,
+ C64EA7A916A00AF400778456 /* tests */,
+ C64EA78E169F259200778456 /* Frameworks */,
+ C64EA538169E772200778456 /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ C64EA538169E772200778456 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ C64EA537169E772200778456 /* libmailcore2.a */,
+ C64EA78C169F259200778456 /* tests */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ C64EA545169E78B100778456 /* src */ = {
+ isa = PBXGroup;
+ children = (
+ C64EA68A169E847800778456 /* async */,
+ C64EA691169E847800778456 /* core */,
+ C64EA7A4169F2A3E00778456 /* mailcore.h */,
+ );
+ name = src;
+ path = ../src;
+ sourceTree = "<group>";
+ };
+ C64EA68A169E847800778456 /* async */ = {
+ isa = PBXGroup;
+ children = (
+ C64EA68B169E847800778456 /* imap */,
+ C64EA68D169E847800778456 /* pop */,
+ C64EA68E169E847800778456 /* smtp */,
+ );
+ path = async;
+ sourceTree = "<group>";
+ };
+ C64EA68B169E847800778456 /* imap */ = {
+ isa = PBXGroup;
+ children = (
+ C64EA68C169E847800778456 /* IMAPAsyncSession.h */,
+ );
+ path = imap;
+ sourceTree = "<group>";
+ };
+ C64EA68D169E847800778456 /* pop */ = {
+ isa = PBXGroup;
+ children = (
+ );
+ path = pop;
+ sourceTree = "<group>";
+ };
+ C64EA68E169E847800778456 /* smtp */ = {
+ isa = PBXGroup;
+ children = (
+ C64EA68F169E847800778456 /* MCSMTPAsyncSession.cc */,
+ C64EA690169E847800778456 /* MCSMTPAsyncSession.h */,
+ C64EA785169F252C00778456 /* MCSMTPSendWithRecipientOperation.cc */,
+ C64EA786169F252C00778456 /* MCSMTPSendWithRecipientOperation.h */,
+ C64EA79C169F29A700778456 /* MCSMTPSendWithDataOperation.cc */,
+ C64EA79D169F29A700778456 /* MCSMTPSendWithDataOperation.h */,
+ C64EA79F169F29D900778456 /* MCSMTPSendWithBuilderOperation.cc */,
+ C64EA7A0169F29D900778456 /* MCSMTPSendWithBuilderOperation.h */,
+ );
+ path = smtp;
+ sourceTree = "<group>";
+ };
+ C64EA691169E847800778456 /* core */ = {
+ isa = PBXGroup;
+ children = (
+ C64EA692169E847800778456 /* abstract */,
+ C64EA6A1169E847800778456 /* basetypes */,
+ C64EA6C3169E847800778456 /* imap */,
+ C64EA6D8169E847800778456 /* pop */,
+ C64EA6DF169E847800778456 /* rfc822 */,
+ C64EA6EB169E847800778456 /* smtp */,
+ C64EA782169F23AB00778456 /* MCCore.h */,
+ );
+ path = core;
+ sourceTree = "<group>";
+ };
+ C64EA692169E847800778456 /* abstract */ = {
+ isa = PBXGroup;
+ children = (
+ C64EA693169E847800778456 /* MCAbstract.h */,
+ C64EA694169E847800778456 /* MCAbstractMessage.cc */,
+ C64EA695169E847800778456 /* MCAbstractMessage.h */,
+ C64EA696169E847800778456 /* MCAbstractMessagePart.cc */,
+ C64EA697169E847800778456 /* MCAbstractMessagePart.h */,
+ C64EA698169E847800778456 /* MCAbstractMultipart.cc */,
+ C64EA699169E847800778456 /* MCAbstractMultipart.h */,
+ C64EA69A169E847800778456 /* MCAbstractPart.cc */,
+ C64EA69B169E847800778456 /* MCAbstractPart.h */,
+ C64EA69C169E847800778456 /* MCAddress.cc */,
+ C64EA69D169E847800778456 /* MCAddress.h */,
+ C64EA69E169E847800778456 /* MCMessageConstants.h */,
+ C64EA69F169E847800778456 /* MCMessageHeader.cc */,
+ C64EA6A0169E847800778456 /* MCMessageHeader.h */,
+ );
+ path = abstract;
+ sourceTree = "<group>";
+ };
+ C64EA6A1169E847800778456 /* basetypes */ = {
+ isa = PBXGroup;
+ children = (
+ C64EA6A2169E847800778456 /* MCAutoreleasePool.cc */,
+ C64EA6A3169E847800778456 /* MCAutoreleasePool.h */,
+ C64EA6A4169E847800778456 /* MCBaseTypes.h */,
+ C64EA6A5169E847800778456 /* MCArray.cc */,
+ C64EA6A6169E847800778456 /* MCArray.h */,
+ C64EA6A7169E847800778456 /* MCAssert.cc */,
+ C64EA6A8169E847800778456 /* MCAssert.h */,
+ C64EA6A9169E847800778456 /* MCData.cc */,
+ C64EA6AA169E847800778456 /* MCData.h */,
+ C64EA6AB169E847800778456 /* MCHash.cc */,
+ C64EA6AC169E847800778456 /* MCHash.h */,
+ C64EA6AD169E847800778456 /* MCHashMap.cc */,
+ C64EA6AE169E847800778456 /* MCHashMap.h */,
+ C64EA6AF169E847800778456 /* MCLog.cc */,
+ C64EA6B0169E847800778456 /* MCLog.h */,
+ C64EA6B1169E847800778456 /* MCObject.cc */,
+ C64EA6B2169E847800778456 /* MCObject.h */,
+ C64EA6B3169E847800778456 /* MCRange.cc */,
+ C64EA6B4169E847800778456 /* MCRange.h */,
+ C64EA6B5169E847800778456 /* MCSet.cc */,
+ C64EA6B6169E847800778456 /* MCSet.h */,
+ C64EA6B7169E847800778456 /* MCString.cc */,
+ C64EA6B8169E847800778456 /* MCString.h */,
+ C64EA6B9169E847800778456 /* MCUtils.h */,
+ C64EA6BA169E847800778456 /* MCValue.cc */,
+ C64EA6BB169E847800778456 /* MCValue.h */,
+ C64EA6BC169E847800778456 /* MCMainThread.h */,
+ C64EA6BD169E847800778456 /* MCMainThread.mm */,
+ C64EA6BE169E847800778456 /* MCOperation.cc */,
+ C64EA6BF169E847800778456 /* MCOperation.h */,
+ C64EA6C0169E847800778456 /* MCOperationCallback.h */,
+ C64EA6C1169E847800778456 /* MCOperationQueue.cc */,
+ C64EA6C2169E847800778456 /* MCOperationQueue.h */,
+ );
+ path = basetypes;
+ sourceTree = "<group>";
+ };
+ C64EA6C3169E847800778456 /* imap */ = {
+ isa = PBXGroup;
+ children = (
+ C64EA6C4169E847800778456 /* MCIMAP.h */,
+ C64EA6C5169E847800778456 /* MCIMAPFolder.cc */,
+ C64EA6C6169E847800778456 /* MCIMAPFolder.h */,
+ C64EA6C7169E847800778456 /* MCIMAPMessage.cc */,
+ C64EA6C8169E847800778456 /* MCIMAPMessage.h */,
+ C64EA6C9169E847800778456 /* MCIMAPMessagePart.cc */,
+ C64EA6CA169E847800778456 /* MCIMAPMessagePart.h */,
+ C64EA6CB169E847800778456 /* MCIMAPMultipart.cc */,
+ C64EA6CC169E847800778456 /* MCIMAPMultipart.h */,
+ C64EA6CD169E847800778456 /* MCIMAPNamespace.cc */,
+ C64EA6CE169E847800778456 /* MCIMAPNamespace.h */,
+ C64EA6CF169E847800778456 /* MCIMAPNamespaceItem.cc */,
+ C64EA6D0169E847800778456 /* MCIMAPNamespaceItem.h */,
+ C64EA6D1169E847800778456 /* MCIMAPPart.cc */,
+ C64EA6D2169E847800778456 /* MCIMAPPart.h */,
+ C64EA6D3169E847800778456 /* MCIMAPProgressCallback.h */,
+ C64EA6D4169E847800778456 /* MCIMAPSearchExpression.cc */,
+ C64EA6D5169E847800778456 /* MCIMAPSearchExpression.h */,
+ C64EA6D6169E847800778456 /* MCIMAPSession.cc */,
+ C64EA6D7169E847800778456 /* MCIMAPSession.h */,
+ );
+ path = imap;
+ sourceTree = "<group>";
+ };
+ C64EA6D8169E847800778456 /* pop */ = {
+ isa = PBXGroup;
+ children = (
+ C64EA6D9169E847800778456 /* MCPOP.h */,
+ C64EA6DA169E847800778456 /* MCPOPMessageInfo.cc */,
+ C64EA6DB169E847800778456 /* MCPOPMessageInfo.h */,
+ C64EA6DC169E847800778456 /* MCPOPProgressCallback.h */,
+ C64EA6DD169E847800778456 /* MCPOPSession.cc */,
+ C64EA6DE169E847800778456 /* MCPOPSession.h */,
+ );
+ path = pop;
+ sourceTree = "<group>";
+ };
+ C64EA6DF169E847800778456 /* rfc822 */ = {
+ isa = PBXGroup;
+ children = (
+ C64EA6E0169E847800778456 /* MCAttachment.cc */,
+ C64EA6E1169E847800778456 /* MCAttachment.h */,
+ C64EA6E2169E847800778456 /* MCMessageBuilder.cc */,
+ C64EA6E3169E847800778456 /* MCMessageBuilder.h */,
+ C64EA6E4169E847800778456 /* MCMessageParser.cc */,
+ C64EA6E5169E847800778456 /* MCMessageParser.h */,
+ C64EA6E6169E847800778456 /* MCMessagePart.cc */,
+ C64EA6E7169E847800778456 /* MCMessagePart.h */,
+ C64EA6E8169E847800778456 /* MCMultipart.cc */,
+ C64EA6E9169E847800778456 /* MCMultipart.h */,
+ C64EA6EA169E847800778456 /* MCRFC822.h */,
+ );
+ path = rfc822;
+ sourceTree = "<group>";
+ };
+ C64EA6EB169E847800778456 /* smtp */ = {
+ isa = PBXGroup;
+ children = (
+ C64EA6EC169E847800778456 /* MCSMTP.h */,
+ C64EA6ED169E847800778456 /* MCSMTPProgressCallback.h */,
+ C64EA6EE169E847800778456 /* MCSMTPSession.cc */,
+ C64EA6EF169E847800778456 /* MCSMTPSession.h */,
+ );
+ path = smtp;
+ sourceTree = "<group>";
+ };
+ C64EA78E169F259200778456 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ C64EA78F169F259200778456 /* Foundation.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ C64EA7A916A00AF400778456 /* tests */ = {
+ isa = PBXGroup;
+ children = (
+ C64EA7AA16A00AF600778456 /* main.mm */,
+ );
+ name = tests;
+ path = ../tests;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ C64EA536169E772200778456 /* mailcore2 */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C64EA53B169E772200778456 /* Build configuration list for PBXNativeTarget "mailcore2" */;
+ buildPhases = (
+ C64EA780169E867600778456 /* ShellScript */,
+ C64EA74B169E854B00778456 /* CopyFiles */,
+ C64EA533169E772200778456 /* Sources */,
+ C64EA534169E772200778456 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mailcore2;
+ productName = mailcore;
+ productReference = C64EA537169E772200778456 /* libmailcore2.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ C64EA78B169F259200778456 /* tests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C64EA798169F259300778456 /* Build configuration list for PBXNativeTarget "tests" */;
+ buildPhases = (
+ C64EA788169F259200778456 /* Sources */,
+ C64EA789169F259200778456 /* Frameworks */,
+ C64EA78A169F259200778456 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ C64EA7A3169F2A1D00778456 /* PBXTargetDependency */,
+ );
+ name = tests;
+ productName = tests;
+ productReference = C64EA78C169F259200778456 /* tests */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ C64EA52E169E772200778456 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0450;
+ ORGANIZATIONNAME = MailCore;
+ };
+ buildConfigurationList = C64EA531169E772200778456 /* Build configuration list for PBXProject "mailcore2" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = C64EA52C169E772200778456;
+ productRefGroup = C64EA538169E772200778456 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ C64EA536169E772200778456 /* mailcore2 */,
+ C64EA78B169F259200778456 /* tests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ C64EA780169E867600778456 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ C64EA533169E772200778456 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C64EA6F4169E847800778456 /* MCAbstractMessage.cc in Sources */,
+ C64EA6F6169E847800778456 /* MCAbstractMessagePart.cc in Sources */,
+ C64EA6F8169E847800778456 /* MCAbstractMultipart.cc in Sources */,
+ C64EA6FA169E847800778456 /* MCAbstractPart.cc in Sources */,
+ C64EA6FC169E847800778456 /* MCAddress.cc in Sources */,
+ C64EA6FF169E847800778456 /* MCMessageHeader.cc in Sources */,
+ C64EA701169E847800778456 /* MCAutoreleasePool.cc in Sources */,
+ C64EA704169E847800778456 /* MCArray.cc in Sources */,
+ C64EA706169E847800778456 /* MCAssert.cc in Sources */,
+ C64EA708169E847800778456 /* MCData.cc in Sources */,
+ C64EA70A169E847800778456 /* MCHash.cc in Sources */,
+ C64EA70C169E847800778456 /* MCHashMap.cc in Sources */,
+ C64EA70E169E847800778456 /* MCLog.cc in Sources */,
+ C64EA710169E847800778456 /* MCObject.cc in Sources */,
+ C64EA712169E847800778456 /* MCRange.cc in Sources */,
+ C64EA714169E847800778456 /* MCSet.cc in Sources */,
+ C64EA716169E847800778456 /* MCString.cc in Sources */,
+ C64EA719169E847800778456 /* MCValue.cc in Sources */,
+ C64EA71C169E847800778456 /* MCMainThread.mm in Sources */,
+ C64EA71D169E847800778456 /* MCOperation.cc in Sources */,
+ C64EA720169E847800778456 /* MCOperationQueue.cc in Sources */,
+ C64EA723169E847800778456 /* MCIMAPFolder.cc in Sources */,
+ C64EA725169E847800778456 /* MCIMAPMessage.cc in Sources */,
+ C64EA727169E847800778456 /* MCIMAPMessagePart.cc in Sources */,
+ C64EA729169E847800778456 /* MCIMAPMultipart.cc in Sources */,
+ C64EA72B169E847800778456 /* MCIMAPNamespace.cc in Sources */,
+ C64EA72D169E847800778456 /* MCIMAPNamespaceItem.cc in Sources */,
+ C64EA72F169E847800778456 /* MCIMAPPart.cc in Sources */,
+ C64EA732169E847800778456 /* MCIMAPSearchExpression.cc in Sources */,
+ C64EA734169E847800778456 /* MCIMAPSession.cc in Sources */,
+ C64EA737169E847800778456 /* MCPOPMessageInfo.cc in Sources */,
+ C64EA73A169E847800778456 /* MCPOPSession.cc in Sources */,
+ C64EA73C169E847800778456 /* MCAttachment.cc in Sources */,
+ C64EA73E169E847800778456 /* MCMessageBuilder.cc in Sources */,
+ C64EA740169E847800778456 /* MCMessageParser.cc in Sources */,
+ C64EA742169E847800778456 /* MCMessagePart.cc in Sources */,
+ C64EA744169E847800778456 /* MCMultipart.cc in Sources */,
+ C64EA781169E89F600778456 /* MCSMTPSession.cc in Sources */,
+ C64EA784169F24E400778456 /* MCSMTPAsyncSession.cc in Sources */,
+ C64EA787169F252C00778456 /* MCSMTPSendWithRecipientOperation.cc in Sources */,
+ C64EA79E169F29A700778456 /* MCSMTPSendWithDataOperation.cc in Sources */,
+ C64EA7A1169F29D900778456 /* MCSMTPSendWithBuilderOperation.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C64EA788169F259200778456 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C64EA7AB16A00AF600778456 /* main.mm in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ C64EA7A3169F2A1D00778456 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C64EA536169E772200778456 /* mailcore2 */;
+ targetProxy = C64EA7A2169F2A1D00778456 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ C64EA539169E772200778456 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_64_BIT)";
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/../Externals/libetpan/include",
+ "$(SRCROOT)/../Externals/icu4c/include",
+ /usr/include/libxml2,
+ );
+ LIBRARY_SEARCH_PATHS = (
+ "$(SRCROOT)/../Externals/libetpan/lib",
+ "$(SRCROOT)/../Externals/icu4c/lib",
+ );
+ MACOSX_DEPLOYMENT_TARGET = 10.8;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = macosx;
+ };
+ name = Debug;
+ };
+ C64EA53A169E772200778456 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_64_BIT)";
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/../Externals/libetpan/include",
+ "$(SRCROOT)/../Externals/icu4c/include",
+ /usr/include/libxml2,
+ );
+ LIBRARY_SEARCH_PATHS = (
+ "$(SRCROOT)/../Externals/libetpan/lib",
+ "$(SRCROOT)/../Externals/icu4c/lib",
+ );
+ MACOSX_DEPLOYMENT_TARGET = 10.8;
+ SDKROOT = macosx;
+ };
+ name = Release;
+ };
+ C64EA53C169E772200778456 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = lib;
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SRCROOT)/../src/core/basetypes\"",
+ "\"$(SRCROOT)/../src/core/abstract\"",
+ );
+ PRODUCT_NAME = mailcore2;
+ };
+ name = Debug;
+ };
+ C64EA53D169E772200778456 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = lib;
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SRCROOT)/../src/core/basetypes\"",
+ "\"$(SRCROOT)/../src/core/abstract\"",
+ );
+ PRODUCT_NAME = mailcore2;
+ };
+ name = Release;
+ };
+ C64EA799169F259300778456 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ OTHER_LDFLAGS = (
+ "-letpan",
+ "-licudata",
+ "-licui18n",
+ "-licuuc",
+ "-lxml2",
+ "-lssl",
+ "-lcrypto",
+ "-lsasl2",
+ "-liconv",
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ C64EA79A169F259300778456 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ OTHER_LDFLAGS = (
+ "-letpan",
+ "-licudata",
+ "-licui18n",
+ "-licuuc",
+ "-lxml2",
+ "-lssl",
+ "-lcrypto",
+ "-lsasl2",
+ "-liconv",
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ C64EA531169E772200778456 /* Build configuration list for PBXProject "mailcore2" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C64EA539169E772200778456 /* Debug */,
+ C64EA53A169E772200778456 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C64EA53B169E772200778456 /* Build configuration list for PBXNativeTarget "mailcore2" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C64EA53C169E772200778456 /* Debug */,
+ C64EA53D169E772200778456 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C64EA798169F259300778456 /* Build configuration list for PBXNativeTarget "tests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C64EA799169F259300778456 /* Debug */,
+ C64EA79A169F259300778456 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = C64EA52E169E772200778456 /* Project object */;
+}
diff --git a/scripts/.DS_Store b/scripts/.DS_Store
new file mode 100644
index 00000000..5008ddfc
--- /dev/null
+++ b/scripts/.DS_Store
Binary files differ
diff --git a/scripts/prepare-icu4c-macos.sh b/scripts/prepare-icu4c-macos.sh
new file mode 100755
index 00000000..e9ab7d37
--- /dev/null
+++ b/scripts/prepare-icu4c-macos.sh
@@ -0,0 +1,123 @@
+#!/bin/sh
+
+versionfolder='50.1.1'
+version='50_1_1'
+url="http://download.icu-project.org/files/icu4c/$versionfolder/icu4c-$version-src.tgz"
+package_filename="icu4c-$version-src.tgz"
+arch="x86_64"
+sysrootpath="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk"
+
+arch_flags=""
+for current_arch in $arch ; do
+ arch_flags="$arch_flags -arch $current_arch"
+done
+
+builddir="$HOME/MailCore-Builds/dependencies"
+BUILD_TIMESTAMP=`date +'%Y%m%d%H%M%S'`
+tempbuilddir="$builddir/workdir/$BUILD_TIMESTAMP"
+mkdir -p "$tempbuilddir"
+srcdir="$tempbuilddir/src"
+logdir="$tempbuilddir/log"
+resultdir="$builddir/builds"
+tmpdir="$tempbuilddir/tmp"
+
+if test -f "$resultdir/icu4c-$version.zip" ; then
+ echo install from cache
+ rm -rf ../Externals/icu4c
+ mkdir -p ../Externals/tmp
+ unzip -q "$resultdir/icu4c-$version.zip" -d ../Externals/tmp
+ mv "../Externals/tmp/icu4c-$version/icu4c" ../Externals
+ rm -rf ../Externals/tmp
+ exit 0
+fi
+
+mkdir -p "$resultdir"
+mkdir -p "$logdir"
+mkdir -p "$tmpdir"
+mkdir -p "$srcdir"
+
+pushd . >/dev/null
+
+echo get icu4c
+cd "$srcdir"
+if test -f "$builddir/downloads/$package_filename" ; then
+ cp "$builddir/downloads/$package_filename" .
+else
+ curl -O "$url"
+ if test x$? != x0 ; then
+ echo fetch of icu4c failed
+ exit 1
+ fi
+ mkdir -p "$builddir/downloads"
+ cp "$package_filename" "$builddir/downloads"
+fi
+
+tar xf "$package_filename"
+
+echo building icu4c
+cd "$srcdir/icu/source"
+for cur_arch in $arch ; do
+ cur_arch_flags="-arch $cur_arch"
+ echo building icu4c for $cur_arch
+ export CFLAGS="$cur_arch_flags -isysroot $sysrootpath -mfix-and-continue -mmacosx-version-min=10.7"
+ export CXXFLAGS="$cur_arch_flags -isysroot $sysrootpath -mfix-and-continue -mmacosx-version-min=10.7"
+ export LDLAGS="$cur_arch_flags -isysroot $sysrootpath -mfix-and-continue -mmacosx-version-min=10.7"
+ mkdir -p "$tmpdir/bin/icu4c-$cur_arch"
+ cd "$tmpdir/bin/icu4c-$cur_arch"
+ if test "x$cur_arch" = xx86_64 ; then
+ "$srcdir/icu/source/configure" --enable-static --disable-shared --with-data-packaging=archive >> "$logdir/icu4c-build.log"
+ else
+ "$srcdir/icu/source/configure" --host=$cur_arch-apple-darwin10.6.0 --enable-static --disable-shared --with-data-packaging=archive --with-cross-build=$tmpdir/crossbuild/icu4c-x86_64 >> "$logdir/icu4c-build.log"
+ fi
+ make >> "$logdir/icu4c-build.log"
+ make install "prefix=$tmpdir/bin/icu4c-$cur_arch" >> "$logdir/icu4c-build.log"
+ if test "x$cur_arch" = xx86_64 ; then
+ make install "prefix=$tmpdir/crossbuild/icu4c-$cur_arch" >> "$logdir/icu4c-build.log"
+ fi
+ if test x$? != x0 ; then
+ echo build of icu4c failed
+ exit 1
+ fi
+ #make distclean
+done
+
+mkdir -p "$tmpdir/bin/icu4c"
+cp -R "$tmpdir/bin/icu4c-x86_64/include" "$tmpdir/bin/icu4c"
+mkdir -p "$tmpdir/bin/icu4c/share/icu"
+cp "$tmpdir/bin/icu4c-x86_64/share/icu/$versionfolder/icudt50l.dat" "$tmpdir/bin/icu4c/share/icu"
+mkdir -p "$tmpdir/bin/icu4c/lib"
+cd "$tmpdir/bin"
+
+icui18n_paths=""
+icudata_paths=""
+icuuc_paths=""
+for cur_arch in $arch ; do
+ icui18n_paths="$icui18n_paths icu4c-$cur_arch/lib/libicui18n.a"
+ icudata_paths="$icudata_paths icu4c-$cur_arch/lib/libicudata.a"
+ icuuc_paths="$icuuc_paths icu4c-$cur_arch/lib/libicuuc.a"
+done
+lipo -create $icui18n_paths -output icu4c/lib/libicui18n.a
+lipo -create $icudata_paths -output icu4c/lib/libicudata.a
+lipo -create $icuuc_paths -output icu4c/lib/libicuuc.a
+
+cd "$tmpdir/bin"
+mkdir -p "icu4c-$version"
+mv icu4c "icu4c-$version"
+zip -qry "$resultdir/icu4c-$version.zip" "icu4c-$version"
+rm -f "$resultdir/icu4c-latest.zip"
+cd "$resultdir"
+ln -s "icu4c-$version.zip" "icu4c-latest.zip"
+
+echo build of icu4c-$version done
+
+popd
+
+rm -rf ../Externals/icu4c
+mkdir -p ../Externals/tmp
+unzip -q "$resultdir/icu4c-$version.zip" -d ../Externals/tmp
+mv "../Externals/tmp/icu4c-$version/icu4c" ../Externals
+rm -rf ../Externals/tmp
+
+echo cleaning
+rm -rf "$tempbuilddir"
+echo "$tempbuilddir"
diff --git a/scripts/prepare-libetpan-macos.sh b/scripts/prepare-libetpan-macos.sh
new file mode 100755
index 00000000..c6079c34
--- /dev/null
+++ b/scripts/prepare-libetpan-macos.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+arch="x86_64"
+sysrootpath="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk"
+url="https://github.com/dinhviethoa/libetpan.git"
+
+arch_flags=""
+for current_arch in $arch ; do
+ arch_flags="$arch_flags -arch $current_arch"
+done
+
+builddir="$HOME/MailCore-Builds/dependencies"
+BUILD_TIMESTAMP=`date +'%Y%m%d%H%M%S'`
+tempbuilddir="$builddir/workdir/$BUILD_TIMESTAMP"
+mkdir -p "$tempbuilddir"
+srcdir="$tempbuilddir/src"
+logdir="$tempbuilddir/log"
+resultdir="$builddir/builds"
+tmpdir="$tempbuilddir/tmp"
+
+mkdir -p "$resultdir"
+mkdir -p "$logdir"
+mkdir -p "$tmpdir"
+mkdir -p "$srcdir"
+
+pushd . >/dev/null
+cd "$builddir/downloads"
+if test -d libetpan ; then
+ cd libetpan
+ git pull --rebase
+else
+ git clone $url
+ cd libetpan
+fi
+version=`git rev-parse HEAD | cut -c1-10`
+
+if test -f "$resultdir/libetpan-$version.zip" ; then
+ echo install from cache
+ popd >/dev/null
+ rm -rf ../Externals/libetpan
+ mkdir -p ../Externals/tmp
+ unzip -q "$resultdir/libetpan-$version.zip" -d ../Externals/tmp
+ mv "../Externals/tmp/libetpan-$version/libetpan" ../Externals
+ rm -rf ../Externals/tmp
+ exit 0
+fi
+popd >/dev/null
+
+pushd . >/dev/null
+
+cp -R "$builddir/downloads/libetpan" "$srcdir/libetpan"
+echo building libetpan
+cd "$srcdir/libetpan"
+./autogen.sh
+cd "$srcdir/libetpan/build-mac"
+./update.sh
+
+xcodebuild -target "static libetpan" -configuration Release SYMROOT="$tmpdir/bin" OBJROOT="$tmpdir/obj"
+echo finished
+
+cd "$tmpdir/bin"
+mkdir -p "libetpan-$version/libetpan"
+mkdir -p "libetpan-$version/libetpan/lib"
+mv Release/include "libetpan-$version/libetpan"
+mv Release/libetpan.a "libetpan-$version/libetpan/lib"
+zip -qry "$resultdir/libetpan-$version.zip" "libetpan-$version"
+rm -f "$resultdir/libetpan-latest.zip"
+cd "$resultdir"
+ln -s "libetpan-$version.zip" "libetpan-latest.zip"
+
+echo build of libetpan-$version done
+
+popd >/dev/null
+
+rm -rf ../Externals/libetpan
+mkdir -p ../Externals/tmp
+unzip -q "$resultdir/libetpan-$version.zip" -d ../Externals/tmp
+mv "../Externals/tmp/libetpan-$version/libetpan" ../Externals
+rm -rf ../Externals/tmp
+
+echo cleaning
+rm -rf "$tempbuilddir"
+echo "$tempbuilddir"
diff --git a/scripts/prepare.sh b/scripts/prepare.sh
new file mode 100755
index 00000000..3e3cb9b1
--- /dev/null
+++ b/scripts/prepare.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+./prepare-icu4c-macos.sh
+./prepare-libetpan-macos.sh
diff --git a/src/async/imap/IMAPAsyncSession.h b/src/async/imap/IMAPAsyncSession.h
new file mode 100644
index 00000000..1e32bc46
--- /dev/null
+++ b/src/async/imap/IMAPAsyncSession.h
@@ -0,0 +1,122 @@
+#ifndef __MAILCORE_MCIMAPASYNCSESSION_H
+
+#define __MAILCORE_MCIMAPASYNCSESSION_H
+
+#include <mailcore/CBaseTypes.h>
+#include <mailcore/MessageConstants.h>
+
+namespace mailcore {
+
+ class IMAPOperation;
+ class IMAPFetchFoldersOperation;
+ class IMAPAppendOperation;
+ class IMAPCopyOperation;
+ class IMAPFetchMessagesOperation;
+ class IMAPIdleOperation;
+ class IMAPSession;
+ class IMAPNamespace;
+
+ class IMAPSession : public Object {
+ private:
+ String * mHostname;
+ unsigned int mPort;
+ String * mUsername;
+ String * mPassword;
+ AuthType mAuthType;
+ ConnectionType mConnectionType;
+ bool mCheckCertificateEnabled;
+ bool mVoIPEnabled;
+ char mDelimiter;
+ IMAPNamespace * mDefaultNamespace;
+
+ IMAPSession * mSession;
+
+ public:
+ IMAPAsyncSession();
+ virtual ~IMAPAsyncSession();
+
+ virtual String * className();
+
+ virtual void setHostname(String * hostname);
+ virtual String * hostname();
+
+ virtual void setPort(unsigned int port);
+ virtual unsigned int port();
+
+ virtual void setUsername(String * login);
+ virtual String * username();
+
+ virtual void setPassword(String * password);
+ virtual String * password();
+
+ virtual void setAuthType(AuthType authType);
+ virtual AuthType authType();
+
+ virtual void setConnectionType(ConnectionType connectionType);
+ virtual ConnectionType connectionType();
+
+ virtual void setTimeout(time_t timeout);
+ virtual time_t timeout();
+
+ virtual void setCheckCertificateEnabled(bool enabled);
+ virtual bool isCheckCertificateEnabled();
+
+ virtual void setVoIPEnabled(bool enabled);
+ virtual bool isVoIPEnabled();
+
+ virtual void setDelimiter(char delimiter);
+ virtual char delimiter();
+
+ virtual void setDefaultNamespace(IMAPNamespace * ns);
+ virtual IMAPNamespace * defaultNamespace();
+
+ virtual IMAPOperation * select(String * folder);
+
+ virtual IMAPFetchFoldersOperation * fetchSubscribedFolders();
+ virtual IMAPFetchFoldersOperation * fetchAllFolders();
+
+ virtual IMAPOperation * renameFolder(String * folder, String * otherName);
+ virtual IMAPOperation * deleteFolder(String * folder, ErrorCode * pError);
+ virtual IMAPOperation * createFolder(String * folder, ErrorCode * pError);
+
+ virtual IMAPOperation * subscribeFolder(String * folder, ErrorCode * pError);
+ virtual IMAPOperation * unsubscribeFolder(String * folder, ErrorCode * pError);
+
+ virtual IMAPAppendOperation * appendMessage(String * folder, Data * messageData, MessageFlag flags);
+
+ virtual IMAPCopyOperation * copyMessages(String * folder, Array * uidSet, String * destFolder);
+
+ virtual IMAPOperation * expunge(String * folder);
+
+ virtual IMAPFetchMessagesOperation * fetchMessagesByUID(String * folder, IMAPMessagesRequestKind requestKind,
+ uint32_t firstUID, uint32_t lastUID);
+ virtual IMAPFetchMessagesOperation * fetchMessagesByNumber(String * folder, IMAPMessagesRequestKind requestKind,
+ uint32_t firstNumber, uint32_t lastNumber);
+ virtual IMAPFetchMessagesOperation * fetchMessagesByUID(String * folder, IMAPMessagesRequestKind requestKind,
+ Array * numbers);
+ virtual IMAPFetchMessagesOperation * fetchMessagesByNumber(String * folder, IMAPMessagesRequestKind requestKind,
+ Array * numbers);
+ virtual IMAPFetchMessageOperation * fetchMessageByUID(String * folder, uint32_t uid);
+ virtual IMAPFetchMessageOperation * fetchMessageAttachmentByUID(String * folder, uint32_t uid, String * partID,
+ Encoding encoding, unsigned int expectedSize);
+
+ virtual IMAPOperation * storeFlags(String * folder, Array * uids, IMAPStoreFlagsRequestKind kind, MessageFlag flags);
+ virtual IMAPOperation * storeLabels(String * folder, Array * uids, IMAPStoreFlagsRequestKind kind, Array * labels);
+
+ virtual Array * search(String * folder, IMAPSearchKind kind, String * searchString);
+ virtual Array * search(String * folder, IMAPSearchExpression * expression);
+
+ virtual IMAPIdleOperation * idle(String * folder, uint32_t lastKnownUID);
+
+ virtual IMAPOperation * connect();
+ virtual IMAPOperation * disconnect();
+
+ virtual IMAPOperation * fetchNamespace();
+
+ virtual IMAPOperation * login();
+
+ virtual IMAPOperation * identity(String * vendor, String * name, String * version);
+ };
+}
+
+#endif
diff --git a/src/async/smtp/MCSMTPAsyncSession.cc b/src/async/smtp/MCSMTPAsyncSession.cc
new file mode 100644
index 00000000..9798fc0c
--- /dev/null
+++ b/src/async/smtp/MCSMTPAsyncSession.cc
@@ -0,0 +1,147 @@
+#include "MCSMTPAsyncSession.h"
+
+#include "MCSMTPSession.h"
+#include "MCSMTPSendWithRecipientOperation.h"
+#include "MCSMTPSendWithDataOperation.h"
+#include "MCSMTPSendWithBuilderOperation.h"
+
+using namespace mailcore;
+
+SMTPAsyncSession::SMTPAsyncSession()
+{
+ mSession = new SMTPSession();
+ mQueue = new OperationQueue();
+}
+
+SMTPAsyncSession::~SMTPAsyncSession()
+{
+ mQueue->release();
+ mSession->release();
+}
+
+String * SMTPAsyncSession::className()
+{
+ return MCSTR("SMTPAsyncSession");
+}
+
+void SMTPAsyncSession::setHostname(String * hostname)
+{
+ mSession->setHostname(hostname);
+}
+
+String * SMTPAsyncSession::hostname()
+{
+ return mSession->hostname();
+}
+
+void SMTPAsyncSession::setPort(unsigned int port)
+{
+ mSession->setPort(port);
+}
+
+unsigned int SMTPAsyncSession::port()
+{
+ return mSession->port();
+}
+
+void SMTPAsyncSession::setUsername(String * username)
+{
+ return mSession->setUsername(username);
+}
+
+String * SMTPAsyncSession::username()
+{
+ return mSession->username();
+}
+
+void SMTPAsyncSession::setPassword(String * password)
+{
+ mSession->setPassword(password);
+}
+
+String * SMTPAsyncSession::password()
+{
+ return mSession->password();
+}
+
+void SMTPAsyncSession::setAuthType(AuthType authType)
+{
+ mSession->setAuthType(authType);
+}
+
+AuthType SMTPAsyncSession::authType()
+{
+ return mSession->authType();
+}
+
+void SMTPAsyncSession::setConnectionType(ConnectionType connectionType)
+{
+ mSession->setConnectionType(connectionType);
+}
+
+ConnectionType SMTPAsyncSession::connectionType()
+{
+ return mSession->connectionType();
+}
+
+void SMTPAsyncSession::setTimeout(time_t timeout)
+{
+ return mSession->setTimeout(timeout);
+}
+
+time_t SMTPAsyncSession::timeout()
+{
+ return mSession->timeout();
+}
+
+void SMTPAsyncSession::setCheckCertificateEnabled(bool enabled)
+{
+ return mSession->setCheckCertificateEnabled(enabled);
+}
+
+bool SMTPAsyncSession::isCheckCertificateEnabled()
+{
+ return mSession->isCheckCertificateEnabled();
+}
+
+void SMTPAsyncSession::setUseHeloIPEnabled(bool enabled)
+{
+ mSession->setUseHeloIPEnabled(enabled);
+}
+
+bool SMTPAsyncSession::useHeloIPEnabled()
+{
+ return mSession->useHeloIPEnabled();
+}
+
+SMTPOperation * sendMessage(Address * from, Array * recipients, Data * messageData)
+{
+#if 0
+ SMTPSendWithRecipientOperation * op = new SMTPSendWithRecipientOperation();
+ op->setFrom(from);
+ op->setRecipients(recipients);
+ op->messageData(messageData);
+ return (SMTPOperation *) op->autorelease();
+#endif
+ return NULL;
+}
+
+SMTPOperation * sendMessage(Data * messageData)
+{
+#if 0
+ SMTPSendWithDataOperation * op = new SMTPSendWithDataOperation();
+ op->setData(messageData);
+ return (SMTPOperation *) op->autorelease();
+#endif
+ return NULL;
+}
+
+SMTPOperation * sendMessage(MessageBuilder * msg)
+{
+#if 0
+ SMTPSendWithBuilderOperation * op = new SMTPSendWithBuilderOperation();
+ op->setBuilder(msg);
+ return (SMTPOperation *) op->autorelease();
+#endif
+ return NULL;
+}
diff --git a/src/async/smtp/MCSMTPAsyncSession.h b/src/async/smtp/MCSMTPAsyncSession.h
new file mode 100644
index 00000000..8e0e50b0
--- /dev/null
+++ b/src/async/smtp/MCSMTPAsyncSession.h
@@ -0,0 +1,73 @@
+#ifndef __MAILCORE_MCSMTPASYNCSESSION_H
+
+#define __MAILCORE_MCSMTPASYNCSESSION_H
+
+#include <mailcore/MCBaseTypes.h>
+#include <mailcore/MCMessageConstants.h>
+#include <libetpan/libetpan.h>
+
+namespace mailcore {
+
+ class MessageBuilder;
+ class SMTPOperation;
+ class SMTPSession;
+ class Address;
+
+ class SMTPAsyncSession : public Object {
+ private:
+ String * mHostname;
+ unsigned int mPort;
+ String * mUsername;
+ String * mPassword;
+ AuthType mAuthType;
+ ConnectionType mConnectionType;
+ time_t mTimeout;
+ bool mCheckCertificateEnabled;
+ bool mUseHeloIPEnabled;
+
+ SMTPSession * mSession;
+ OperationQueue * mQueue;
+
+ void queue(SMTPOperation * op);
+
+ public:
+ SMTPAsyncSession();
+ virtual ~SMTPAsyncSession();
+
+ virtual String * className();
+
+ virtual void setHostname(String * hostname);
+ virtual String * hostname();
+
+ virtual void setPort(unsigned int port);
+ virtual unsigned int port();
+
+ virtual void setUsername(String * username);
+ virtual String * username();
+
+ virtual void setPassword(String * password);
+ virtual String * password();
+
+ virtual void setAuthType(AuthType authType);
+ virtual AuthType authType();
+
+ virtual void setConnectionType(ConnectionType connectionType);
+ virtual ConnectionType connectionType();
+
+ virtual void setTimeout(time_t timeout);
+ virtual time_t timeout();
+
+ virtual void setCheckCertificateEnabled(bool enabled);
+ virtual bool isCheckCertificateEnabled();
+
+ virtual void setUseHeloIPEnabled(bool enabled);
+ virtual bool useHeloIPEnabled();
+
+ virtual SMTPOperation * sendMessage(Address * from, Array * recipients, Data * messageData);
+ virtual SMTPOperation * sendMessage(Data * messageData);
+ virtual SMTPOperation * sendMessage(MessageBuilder * msg);
+ };
+
+}
+
+#endif
diff --git a/src/async/smtp/MCSMTPSendWithBuilderOperation.cc b/src/async/smtp/MCSMTPSendWithBuilderOperation.cc
new file mode 100644
index 00000000..560998ff
--- /dev/null
+++ b/src/async/smtp/MCSMTPSendWithBuilderOperation.cc
@@ -0,0 +1,9 @@
+//
+// SMTPSendWithBuilderOperation.cc
+// mailcore2
+//
+// Created by DINH Viêt Hoà on 1/10/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#include "MCSMTPSendWithBuilderOperation.h"
diff --git a/src/async/smtp/MCSMTPSendWithBuilderOperation.h b/src/async/smtp/MCSMTPSendWithBuilderOperation.h
new file mode 100644
index 00000000..d306e30c
--- /dev/null
+++ b/src/async/smtp/MCSMTPSendWithBuilderOperation.h
@@ -0,0 +1,14 @@
+//
+// SMTPSendWithBuilderOperation.h
+// mailcore2
+//
+// Created by DINH Viêt Hoà on 1/10/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#ifndef __mailcore2__MCSMTPSendWithBuilderOperation__
+#define __mailcore2__MCSMTPSendWithBuilderOperation__
+
+#include <iostream>
+
+#endif /* defined(__mailcore2__SMTPSendWithBuilderOperation__) */
diff --git a/src/async/smtp/MCSMTPSendWithDataOperation.cc b/src/async/smtp/MCSMTPSendWithDataOperation.cc
new file mode 100644
index 00000000..ab42aa0e
--- /dev/null
+++ b/src/async/smtp/MCSMTPSendWithDataOperation.cc
@@ -0,0 +1,9 @@
+//
+// SMTPSendWithDataOperation.cc
+// mailcore2
+//
+// Created by DINH Viêt Hoà on 1/10/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#include "MCSMTPSendWithDataOperation.h"
diff --git a/src/async/smtp/MCSMTPSendWithDataOperation.h b/src/async/smtp/MCSMTPSendWithDataOperation.h
new file mode 100644
index 00000000..c13ee07d
--- /dev/null
+++ b/src/async/smtp/MCSMTPSendWithDataOperation.h
@@ -0,0 +1,14 @@
+//
+// SMTPSendWithDataOperation.h
+// mailcore2
+//
+// Created by DINH Viêt Hoà on 1/10/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#ifndef __mailcore2__MCSMTPSendWithDataOperation__
+#define __mailcore2__MCSMTPSendWithDataOperation__
+
+#include <iostream>
+
+#endif /* defined(__mailcore2__SMTPSendWithDataOperation__) */
diff --git a/src/async/smtp/MCSMTPSendWithRecipientOperation.cc b/src/async/smtp/MCSMTPSendWithRecipientOperation.cc
new file mode 100644
index 00000000..5fee7fa3
--- /dev/null
+++ b/src/async/smtp/MCSMTPSendWithRecipientOperation.cc
@@ -0,0 +1,9 @@
+//
+// SMTPSendWithRecipientOperation.cc
+// mailcore2
+//
+// Created by DINH Viêt Hoà on 1/10/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#include "MCSMTPSendWithRecipientOperation.h"
diff --git a/src/async/smtp/MCSMTPSendWithRecipientOperation.h b/src/async/smtp/MCSMTPSendWithRecipientOperation.h
new file mode 100644
index 00000000..f4134688
--- /dev/null
+++ b/src/async/smtp/MCSMTPSendWithRecipientOperation.h
@@ -0,0 +1,13 @@
+//
+// SMTPSendWithRecipientOperation.h
+// mailcore2
+//
+// Created by DINH Viêt Hoà on 1/10/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#ifndef __mailcore2__MCSMTPSendWithRecipientOperation__
+#define __mailcore2__MCSMTPSendWithRecipientOperation__
+
+
+#endif /* defined(__mailcore2__SMTPSendWithRecipientOperation__) */
diff --git a/src/core/MCCore.h b/src/core/MCCore.h
new file mode 100644
index 00000000..9c1e0d42
--- /dev/null
+++ b/src/core/MCCore.h
@@ -0,0 +1,19 @@
+//
+// Core.h
+// mailcore2
+//
+// Created by DINH Viêt Hoà on 1/10/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#ifndef __MAILCORE_MCCORE_H_
+#define __MAILCORE_MCCORE_H_
+
+#include <mailcore/MCAbstract.h>
+#include <mailcore/MCBaseTypes.h>
+#include <mailcore/MCIMAP.h>
+#include <mailcore/MCPOP.h>
+#include <mailcore/MCRFC822.h>
+#include <mailcore/MCSMTP.h>
+
+#endif
diff --git a/src/core/abstract/.DS_Store b/src/core/abstract/.DS_Store
new file mode 100644
index 00000000..5008ddfc
--- /dev/null
+++ b/src/core/abstract/.DS_Store
Binary files differ
diff --git a/src/core/abstract/MCAbstract.h b/src/core/abstract/MCAbstract.h
new file mode 100644
index 00000000..fd36af46
--- /dev/null
+++ b/src/core/abstract/MCAbstract.h
@@ -0,0 +1,13 @@
+#ifndef __MAILCORE_MCABSTRACT_H
+
+#define __MAILCORE_MCABSTRACT_H
+
+#include <mailcore/MCAbstractMessage.h>
+#include <mailcore/MCAbstractMessagePart.h>
+#include <mailcore/MCAbstractMultipart.h>
+#include <mailcore/MCAbstractPart.h>
+#include <mailcore/MCAddress.h>
+#include <mailcore/MCMessageConstants.h>
+#include <mailcore/MCMessageHeader.h>
+
+#endif
diff --git a/src/core/abstract/MCAbstractMessage.cc b/src/core/abstract/MCAbstractMessage.cc
new file mode 100644
index 00000000..00a4b9b9
--- /dev/null
+++ b/src/core/abstract/MCAbstractMessage.cc
@@ -0,0 +1,65 @@
+#include "MCAbstractMessage.h"
+
+#include "MCMessageHeader.h"
+
+using namespace mailcore;
+
+AbstractMessage::AbstractMessage()
+{
+ init();
+}
+
+AbstractMessage::AbstractMessage(AbstractMessage * other)
+{
+ init();
+ mHeader = (MessageHeader *) MC_SAFE_COPY(other->mHeader);
+}
+
+void AbstractMessage::init()
+{
+ mHeader = NULL;
+}
+
+AbstractMessage::~AbstractMessage()
+{
+ MC_SAFE_RELEASE(mHeader);
+}
+
+String * AbstractMessage::description()
+{
+ if (mHeader != NULL) {
+ String * result = String::string();
+ result->appendUTF8Format("<%s:%p\n", className()->UTF8Characters(), this);
+ result->appendString(mHeader->description());
+ result->appendUTF8Characters(">");
+ return result;
+ }
+ else {
+ return Object::description();
+ }
+}
+
+#if 0
+String * AbstractMessage::className()
+{
+ return MCSTR("MessageHeader");
+}
+#endif
+
+Object * AbstractMessage::copy()
+{
+ return new AbstractMessage(this);
+}
+
+MessageHeader * AbstractMessage::header()
+{
+ if (mHeader == NULL) {
+ mHeader = new MessageHeader();
+ }
+ return mHeader;
+}
+
+void AbstractMessage::setHeader(MessageHeader * header)
+{
+ MC_SAFE_REPLACE_RETAIN(MessageHeader, mHeader, header);
+}
diff --git a/src/core/abstract/MCAbstractMessage.h b/src/core/abstract/MCAbstractMessage.h
new file mode 100644
index 00000000..e5b62c8a
--- /dev/null
+++ b/src/core/abstract/MCAbstractMessage.h
@@ -0,0 +1,29 @@
+#ifndef __MAILCORE_MCABSTRACTMESSAGE_H_
+#define __MAILCORE_MCABSTRACTMESSAGE_H_
+
+#include <mailcore/MCBaseTypes.h>
+
+namespace mailcore {
+
+ class MessageHeader;
+
+ class AbstractMessage : public Object {
+ private:
+ MessageHeader * mHeader;
+ void init();
+
+ public:
+ AbstractMessage();
+ AbstractMessage(AbstractMessage * other);
+ virtual ~AbstractMessage();
+
+ virtual String * description();
+ //virtual String * className();
+ virtual Object * copy();
+
+ virtual MessageHeader * header();
+ virtual void setHeader(MessageHeader * header);
+ };
+}
+
+#endif
diff --git a/src/core/abstract/MCAbstractMessagePart.cc b/src/core/abstract/MCAbstractMessagePart.cc
new file mode 100644
index 00000000..6939d060
--- /dev/null
+++ b/src/core/abstract/MCAbstractMessagePart.cc
@@ -0,0 +1,88 @@
+#include "MCAbstractMessagePart.h"
+
+#include "MCMessageHeader.h"
+
+using namespace mailcore;
+
+void AbstractMessagePart::init()
+{
+ mMainPart = NULL;
+ mHeader = NULL;
+}
+
+AbstractMessagePart::AbstractMessagePart()
+{
+}
+
+AbstractMessagePart::AbstractMessagePart(AbstractMessagePart * other)
+{
+ if (other->mainPart() != NULL) {
+ setMainPart((AbstractPart *) other->mainPart()->copy()->autorelease());
+ }
+ if (other->mHeader != NULL) {
+ setHeader((MessageHeader *) other->header()->copy()->autorelease());
+ }
+}
+
+AbstractMessagePart::~AbstractMessagePart()
+{
+ MC_SAFE_RELEASE(mMainPart);
+ MC_SAFE_RELEASE(mHeader);
+}
+
+String * AbstractMessagePart::description()
+{
+ String * result = String::string();
+ result->appendUTF8Format("<%s:%p %s>", className(), this, mMainPart->description());
+ return result;
+}
+
+#if 0
+String * AbstractMessagePart::className()
+{
+ return MCSTR("AbstractMessagePart");
+}
+#endif
+
+Object * AbstractMessagePart::copy()
+{
+ return new AbstractMessagePart(this);
+}
+
+MessageHeader * AbstractMessagePart::header()
+{
+ if (mHeader == NULL) {
+ mHeader = new MessageHeader();
+ }
+ return mHeader;
+}
+
+void AbstractMessagePart::setHeader(MessageHeader * header)
+{
+ MC_SAFE_REPLACE_RETAIN(MessageHeader, mHeader, header);
+}
+
+AbstractPart * AbstractMessagePart::mainPart()
+{
+ return mMainPart;
+}
+
+void AbstractMessagePart::setMainPart(AbstractPart * mainPart)
+{
+ MC_SAFE_REPLACE_RETAIN(AbstractPart, mMainPart, mainPart);
+ applyMessage();
+}
+
+void AbstractMessagePart::applyMessage()
+{
+ if (mMainPart == NULL)
+ return;
+
+ mMainPart->setMessage(message());
+}
+
+void AbstractMessagePart::setMessage(AbstractMessage * message)
+{
+ AbstractPart::setMessage(message);
+ applyMessage();
+}
diff --git a/src/core/abstract/MCAbstractMessagePart.h b/src/core/abstract/MCAbstractMessagePart.h
new file mode 100644
index 00000000..a855202c
--- /dev/null
+++ b/src/core/abstract/MCAbstractMessagePart.h
@@ -0,0 +1,39 @@
+#ifndef __MAILCORE_MCABSTRACTMESSAGEPART_H_
+
+#define __MAILCORE_MCABSTRACTMESSAGEPART_H_
+
+#include <mailcore/MCBaseTypes.h>
+#include <mailcore/MCAbstractPart.h>
+
+namespace mailcore {
+
+ class MessageHeader;
+
+ class AbstractMessagePart : public AbstractPart {
+ private:
+ AbstractPart * mMainPart;
+ MessageHeader * mHeader;
+ void init();
+ void applyMessage();
+
+ public:
+ AbstractMessagePart();
+ AbstractMessagePart(AbstractMessagePart * other);
+ virtual ~AbstractMessagePart();
+
+ virtual String * description();
+ //virtual String * className();
+ virtual Object * copy();
+
+ virtual MessageHeader * header();
+ virtual void setHeader(MessageHeader * header);
+
+ virtual AbstractPart * mainPart();
+ virtual void setMainPart(AbstractPart * mainPart);
+
+ virtual void setMessage(AbstractMessage * message);
+ };
+}
+
+
+#endif
diff --git a/src/core/abstract/MCAbstractMultipart.cc b/src/core/abstract/MCAbstractMultipart.cc
new file mode 100644
index 00000000..fa48d959
--- /dev/null
+++ b/src/core/abstract/MCAbstractMultipart.cc
@@ -0,0 +1,95 @@
+#include "MCAbstractMultipart.h"
+
+using namespace mailcore;
+
+AbstractMultipart::AbstractMultipart()
+{
+ init();
+}
+
+AbstractMultipart::AbstractMultipart(AbstractMultipart * other) : AbstractPart(other)
+{
+ init();
+
+ setPartType(other->partType());
+ Array * parts = Array::array();
+ for(unsigned int i = 0 ; i < other->parts()->count() ; i ++) {
+ AbstractPart * part = (AbstractPart *) other->parts()->objectAtIndex(i);
+ parts->addObject(part->copy()->autorelease());
+ }
+ setParts(parts);
+}
+
+void AbstractMultipart::init()
+{
+ mParts = NULL;
+ setPartType(PartTypeMultipartMixed);
+}
+
+AbstractMultipart::~AbstractMultipart()
+{
+ MC_SAFE_RELEASE(mParts);
+}
+
+Array * AbstractMultipart::parts()
+{
+ return mParts;
+}
+
+void AbstractMultipart::setParts(Array * parts)
+{
+ MC_SAFE_REPLACE_COPY(Array, mParts, parts);
+ applyMessage();
+}
+
+String * AbstractMultipart::description()
+{
+ String * result = String::string();
+
+ const char * partTypeName = NULL;
+ switch (partType()) {
+ default:
+ case PartTypeMultipartMixed:
+ partTypeName = "mixed";
+ break;
+ case PartTypeMultipartRelated:
+ partTypeName = "related";
+ break;
+ case PartTypeMultipartAlternative:
+ partTypeName = "alernative";
+ break;
+ }
+
+ result->appendUTF8Format("<%s:%p %s %s>",
+ MCUTF8(className()), this, partTypeName, MCUTF8(mParts->description()));
+ return result;
+}
+
+#if 0
+String * AbstractMultipart::className()
+{
+ return MCSTR("AbstractMultipart");
+}
+#endif
+
+Object * AbstractMultipart::copy()
+{
+ return new AbstractMultipart(this);
+}
+
+void AbstractMultipart::applyMessage()
+{
+ if (mParts == NULL)
+ return;
+
+ for(unsigned int i = 0 ; i < mParts->count() ; i ++) {
+ AbstractPart * part = (AbstractPart *) mParts->objectAtIndex(i);
+ part->setMessage(message());
+ }
+}
+
+void AbstractMultipart::setMessage(AbstractMessage * message)
+{
+ AbstractPart::setMessage(message);
+ applyMessage();
+}
diff --git a/src/core/abstract/MCAbstractMultipart.h b/src/core/abstract/MCAbstractMultipart.h
new file mode 100644
index 00000000..c731ed7b
--- /dev/null
+++ b/src/core/abstract/MCAbstractMultipart.h
@@ -0,0 +1,32 @@
+#ifndef __MAILCORE_MCABSTRACTMULTIPART_H
+
+#define __MAILCORE_MCABSTRACTMULTIPART_H
+
+#include <mailcore/MCBaseTypes.h>
+#include <mailcore/MCAbstractPart.h>
+
+namespace mailcore {
+
+ class AbstractMultipart : public AbstractPart {
+ private:
+ Array * mParts;
+ void init();
+ void applyMessage();
+
+ public:
+ AbstractMultipart();
+ AbstractMultipart(AbstractMultipart * other);
+ virtual ~AbstractMultipart();
+
+ virtual String * description();
+ //virtual String * className();
+ virtual Object * copy();
+
+ virtual Array * parts();
+ virtual void setParts(Array * parts);
+
+ virtual void setMessage(AbstractMessage * message);
+ };
+}
+
+#endif
diff --git a/src/core/abstract/MCAbstractPart.cc b/src/core/abstract/MCAbstractPart.cc
new file mode 100644
index 00000000..30c4c8f0
--- /dev/null
+++ b/src/core/abstract/MCAbstractPart.cc
@@ -0,0 +1,223 @@
+#include "MCAbstractPart.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+using namespace mailcore;
+
+AbstractPart::AbstractPart()
+{
+ init();
+}
+
+AbstractPart::AbstractPart(AbstractPart * other)
+{
+ init();
+ setFilename(other->mFilename);
+ setMimeType(other->mMimeType);
+ setCharset(other->mCharset);
+ setContentID(other->mContentID);
+ setContentLocation(other->mContentLocation);
+ setInlineAttachment(other->mInlineAttachment);
+ setPartType(other->mPartType);
+}
+
+void AbstractPart::init()
+{
+ mFilename = NULL;
+ mMimeType = NULL;
+ mCharset = NULL;
+ mContentID = NULL;
+ mContentLocation = NULL;
+ mInlineAttachment = false;
+ mPartType = PartTypeSingle;
+}
+
+AbstractPart::~AbstractPart()
+{
+ MC_SAFE_RELEASE(mFilename);
+ MC_SAFE_RELEASE(mMimeType);
+ MC_SAFE_RELEASE(mCharset);
+ MC_SAFE_RELEASE(mContentID);
+ MC_SAFE_RELEASE(mContentLocation);
+}
+
+String * AbstractPart::description()
+{
+ String * result = String::string();
+ result->appendUTF8Format("<%s:%p\n", className()->UTF8Characters(), this);
+ if (mFilename != NULL) {
+ result->appendUTF8Format("filename: %s\n", mFilename->UTF8Characters());
+ }
+ if (mMimeType != NULL) {
+ result->appendUTF8Format("mime type: %s\n", mMimeType->UTF8Characters());
+ }
+ if (mCharset != NULL) {
+ result->appendUTF8Format("charset: %s\n", mCharset->UTF8Characters());
+ }
+ if (mContentID != NULL) {
+ result->appendUTF8Format("content-ID: %s\n", mContentID->UTF8Characters());
+ }
+ if (mContentLocation != NULL) {
+ result->appendUTF8Format("content-location: %s\n", mContentLocation->UTF8Characters());
+ }
+ result->appendUTF8Format("inline: %i\n", mInlineAttachment);
+ result->appendUTF8Format(">");
+
+ return result;
+}
+
+#if 0
+String * AbstractPart::className()
+{
+ return MCSTR("AbstractPart");
+}
+#endif
+
+Object * AbstractPart::copy()
+{
+ return new AbstractPart(this);
+}
+
+PartType AbstractPart::partType()
+{
+ return mPartType;
+}
+
+void AbstractPart::setPartType(PartType type)
+{
+ mPartType = type;
+}
+
+String * AbstractPart::filename()
+{
+ return mFilename;
+}
+
+void AbstractPart::setFilename(String * filename)
+{
+ MC_SAFE_REPLACE_COPY(String, mFilename, filename);
+}
+
+String * AbstractPart::mimeType()
+{
+ return mMimeType;
+}
+
+void AbstractPart::setMimeType(String * mimeType)
+{
+ MC_SAFE_REPLACE_COPY(String, mMimeType, mimeType);
+}
+
+String * AbstractPart::charset()
+{
+ return mCharset;
+}
+
+void AbstractPart::setCharset(String * charset)
+{
+ MC_SAFE_REPLACE_COPY(String, mCharset, charset);
+}
+
+String * AbstractPart::contentID()
+{
+ return mContentID;
+}
+
+void AbstractPart::setContentID(String * contentID)
+{
+ MC_SAFE_REPLACE_COPY(String, mContentID, contentID);
+}
+
+String * AbstractPart::contentLocation()
+{
+ return mContentLocation;
+}
+
+void AbstractPart::setContentLocation(String * contentLocation)
+{
+ MC_SAFE_REPLACE_COPY(String, mContentLocation, contentLocation);
+}
+
+bool AbstractPart::isInlineAttachment()
+{
+ return mInlineAttachment;
+}
+
+void AbstractPart::setInlineAttachment(bool inlineAttachment)
+{
+ mInlineAttachment = inlineAttachment;
+}
+
+AbstractMessage * AbstractPart::message()
+{
+ return mMessage;
+}
+
+void AbstractPart::setMessage(AbstractMessage * message)
+{
+ mMessage = message;
+}
+
+void AbstractPart::importIMAPFields(struct mailimap_body_fields * fields,
+ struct mailimap_body_ext_1part * extension)
+{
+ if (fields->bd_parameter != NULL) {
+ clistiter * cur;
+
+ for(cur = clist_begin(fields->bd_parameter->pa_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimap_single_body_fld_param * imap_param;
+
+ imap_param = (struct mailimap_single_body_fld_param *) clist_content(cur);
+
+ if (strcasecmp(imap_param->pa_name, "name") == 0) {
+ setFilename(String::stringByDecodingMIMEHeaderValue(imap_param->pa_value));
+ }
+ else if (strcasecmp(imap_param->pa_name, "charset") == 0) {
+ setCharset(String::stringByDecodingMIMEHeaderValue(imap_param->pa_value));
+ }
+ }
+ }
+ if (fields->bd_id != NULL) {
+ char * contentid;
+ size_t cur_token;
+ int r;
+
+ cur_token = 0;
+ r = mailimf_msg_id_parse(fields->bd_id, strlen(fields->bd_id),
+ &cur_token, &contentid);
+ if (r == MAILIMF_NO_ERROR) {
+ // msg id
+ setContentID(String::stringWithUTF8Characters(contentid));
+ free(contentid);
+ }
+ }
+
+ if (extension != NULL) {
+ if (extension->bd_disposition != NULL) {
+ if (strcasecmp(extension->bd_disposition->dsp_type, "inline") == 0) {
+ setInlineAttachment(true);
+ }
+
+ if (extension->bd_disposition->dsp_attributes != NULL) {
+ clistiter * cur;
+
+ for(cur = clist_begin(extension->bd_disposition->dsp_attributes->pa_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimap_single_body_fld_param * imap_param;
+
+ imap_param = (struct mailimap_single_body_fld_param *) clist_content(cur);
+
+ if (strcasecmp(imap_param->pa_name, "filename") == 0) {
+ setFilename(String::stringByDecodingMIMEHeaderValue(imap_param->pa_value));
+ }
+ }
+ }
+ }
+
+ if (extension->bd_loc != NULL) {
+ setContentLocation(String::stringWithUTF8Characters(extension->bd_loc));
+ }
+ }
+}
diff --git a/src/core/abstract/MCAbstractPart.h b/src/core/abstract/MCAbstractPart.h
new file mode 100644
index 00000000..356ed256
--- /dev/null
+++ b/src/core/abstract/MCAbstractPart.h
@@ -0,0 +1,63 @@
+#ifndef __MAILCORE_MCABSTRACTPART_H_
+
+#define __MAILCORE_MCABSTRACTPART_H_
+
+#include <mailcore/MCBaseTypes.h>
+#include <mailcore/MCMessageConstants.h>
+
+namespace mailcore {
+
+ class AbstractMessage;
+
+ class AbstractPart : public Object {
+ private:
+ String * mFilename;
+ String * mMimeType;
+ String * mCharset;
+ String * mContentID;
+ String * mContentLocation;
+ bool mInlineAttachment;
+ PartType mPartType;
+ AbstractMessage * mMessage; // weak
+ void init();
+
+ public:
+ AbstractPart();
+ AbstractPart(AbstractPart * other);
+ virtual ~AbstractPart();
+
+ virtual String * description();
+ //virtual String * className();
+ virtual Object * copy();
+
+ virtual PartType partType();
+ virtual void setPartType(PartType type);
+
+ virtual String * filename();
+ virtual void setFilename(String * filename);
+
+ virtual String * mimeType();
+ virtual void setMimeType(String * mimeType);
+
+ virtual String * charset();
+ virtual void setCharset(String * charset);
+
+ virtual String * contentID();
+ virtual void setContentID(String * contentID);
+
+ virtual String * contentLocation();
+ virtual void setContentLocation(String * contentLocation);
+
+ virtual bool isInlineAttachment();
+ virtual void setInlineAttachment(bool inlineAttachment);
+
+ virtual AbstractMessage * message();
+ virtual void setMessage(AbstractMessage * message);
+
+ virtual void importIMAPFields(struct mailimap_body_fields * fields,
+ struct mailimap_body_ext_1part * extension);
+ };
+
+}
+
+#endif
diff --git a/src/core/abstract/MCAddress.cc b/src/core/abstract/MCAddress.cc
new file mode 100644
index 00000000..25bed974
--- /dev/null
+++ b/src/core/abstract/MCAddress.cc
@@ -0,0 +1,364 @@
+#include "MCAddress.h"
+
+#include <string.h>
+
+using namespace mailcore;
+
+Address::Address()
+{
+ init();
+}
+
+Address::Address(Address * other)
+{
+ init();
+ setDisplayName(other->displayName());
+ setMailbox(other->mailbox());
+}
+
+void Address::init()
+{
+ mDisplayName = NULL;
+ mMailbox = NULL;
+}
+
+Address::~Address()
+{
+ MC_SAFE_RELEASE(mDisplayName);
+ MC_SAFE_RELEASE(mMailbox);
+}
+
+Address * Address::addressWithDisplayName(String * displayName, String * mailbox)
+{
+ Address * result = new Address();
+ result->setDisplayName(displayName);
+ result->setMailbox(mailbox);
+ return (Address *) result->autorelease();
+}
+
+Address * Address::addressWithMailbox(String * mailbox)
+{
+ return addressWithDisplayName(NULL, mailbox);
+}
+
+Address * Address::addressWithIMFMailbox(struct mailimf_mailbox * mailbox)
+{
+ Address * address;
+
+ address = new Address();
+ if (mailbox->mb_display_name != NULL) {
+ address->setDisplayName(String::stringByDecodingMIMEHeaderValue(mailbox->mb_display_name));
+ }
+ if (mailbox->mb_addr_spec != NULL) {
+ address->setMailbox(String::stringWithUTF8Characters(mailbox->mb_addr_spec));
+ }
+ if (address->mailbox() == NULL) {
+ address->setMailbox(String::string());
+ }
+
+ return (Address *) address->autorelease();
+}
+
+Address * Address::addressWithIMAPAddress(struct mailimap_address * imap_addr)
+{
+ char * dsp_name;
+ Address * address;
+ String * mailbox;
+
+ if (imap_addr->ad_personal_name == NULL)
+ dsp_name = NULL;
+ else {
+ dsp_name = imap_addr->ad_personal_name;
+ }
+
+ if (imap_addr->ad_host_name == NULL) {
+ const char * addr;
+
+ if (imap_addr->ad_mailbox_name == NULL) {
+ addr = "";
+ }
+ else {
+ addr = imap_addr->ad_mailbox_name;
+ }
+ mailbox = String::stringWithUTF8Characters(addr);
+ if (mailbox == NULL) {
+ mailbox = MCSTR("");
+ }
+ }
+ else if (imap_addr->ad_mailbox_name == NULL) {
+ // fix by Gabor Cselle, (http://gaborcselle.com/), reported 8/16/2009
+ mailbox = String::stringWithUTF8Format("@%s", imap_addr->ad_host_name);
+ }
+ else {
+ mailbox = String::stringWithUTF8Format("%s@%s", imap_addr->ad_mailbox_name, imap_addr->ad_host_name);
+ }
+
+ address = new Address();
+ if (dsp_name != NULL) {
+ address->setDisplayName(String::stringByDecodingMIMEHeaderValue(dsp_name));
+ }
+ address->setMailbox(mailbox);
+
+ return (Address *) address->autorelease();
+}
+
+Address * Address::addressWithRFC822String(String * RFC822String)
+{
+ const char * utf8String;
+ size_t currentIndex;
+ struct mailimf_mailbox * mb;
+ int r;
+ Address * result;
+
+ utf8String = RFC822String->UTF8Characters();
+ currentIndex = 0;
+ r = mailimf_mailbox_parse(utf8String, strlen(utf8String), &currentIndex, &mb);
+ if (r != MAILIMF_NO_ERROR)
+ return NULL;
+
+ result = addressWithIMFMailbox(mb);
+ mailimf_mailbox_free(mb);
+
+ return result;
+}
+
+Address * Address::addressWithNonEncodedIMFMailbox(struct mailimf_mailbox * mailbox)
+{
+ Address * address;
+
+ address = new Address();
+ if (mailbox->mb_display_name != NULL) {
+ address->setDisplayName(String::stringWithUTF8Characters(mailbox->mb_display_name));
+ }
+ if (mailbox->mb_addr_spec != NULL) {
+ address->setMailbox(String::stringWithUTF8Characters(mailbox->mb_addr_spec));
+ }
+ if (address->mailbox() == NULL) {
+ address->setMailbox(String::string());
+ }
+
+ return (Address *) address->autorelease();
+}
+
+Address * Address::addressWithNonEncodedRFC822String(String * nonEncodedRFC822String)
+{
+ const char * utf8String;
+ size_t currentIndex;
+ struct mailimf_mailbox * mb;
+ int r;
+ Address * result;
+
+ utf8String = nonEncodedRFC822String->UTF8Characters();
+ currentIndex = 0;
+ r = mailimf_mailbox_parse(utf8String, strlen(utf8String), &currentIndex, &mb);
+ if (r != MAILIMF_NO_ERROR)
+ return NULL;
+
+ result = addressWithNonEncodedIMFMailbox(mb);
+ mailimf_mailbox_free(mb);
+
+ return result;
+}
+
+String * Address::description()
+{
+ String * result = String::string();
+ result->appendString(className());
+ result->appendUTF8Format(":%p ", this);
+ if (mDisplayName != NULL) {
+ result->appendString(mDisplayName);
+ }
+ result->appendUTF8Characters(" <");
+ if (mMailbox != NULL) {
+ result->appendString(mMailbox);
+ }
+ result->appendUTF8Characters(">");
+
+ return result;
+}
+
+#if 0
+String * Address::className()
+{
+ return MCSTR("Address");
+}
+#endif
+
+bool Address::isEqual(Object * otherObject)
+{
+ Address * otherAddress = (Address *) otherObject;
+
+ if (mDisplayName == NULL) {
+ if (otherAddress->displayName() != NULL) {
+ return false;
+ }
+ }
+ else if (mDisplayName != NULL) {
+ if (otherAddress->displayName() == NULL) {
+ return false;
+ }
+ else {
+ if (!mDisplayName->isEqual(otherAddress->displayName()))
+ return false;
+ }
+ }
+
+ if (mMailbox == NULL) {
+ if (otherAddress->mailbox() != NULL) {
+ return false;
+ }
+ }
+ else if (mMailbox != NULL) {
+ if (otherAddress->mailbox() == NULL) {
+ return false;
+ }
+ else {
+ if (!mMailbox->isEqual(otherAddress->mailbox()))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+unsigned int Address::hash()
+{
+ unsigned int value;
+
+ value = 0;
+ if (mDisplayName != NULL) {
+ value += mDisplayName->hash();
+ }
+ if (mMailbox != NULL) {
+ value += mMailbox->hash();
+ }
+
+ return value;
+}
+
+Object * Address::copy()
+{
+ return new Address(this);
+}
+
+void Address::setDisplayName(String * displayName)
+{
+ MC_SAFE_REPLACE_COPY(String, mDisplayName, displayName);
+}
+
+String * Address::displayName()
+{
+ return mDisplayName;
+}
+
+void Address::setMailbox(String * mailbox)
+{
+ MC_SAFE_REPLACE_COPY(String, mMailbox, mailbox);
+}
+
+String * Address::mailbox()
+{
+ return mMailbox;
+}
+
+struct mailimf_address * Address::createIMFAddress()
+{
+ struct mailimf_mailbox * mailbox;
+ struct mailimf_address * result;
+
+ mailbox = createIMFMailbox();
+ result = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mailbox, NULL);
+
+ return result;
+}
+
+struct mailimf_mailbox * Address::createIMFMailbox()
+{
+ struct mailimf_mailbox * result;
+ char * display_name;
+ char * addr_spec;
+
+ display_name = NULL;
+ if (displayName() != NULL) {
+ if (displayName()->length() > 0) {
+ Data * data;
+
+ data = displayName()->encodedAddressDisplayNameValue();
+ if (data->bytes() != NULL) {
+ display_name = strdup(data->bytes());
+ }
+ }
+ }
+ addr_spec = strdup(mailbox()->UTF8Characters());
+ result = mailimf_mailbox_new(display_name, addr_spec);
+
+ return result;
+}
+
+String * Address::RFC822String()
+{
+ struct mailimf_mailbox * mb;
+ MMAPString * str;
+ int col;
+ struct mailimf_mailbox_list * mb_list;
+ clist * list;
+ String * result;
+
+ mb = createIMFMailbox();
+
+ list = clist_new();
+ clist_append(list, mb);
+ mb_list = mailimf_mailbox_list_new(list);
+
+ str = mmap_string_new("");
+ col = 0;
+ mailimf_mailbox_list_write_mem(str, &col, mb_list);
+
+ result = String::stringWithUTF8Characters(str->str);
+
+ mailimf_mailbox_list_free(mb_list);
+ mmap_string_free(str);
+
+ return result;
+}
+
+String * Address::nonEncodedRFC822String()
+{
+ struct mailimf_mailbox * mb;
+ MMAPString * str;
+ int col;
+ struct mailimf_mailbox_list * mb_list;
+ clist * list;
+ String * result;
+ char * display_name;
+ char * addr_spec;
+
+ display_name = NULL;
+ if (displayName() != NULL) {
+ if (displayName()->length() > 0) {
+ display_name = strdup(displayName()->UTF8Characters());
+ }
+ }
+ if ((mailbox() == NULL) || (mailbox()->length() == 0)) {
+ addr_spec = strdup("invalid");
+ }
+ else {
+ addr_spec = strdup(mailbox()->UTF8Characters());
+ }
+ mb = mailimf_mailbox_new(display_name, addr_spec);
+
+ list = clist_new();
+ clist_append(list, mb);
+ mb_list = mailimf_mailbox_list_new(list);
+
+ str = mmap_string_new("");
+ col = 0;
+ mailimf_mailbox_list_write_mem(str, &col, mb_list);
+
+ result = String::stringWithUTF8Characters(str->str);
+
+ mailimf_mailbox_list_free(mb_list);
+ mmap_string_free(str);
+
+ return result;
+}
diff --git a/src/core/abstract/MCAddress.h b/src/core/abstract/MCAddress.h
new file mode 100644
index 00000000..227c1136
--- /dev/null
+++ b/src/core/abstract/MCAddress.h
@@ -0,0 +1,55 @@
+#ifndef __MAILCORE_MCADDRESS_H_
+
+#define __MAILCORE_MCADDRESS_H_
+
+#include <libetpan/libetpan.h>
+#include <mailcore/MCBaseTypes.h>
+
+namespace mailcore {
+
+ class Address : public Object {
+ private:
+ String * mDisplayName;
+ String * mMailbox;
+ void init();
+
+ public:
+ Address();
+ Address(Address * other);
+ virtual ~Address();
+
+ static Address * addressWithDisplayName(String * displayName, String * mailbox);
+ static Address * addressWithMailbox(String * mailbox);
+ static Address * addressWithRFC822String(String * RFC822String);
+ static Address * addressWithNonEncodedRFC822String(String * nonEncodedRFC822String);
+
+ virtual String * description();
+ //virtual String * className();
+
+ virtual bool isEqual(Object * otherObject);
+ virtual unsigned int hash();
+
+ virtual Object * copy();
+
+ virtual void setDisplayName(String * displayName);
+ virtual String * displayName();
+
+ virtual void setMailbox(String * address);
+ virtual String * mailbox();
+
+ virtual String * RFC822String();
+ virtual String * nonEncodedRFC822String();
+
+ // Additions
+ static Address * addressWithIMFMailbox(struct mailimf_mailbox * mb);
+ static Address * addressWithNonEncodedIMFMailbox(struct mailimf_mailbox * mb);
+ static Address * addressWithIMAPAddress(struct mailimap_address * imap_addr);
+
+ // Must be released
+ virtual struct mailimf_address * createIMFAddress();
+ virtual struct mailimf_mailbox * createIMFMailbox();
+ };
+
+}
+
+#endif
diff --git a/src/core/abstract/MCMessageConstants.h b/src/core/abstract/MCMessageConstants.h
new file mode 100644
index 00000000..ab30b8c4
--- /dev/null
+++ b/src/core/abstract/MCMessageConstants.h
@@ -0,0 +1,208 @@
+#ifndef __MAILCORE_MCMESSAGECONSTANTS_H_
+#define __MAILCORE_MCMESSAGECONSTANTS_H_
+
+namespace mailcore {
+
+ enum ConnectionType {
+ ConnectionTypeClear = 1 << 0,
+ ConnectionTypeStartTLS = 1 << 1,
+ ConnectionTypeTLS = 1 << 2,
+ };
+
+ enum AuthType {
+ AuthTypeSASLNone = 0,
+ AuthTypeSASLCRAMMD5 = 1 << 0,
+ AuthTypeSASLPlain = 1 << 1,
+ AuthTypeSASLGSSAPI = 1 << 2,
+ AuthTypeSASLDIGESTMD5 = 1 << 3,
+ AuthTypeSASLLogin = 1 << 4,
+ AuthTypeSASLSRP = 1 << 5,
+ AuthTypeSASLNTLM = 1 << 6,
+ AuthTypeSASLKerberosV4 = 1 << 7,
+ };
+
+ enum IMAPFolderFlag {
+ IMAPFolderFlagNone = 0,
+ IMAPFolderFlagMarked = 1 << 0,
+ IMAPFolderFlagUnmarked = 1 << 1,
+ IMAPFolderFlagNoSelect = 1 << 2,
+ IMAPFolderFlagNoInferiors = 1 << 3,
+ IMAPFolderFlagInbox = 1 << 4,
+ IMAPFolderFlagSentMail = 1 << 5,
+ IMAPFolderFlagStarred = 1 << 6,
+ IMAPFolderFlagAllMail = 1 << 7,
+ IMAPFolderFlagTrash = 1 << 8,
+ IMAPFolderFlagDrafts = 1 << 9,
+ IMAPFolderFlagSpam = 1 << 10,
+ IMAPFolderFlagImportant = 1 << 11,
+ IMAPFolderFlagArchive = 1 << 12,
+ };
+
+ enum MessageFlag {
+ MessageFlagNone = 0,
+ MessageFlagSeen = 1 << 0,
+ MessageFlagAnswered = 1 << 1,
+ MessageFlagFlagged = 1 << 2,
+ MessageFlagDeleted = 1 << 3,
+ MessageFlagDraft = 1 << 4,
+ MessageFlagMDNSent = 1 << 5,
+ MessageFlagForwarded = 1 << 6,
+ MessageFlagSubmitPending = 1 << 7,
+ MessageFlagSubmitted = 1 << 8,
+ } ;
+
+ enum IMAPMessagesRequestKind {
+ IMAPMessagesRequestKindUid = 0, // This is the default and it's always fetched
+ IMAPMessagesRequestKindFlags = 1 << 0,
+ IMAPMessagesRequestKindHeaders = 1 << 1,
+ IMAPMessagesRequestKindStructure = 1 << 2,
+ IMAPMessagesRequestKindInternalDate = 1 << 3,
+ IMAPMessagesRequestKindFullHeaders = 1 << 4,
+ IMAPMessagesRequestKindHeaderSubject = 1 << 5,
+ IMAPMessagesRequestKindGmailLabels = 1 << 6,
+ };
+
+ enum IMAPFetchRequestType {
+ IMAPFetchRequestTypeUID = 0,
+ IMAPFetchRequestTypeSequence = 1
+ };
+
+ enum IMAPStoreFlagsRequestKind {
+ IMAPStoreFlagsRequestKindAdd,
+ IMAPStoreFlagsRequestKindRemove,
+ IMAPStoreFlagsRequestKindSet,
+ };
+
+ enum IMAPWorkaround {
+ IMAPWorkaroundGmail = 1 << 0,
+ IMAPWorkaroundYahoo = 1 << 1,
+ IMAPWorkaroundExchange2003 = 1 << 2,
+ };
+
+ enum IMAPCapability {
+ IMAPCapabilityACL,
+ IMAPCapabilityBinary,
+ IMAPCapabilityCatenate,
+ IMAPCapabilityChildren,
+ IMAPCapabilityCompressDeflate,
+ IMAPCapabilityCondstore,
+ IMAPCapabilityEnable,
+ IMAPCapabilityIdle,
+ IMAPCapabilityLiteralPlus,
+ IMAPCapabilityMultiAppend,
+ IMAPCapabilityNamespace,
+ IMAPCapabilityQResync,
+ IMAPCapabilityQuota,
+ IMAPCapabilitySort,
+ IMAPCapabilityStartTLS,
+ IMAPCapabilityThreadOrderedSubject,
+ IMAPCapabilityThreadReferences,
+ IMAPCapabilityUIDPlus,
+ IMAPCapabilityUnselect,
+ IMAPCapabilityXList,
+ IMAPCapabilityAuthAnonymous,
+ IMAPCapabilityAuthCRAMMD5,
+ MAPCapabilityAuthDigestMD5,
+ IMAPCapabilityAuthExternal,
+ IMAPCapabilityAuthGSSAPI,
+ IMAPCapabilityAuthKerberosV4,
+ IMAPCapabilityAuthLogin,
+ IMAPCapabilityAuthNTLM,
+ IMAPCapabilityAuthOTP,
+ IMAPCapabilityAuthPlain,
+ IMAPCapabilityAuthSKey,
+ IMAPCapabilityAuthSRP,
+ };
+
+ enum POPCapability {
+ POPCapabilityNone,
+ POPCapabilityStartTLS,
+ POPCapabilityTop,
+ POPCapabilityUser,
+ POPCapabilityRespCodes,
+ POPCapabilityPipelining,
+ POPCapabilityUIDL,
+ POPCapabilitySASL,
+ POPCapabilityAuthAnonymous,
+ POPCapabilityAuthCRAMMD5,
+ POPCapabilityAuthDigestMD5,
+ POPCapabilityAuthExternal,
+ POPCapabilityAuthGSSAPI,
+ POPCapabilityAuthKerberosV4,
+ POPCapabilityAuthLogin,
+ POPCapabilityAuthNTLM,
+ POPCapabilityAuthOTP,
+ POPCapabilityAuthPlain,
+ POPCapabilityAuthSKey,
+ POPCapabilityAuthSRP,
+ };
+
+ enum Encoding {
+ Encoding7Bit = 0, // should match MAILIMAP_BODY_FLD_ENC_7BIT
+ Encoding8Bit = 1, // should match MAILIMAP_BODY_FLD_ENC_8BIT
+ EncodingBinary = 2, // should match MAILIMAP_BODY_FLD_ENC_BINARY
+ EncodingBase64 = 3, // should match MAILIMAP_BODY_FLD_ENC_BASE64
+ EncodingQuotedPrintable = 4, // should match MAILIMAP_BODY_FLD_ENC_QUOTED_PRINTABLE
+ EncodingOther = 5, // should match MAILIMAP_BODY_FLD_ENC_OTHER
+ // negative values should be used for other encoding
+ EncodingUUEncode = -1
+ };
+
+ enum IMAPSearchKind {
+ IMAPSearchKindNone,
+ IMAPSearchKindFrom,
+ IMAPSearchKindRecipient,
+ IMAPSearchKindSubject,
+ IMAPSearchKindContent,
+ IMAPSearchKindHeader,
+ IMAPSearchKindOr,
+ IMAPSearchKindAnd,
+ };
+
+ enum ErrorCode {
+ ErrorNone,
+ ErrorConnection,
+ ErrorTLSNotAvailable,
+ ErrorTLSCertificate,
+ ErrorParse,
+ ErrorCertificate,
+ ErrorAuthentication,
+ ErrorGmailIMAPNotEnabled,
+ ErrorGmailExceededBandwidthLimit,
+ ErrorGmailTooManySimultaneousConnections,
+ ErrorMobileMeMoved,
+ ErrorYahooUnavailable,
+ ErrorNonExistantFolder,
+ ErrorRename,
+ ErrorDelete,
+ ErrorCreate,
+ ErrorSubscribe,
+ ErrorAppend,
+ ErrorCopy,
+ ErrorExpunge,
+ ErrorFetch,
+ ErrorIdle,
+ ErrorIdentity,
+ ErrorNamespace,
+ ErrorStore,
+ ErrorStartTLSNotAvailable,
+ ErrorSendMessageIllegalAttachment,
+ ErrorStorageLimit,
+ ErrorSendMessageNotAllowed,
+ ErrorNeedsConnectToWebmail,
+ ErrorSendMessage,
+ ErrorAuthenticationRequired,
+ ErrorFetchMessageList,
+ ErrorDeleteMessage,
+ };
+
+ enum PartType {
+ PartTypeSingle,
+ PartTypeMessage,
+ PartTypeMultipartMixed,
+ PartTypeMultipartRelated,
+ PartTypeMultipartAlternative,
+ };
+}
+
+#endif \ No newline at end of file
diff --git a/src/core/abstract/MCMessageHeader.cc b/src/core/abstract/MCMessageHeader.cc
new file mode 100644
index 00000000..06ad386b
--- /dev/null
+++ b/src/core/abstract/MCMessageHeader.cc
@@ -0,0 +1,1054 @@
+#include "MCMessageHeader.h"
+
+#include "MCAddress.h"
+
+#include <string.h>
+#include <unistd.h>
+
+using namespace mailcore;
+
+static time_t timestamp_from_date(struct mailimf_date_time * date_time);
+static struct mailimf_date_time * get_date_from_timestamp(time_t timeval);
+static time_t timestamp_from_imap_date(struct mailimap_date_time * date_time);
+static time_t mkgmtime(struct tm * tmp);
+static int tmcomp(struct tm * atmp, struct tm * btmp);
+
+static struct mailimf_address_list * lep_address_list_from_array(Array * addresses);
+static struct mailimf_mailbox_list * lep_mailbox_list_from_array(Array * addresses);
+static Array * lep_address_list_from_lep_addr(struct mailimf_address_list * addr_list);
+static Array * lep_address_list_from_lep_mailbox(struct mailimf_mailbox_list * mb_list);
+
+static Array * msg_id_to_string_array(clist * msgids);
+static clist * msg_id_from_string_array(Array * msgids);
+
+#define MAX_HOSTNAME 512
+
+MessageHeader::MessageHeader()
+{
+ init(true, true);
+}
+
+MessageHeader::MessageHeader(MessageHeader * other)
+{
+ init(false, other->mMessageID == NULL);
+ setMessageID(other->mMessageID);
+ setReferences(other->mReferences);
+ setInReplyTo(other->mInReplyTo);
+ setSender(other->mSender);
+ setFrom(other->mFrom);
+ setTo(other->mTo);
+ setCc(other->mCc);
+ setBcc(other->mBcc);
+ setReplyTo(other->mReplyTo);
+ setSubject(other->mSubject);
+ setUserAgent(other->mUserAgent);
+}
+
+void MessageHeader::init(bool generateDate, bool generateMessageID)
+{
+ mMessageID = NULL;
+ mReferences = NULL;
+ mInReplyTo = NULL;
+ mSender = NULL;
+ mFrom = NULL;
+ mTo = NULL;
+ mCc = NULL;
+ mBcc = NULL;
+ mReplyTo = NULL;
+ mSubject = NULL;
+ mDate = (time_t) -1;
+ mReceivedDate = (time_t) -1;
+ mUserAgent = NULL;
+
+ if (generateDate) {
+ time_t date;
+ date = time(NULL);
+ setDate(date);
+ setReceivedDate(date);
+ }
+ if (generateMessageID) {
+ static String * hostname = NULL;
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+ pthread_mutex_lock(&lock);
+ if (hostname == NULL) {
+ char name[MAX_HOSTNAME];
+ int r;
+
+ r = gethostname(name, MAX_HOSTNAME);
+ if (r < 0) {
+ hostname = NULL;
+ }
+ else {
+ hostname = new String(name);
+ }
+ if (hostname == NULL) {
+ hostname = new String("localhost");
+ }
+ }
+ pthread_mutex_unlock(&lock);
+
+ String * messageID = new String();
+ messageID->appendString(String::uuidString());
+ messageID->appendUTF8Characters("@");
+ messageID->appendString(hostname);
+ setMessageID(messageID);
+ messageID->release();
+ }
+}
+
+MessageHeader::~MessageHeader()
+{
+ MC_SAFE_RELEASE(mMessageID);
+ MC_SAFE_RELEASE(mReferences);
+ MC_SAFE_RELEASE(mInReplyTo);
+ MC_SAFE_RELEASE(mSender);
+ MC_SAFE_RELEASE(mFrom);
+ MC_SAFE_RELEASE(mTo);
+ MC_SAFE_RELEASE(mCc);
+ MC_SAFE_RELEASE(mBcc);
+ MC_SAFE_RELEASE(mReplyTo);
+ MC_SAFE_RELEASE(mSubject);
+ MC_SAFE_RELEASE(mUserAgent);
+}
+
+String * MessageHeader::description()
+{
+ String * result = String::string();
+ result->appendUTF8Format("<%s:%p\n", className()->UTF8Characters(), this);
+ if (mMessageID != NULL) {
+ result->appendUTF8Format("Message-ID: %s\n", mMessageID->UTF8Characters());
+ }
+ if (mReferences != NULL) {
+ result->appendUTF8Format("References: %s\n", mReferences->description()->UTF8Characters());
+ }
+ if (mInReplyTo != NULL) {
+ result->appendUTF8Format("In-Reply-To: %s\n", mInReplyTo->description()->UTF8Characters());
+ }
+ if (mSender != NULL) {
+ result->appendUTF8Format("Sender: %s\n", mSender->description()->UTF8Characters());
+ }
+ if (mFrom != NULL) {
+ result->appendUTF8Format("From: %s\n", mFrom->description()->UTF8Characters());
+ }
+ if (mTo != NULL) {
+ result->appendUTF8Format("To: %s\n", mTo->description()->UTF8Characters());
+ }
+ if (mCc != NULL) {
+ result->appendUTF8Format("Cc: %s\n", mCc->description()->UTF8Characters());
+ }
+ if (mBcc != NULL) {
+ result->appendUTF8Format("Bcc: %s\n", mBcc->description()->UTF8Characters());
+ }
+ if (mReplyTo != NULL) {
+ result->appendUTF8Format("Reply-To: %s\n", mReplyTo->description()->UTF8Characters());
+ }
+ if (mSubject != NULL) {
+ result->appendUTF8Format("Subject: %s\n", mSubject->UTF8Characters());
+ }
+ if (mUserAgent != NULL) {
+ result->appendUTF8Format("X-Mailer: %s\n", mUserAgent->UTF8Characters());
+ }
+ result->appendUTF8Format(">");
+
+ return result;
+}
+
+#if 0
+String * MessageHeader::className()
+{
+ return MCSTR("MessageHeader");
+}
+#endif
+
+Object * MessageHeader::copy()
+{
+ return new MessageHeader(this);
+}
+
+void MessageHeader::setMessageID(String * messageID)
+{
+ MC_SAFE_REPLACE_COPY(String, mMessageID, messageID);
+}
+
+String * MessageHeader::messageID()
+{
+ return mMessageID;
+}
+
+void MessageHeader::setReferences(Array * references)
+{
+ MC_SAFE_REPLACE_COPY(Array, mReferences, references);
+}
+
+Array * MessageHeader::references()
+{
+ return mReferences;
+}
+
+void MessageHeader::setInReplyTo(Array * inReplyTo)
+{
+ MC_SAFE_REPLACE_COPY(Array, mInReplyTo, inReplyTo);
+}
+
+Array * MessageHeader::inReplyTo()
+{
+ return mInReplyTo;
+}
+
+void MessageHeader::setDate(time_t date)
+{
+ mDate = date;
+}
+
+time_t MessageHeader::date()
+{
+ return mDate;
+}
+
+void MessageHeader::setReceivedDate(time_t date)
+{
+ mReceivedDate = date;
+}
+
+time_t MessageHeader::receivedDate()
+{
+ return mReceivedDate;
+}
+
+void MessageHeader::setSender(Address * sender)
+{
+ MC_SAFE_REPLACE_RETAIN(Address, mSender, sender);
+}
+
+Address * MessageHeader::sender()
+{
+ return mSender;
+}
+
+void MessageHeader::setFrom(Address * from)
+{
+ MC_SAFE_REPLACE_RETAIN(Address, mFrom, from);
+}
+
+Address * MessageHeader::from()
+{
+ return mFrom;
+}
+
+void MessageHeader::setTo(Array * to)
+{
+ MC_SAFE_REPLACE_COPY(Array, mTo, to);
+}
+
+Array * MessageHeader::to()
+{
+ return mTo;
+}
+
+void MessageHeader::setCc(Array * cc)
+{
+ MC_SAFE_REPLACE_COPY(Array, mCc, cc);
+}
+
+Array * MessageHeader::cc()
+{
+ return mCc;
+}
+
+void MessageHeader::setBcc(Array * bcc)
+{
+ MC_SAFE_REPLACE_COPY(Array, mBcc, bcc);
+}
+
+Array * MessageHeader::bcc()
+{
+ return mBcc;
+}
+
+void MessageHeader::setReplyTo(Array * replyTo)
+{
+ MC_SAFE_REPLACE_COPY(Array, mReplyTo, replyTo);
+}
+
+Array * MessageHeader::replyTo()
+{
+ return mReplyTo;
+}
+
+void MessageHeader::setSubject(String * subject)
+{
+ MC_SAFE_REPLACE_COPY(String, mSubject, subject);
+}
+
+String * MessageHeader::subject()
+{
+ return mSubject;
+}
+
+void MessageHeader::setUserAgent(String * userAgent)
+{
+ MC_SAFE_REPLACE_COPY(String, mUserAgent, userAgent);
+}
+
+String * MessageHeader::userAgent()
+{
+ return mUserAgent;
+}
+
+String * MessageHeader::extractedSubject()
+{
+ return subject()->extractedSubject();
+}
+
+String * MessageHeader::partialExtractedSubject()
+{
+ return subject()->extractedSubjectAndKeepBracket(true);
+}
+
+void MessageHeader::importHeadersData(Data * data)
+{
+ size_t cur_token;
+ struct mailimf_fields * fields;
+ int r;
+
+ cur_token = 0;
+ r = mailimf_fields_parse(data->bytes(), data->length(), &cur_token, &fields);
+ if (r != MAILIMF_NO_ERROR) {
+ return;
+ }
+
+ importIMFFields(fields);
+
+ mailimf_fields_free(fields);
+}
+
+void MessageHeader::importIMFFields(struct mailimf_fields * fields)
+{
+ struct mailimf_single_fields single_fields;
+
+ mailimf_single_fields_init(&single_fields, fields);
+
+ /* date */
+
+ if (single_fields.fld_orig_date != NULL) {
+ time_t timestamp;
+ timestamp = timestamp_from_date(single_fields.fld_orig_date->dt_date_time);
+ setDate(timestamp);
+ setReceivedDate(timestamp);
+ //MCLog("%lu %lu", (unsigned long) timestamp, date());
+ }
+
+ /* subject */
+ if (single_fields.fld_subject != NULL) {
+ char * subject;
+
+ subject = single_fields.fld_subject->sbj_value;
+ setSubject(String::stringByDecodingMIMEHeaderValue(subject));
+ }
+
+ /* sender */
+ if (single_fields.fld_sender != NULL) {
+ struct mailimf_mailbox * mb;
+ Address * address;
+
+ mb = single_fields.fld_sender->snd_mb;
+ if (mb != NULL) {
+ address = Address::addressWithIMFMailbox(mb);
+ setSender(address);
+ }
+ }
+
+ /* from */
+ if (single_fields.fld_from != NULL) {
+ struct mailimf_mailbox_list * mb_list;
+ Array * addresses;
+
+ mb_list = single_fields.fld_from->frm_mb_list;
+ addresses = lep_address_list_from_lep_mailbox(mb_list);
+ if (addresses->count() > 0) {
+ setFrom((Address *) (addresses->objectAtIndex(0)));
+ }
+ }
+
+ /* replyto */
+ if (single_fields.fld_reply_to != NULL) {
+ struct mailimf_address_list * addr_list;
+ Array * addresses;
+
+ addr_list = single_fields.fld_reply_to->rt_addr_list;
+ addresses = lep_address_list_from_lep_addr(addr_list);
+ setReplyTo(addresses);
+ }
+
+ /* to */
+ if (single_fields.fld_to != NULL) {
+ struct mailimf_address_list * addr_list;
+ Array * addresses;
+
+ addr_list = single_fields.fld_to->to_addr_list;
+ addresses = lep_address_list_from_lep_addr(addr_list);
+ setTo(addresses);
+ }
+
+ /* cc */
+ if (single_fields.fld_cc != NULL) {
+ struct mailimf_address_list * addr_list;
+ Array * addresses;
+
+ addr_list = single_fields.fld_cc->cc_addr_list;
+ addresses = lep_address_list_from_lep_addr(addr_list);
+ setCc(addresses);
+ }
+
+ /* bcc */
+ if (single_fields.fld_bcc != NULL) {
+ struct mailimf_address_list * addr_list;
+ Array * addresses;
+
+ addr_list = single_fields.fld_bcc->bcc_addr_list;
+ addresses = lep_address_list_from_lep_addr(addr_list);
+ setBcc(addresses);
+ }
+
+ /* msgid */
+ if (single_fields.fld_message_id != NULL) {
+ char * msgid;
+ String * str;
+
+ msgid = single_fields.fld_message_id->mid_value;
+ str = String::stringWithUTF8Characters(msgid);
+ setMessageID(str);
+ }
+
+ /* references */
+ if (single_fields.fld_references != NULL) {
+ clist * msg_id_list;
+ Array * msgids;
+
+ msg_id_list = single_fields.fld_references->mid_list;
+ msgids = msg_id_to_string_array(msg_id_list);
+ setReferences(msgids);
+ }
+
+ /* inreplyto */
+ if (single_fields.fld_in_reply_to != NULL) {
+ clist * msg_id_list;
+ Array * msgids;
+
+ msg_id_list = single_fields.fld_in_reply_to->mid_list;
+ msgids = msg_id_to_string_array(msg_id_list);
+ setInReplyTo(msgids);
+ }
+}
+
+static time_t timestamp_from_date(struct mailimf_date_time * date_time)
+{
+ struct tm tmval;
+ time_t timeval;
+ int zone_min;
+ int zone_hour;
+
+ tmval.tm_sec = date_time->dt_sec;
+ tmval.tm_min = date_time->dt_min;
+ tmval.tm_hour = date_time->dt_hour;
+ tmval.tm_mday = date_time->dt_day;
+ tmval.tm_mon = date_time->dt_month - 1;
+ if (date_time->dt_year < 1000) {
+ // workaround when century is not given in year
+ tmval.tm_year = date_time->dt_year + 2000 - 1900;
+ }
+ else {
+ tmval.tm_year = date_time->dt_year - 1900;
+ }
+
+ timeval = mkgmtime(&tmval);
+
+ if (date_time->dt_zone >= 0) {
+ zone_hour = date_time->dt_zone / 100;
+ zone_min = date_time->dt_zone % 100;
+ }
+ else {
+ zone_hour = -((- date_time->dt_zone) / 100);
+ zone_min = -((- date_time->dt_zone) % 100);
+ }
+ timeval -= zone_hour * 3600 + zone_min * 60;
+
+ return timeval;
+}
+
+static struct mailimf_date_time * get_date_from_timestamp(time_t timeval)
+{
+ struct tm gmt;
+ struct tm lt;
+ int off;
+ struct mailimf_date_time * date_time;
+ int sign;
+ int hour;
+ int min;
+
+ gmtime_r(&timeval, &gmt);
+ localtime_r(&timeval, &lt);
+
+ off = (mkgmtime(&lt) - mkgmtime(&gmt)) / 60;
+ if (off < 0) {
+ sign = -1;
+ }
+ else {
+ sign = 1;
+ }
+ off = off * sign;
+ min = off % 60;
+ hour = off / 60;
+ off = hour * 100 + min;
+ off = off * sign;
+
+ date_time = mailimf_date_time_new(lt.tm_mday, lt.tm_mon + 1,
+ lt.tm_year + 1900,
+ lt.tm_hour, lt.tm_min, lt.tm_sec,
+ off);
+
+ return date_time;
+}
+
+static time_t timestamp_from_imap_date(struct mailimap_date_time * date_time)
+{
+ struct tm tmval;
+ time_t timeval;
+ int zone_min;
+ int zone_hour;
+
+ tmval.tm_sec = date_time->dt_sec;
+ tmval.tm_min = date_time->dt_min;
+ tmval.tm_hour = date_time->dt_hour;
+ tmval.tm_mday = date_time->dt_day;
+ tmval.tm_mon = date_time->dt_month - 1;
+ if (date_time->dt_year < 1000) {
+ // workaround when century is not given in year
+ tmval.tm_year = date_time->dt_year + 2000 - 1900;
+ }
+ else {
+ tmval.tm_year = date_time->dt_year - 1900;
+ }
+
+ timeval = mkgmtime(&tmval);
+
+ if (date_time->dt_zone >= 0) {
+ zone_hour = date_time->dt_zone / 100;
+ zone_min = date_time->dt_zone % 100;
+ }
+ else {
+ zone_hour = -((- date_time->dt_zone) / 100);
+ zone_min = -((- date_time->dt_zone) % 100);
+ }
+ timeval -= zone_hour * 3600 + zone_min * 60;
+
+ return timeval;
+}
+
+#define INVALID_TIMESTAMP (-1)
+
+static int tmcomp(struct tm * atmp, struct tm * btmp)
+{
+ register int result;
+
+ if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
+ (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
+ (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
+ (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
+ (result = (atmp->tm_min - btmp->tm_min)) == 0)
+ result = atmp->tm_sec - btmp->tm_sec;
+ return result;
+}
+
+static time_t mkgmtime(struct tm * tmp)
+{
+ register int dir;
+ register int bits;
+ register int saved_seconds;
+ time_t t;
+ struct tm yourtm, mytm;
+
+ yourtm = *tmp;
+ saved_seconds = yourtm.tm_sec;
+ yourtm.tm_sec = 0;
+ /*
+ ** Calculate the number of magnitude bits in a time_t
+ ** (this works regardless of whether time_t is
+ ** signed or unsigned, though lint complains if unsigned).
+ */
+ for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
+ ;
+ /*
+ ** If time_t is signed, then 0 is the median value,
+ ** if time_t is unsigned, then 1 << bits is median.
+ */
+ if(bits > 40) bits = 40;
+ t = (t < 0) ? 0 : ((time_t) 1 << bits);
+ for ( ; ; ) {
+ gmtime_r(&t, &mytm);
+ dir = tmcomp(&mytm, &yourtm);
+ if (dir != 0) {
+ if (bits-- < 0) {
+ return INVALID_TIMESTAMP;
+ }
+ if (bits < 0)
+ --t;
+ else if (dir > 0)
+ t -= (time_t) 1 << bits;
+ else t += (time_t) 1 << bits;
+ continue;
+ }
+ break;
+ }
+ t += saved_seconds;
+ return t;
+}
+
+#pragma mark RFC 2822 mailbox conversion
+
+static Array * lep_address_list_from_lep_mailbox(struct mailimf_mailbox_list * mb_list)
+{
+ Array * result;
+ clistiter * cur;
+
+ result = Array::array();
+ for(cur = clist_begin(mb_list->mb_list) ; cur != NULL ; cur = clist_next(cur)) {
+ struct mailimf_mailbox * mb;
+ Address * address;
+
+ mb = (struct mailimf_mailbox *) clist_content(cur);
+ address = Address::addressWithIMFMailbox(mb);
+ result->addObject(address);
+ }
+
+ return result;
+}
+
+static Array * lep_address_list_from_lep_addr(struct mailimf_address_list * addr_list)
+{
+ Array * result;
+ clistiter * cur;
+
+ result = Array::array();
+
+ if (addr_list == NULL) {
+ return result;
+ }
+
+ if (addr_list->ad_list == NULL) {
+ return result;
+ }
+
+ for(cur = clist_begin(addr_list->ad_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimf_address * addr;
+
+ addr = (struct mailimf_address *) clist_content(cur);
+ switch (addr->ad_type) {
+ case MAILIMF_ADDRESS_MAILBOX:
+ {
+ Address * address;
+
+ address = Address::addressWithIMFMailbox(addr->ad_data.ad_mailbox);
+ result->addObject(address);
+ break;
+ }
+
+ case MAILIMF_ADDRESS_GROUP:
+ {
+ if (addr->ad_data.ad_group->grp_mb_list != NULL) {
+ Array * subArray;
+
+ subArray = lep_address_list_from_lep_mailbox(addr->ad_data.ad_group->grp_mb_list);
+ result->addObjectsFromArray(subArray);
+ }
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+static struct mailimf_mailbox_list * lep_mailbox_list_from_array(Array * addresses)
+{
+ struct mailimf_mailbox_list * mb_list;
+
+ if (addresses == NULL)
+ return NULL;
+
+ if (addresses->count() == 0)
+ return NULL;
+
+ mb_list = mailimf_mailbox_list_new_empty();
+
+ for(unsigned i = 0 ; i < addresses->count() ; i ++) {
+ Address * address = (Address *) addresses->objectAtIndex(i);
+ struct mailimf_mailbox * mailbox = address->createIMFMailbox();
+ mailimf_mailbox_list_add(mb_list, mailbox);
+ }
+
+ return mb_list;
+}
+
+static struct mailimf_address_list * lep_address_list_from_array(Array * addresses)
+{
+ struct mailimf_address_list * addr_list;
+
+ if (addresses == NULL)
+ return NULL;
+
+ if (addresses->count() == 0)
+ return NULL;
+
+ addr_list = mailimf_address_list_new_empty();
+
+ for(unsigned i = 0 ; i < addresses->count() ; i ++) {
+ Address * address = (Address *) addresses->objectAtIndex(i);
+ struct mailimf_address * addr = address->createIMFAddress();
+ mailimf_address_list_add(addr_list, addr);
+ }
+
+ return addr_list;
+}
+
+#pragma mark Message-ID conversion
+
+static Array * msg_id_to_string_array(clist * msgids)
+{
+ clistiter * cur;
+ Array * result;
+
+ result = Array::array();
+
+ for(cur = clist_begin(msgids) ; cur != NULL ; cur = clist_next(cur)) {
+ char * msgid;
+ String * str;
+
+ msgid = (char *) clist_content(cur);
+ str = String::stringWithUTF8Characters(msgid);
+ result->addObject(str);
+ }
+
+ return result;
+}
+
+static clist * msg_id_from_string_array(Array * msgids)
+{
+ clist * result;
+
+ if (msgids == NULL)
+ return NULL;
+
+ if (msgids->count() == 0)
+ return NULL;
+
+ result = clist_new();
+ for(unsigned int i = 0 ; i < msgids->count() ; i ++) {
+ String * msgid = (String *) msgids->objectAtIndex(i);
+ clist_append(result, strdup(msgid->UTF8Characters()));
+ }
+
+ return result;
+}
+
+struct mailimf_fields * MessageHeader::createIMFFieldsAndFilterBcc(bool filterBcc)
+{
+ struct mailimf_date_time * imfDate;
+ char * imfMsgid;
+ char * imfSubject;
+ struct mailimf_mailbox_list * imfFrom;
+ struct mailimf_address_list * imfReplyTo;
+ struct mailimf_address_list * imfTo;
+ struct mailimf_address_list * imfCc;
+ struct mailimf_address_list * imfBcc;
+ clist * imfInReplyTo;
+ clist * imfReferences;
+ struct mailimf_fields * fields;
+
+ imfDate = NULL;
+ if (date() != (time_t) -1) {
+ MCLog("%lu", date());
+ imfDate = get_date_from_timestamp(date());
+ }
+ imfFrom = NULL;
+ if (from() != NULL) {
+ imfFrom = lep_mailbox_list_from_array(Array::arrayWithObject(from()));
+ }
+ imfReplyTo = lep_address_list_from_array(replyTo());
+ imfTo = lep_address_list_from_array(to());
+ imfCc = lep_address_list_from_array(cc());
+ imfBcc = NULL;
+ if (!filterBcc) {
+ imfBcc = lep_address_list_from_array(bcc());
+ }
+ imfMsgid = NULL;
+ if (messageID() != NULL) {
+ imfMsgid = strdup(messageID()->UTF8Characters());
+ }
+ imfInReplyTo = msg_id_from_string_array(inReplyTo());
+ imfReferences = msg_id_from_string_array(references());
+ imfSubject = NULL;
+ if ((subject() != NULL) && (subject()->length() > 0)) {
+ Data * data;
+
+ data = subject()->encodedMIMEHeaderValueForSubject();
+ if (data->bytes() != NULL) {
+ imfSubject = strdup(data->bytes());
+ }
+ }
+
+ if ((imfTo == NULL) && (imfCc == NULL) && (imfBcc == NULL)) {
+ imfTo = mailimf_address_list_new_empty();
+ mailimf_address_list_add_parse(imfTo, (char *) "Undisclosed recipients:;");
+ }
+
+ fields = mailimf_fields_new_with_data_all(imfDate,
+ imfFrom,
+ NULL /* sender */,
+ imfReplyTo,
+ imfTo,
+ imfCc,
+ imfBcc,
+ imfMsgid,
+ imfInReplyTo,
+ imfReferences,
+ imfSubject);
+
+ if (mUserAgent != NULL) {
+ struct mailimf_field * field;
+
+ field = mailimf_field_new_custom(strdup("X-Mailer"), strdup(mUserAgent->UTF8Characters()));
+ mailimf_fields_add(fields, field);
+ }
+
+ return fields;
+}
+
+extern "C" {
+ extern int mailimap_hack_date_time_parse(char * str,
+ struct mailimap_date_time ** result,
+ size_t progr_rate,
+ progress_function * progr_fun);
+}
+
+#pragma mark IMAP mailbox conversion
+
+static Array * imap_mailbox_list_to_address_array(clist * imap_mailbox_list)
+{
+ clistiter * cur;
+ Array * result;
+
+ result = Array::array();
+
+ for(cur = clist_begin(imap_mailbox_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimap_address * imap_addr;
+ Address * address;
+
+ imap_addr = (struct mailimap_address *) clist_content(cur);
+ address = Address::addressWithIMAPAddress(imap_addr);
+ result->addObject(address);
+ }
+
+ return result;
+}
+
+void MessageHeader::importIMAPEnvelope(struct mailimap_envelope * env)
+{
+ if (env->env_date != NULL) {
+ size_t cur_token;
+ struct mailimf_date_time * date_time;
+ int r;
+
+ cur_token = 0;
+ r = mailimf_date_time_parse(env->env_date, strlen(env->env_date),
+ &cur_token, &date_time);
+ if (r == MAILIMF_NO_ERROR) {
+ time_t timestamp;
+
+ // date
+ timestamp = timestamp_from_date(date_time);
+ setDate(timestamp);
+ setReceivedDate(timestamp);
+ mailimf_date_time_free(date_time);
+ }
+ else {
+ struct mailimap_date_time * imap_date;
+
+ r = mailimap_hack_date_time_parse(env->env_date, &imap_date, 0, NULL);
+ if (r == MAILIMAP_NO_ERROR) {
+ time_t timestamp;
+
+ timestamp = timestamp_from_imap_date(imap_date);
+ setDate(timestamp);
+ setReceivedDate(timestamp);
+ mailimap_date_time_free(imap_date);
+ }
+ }
+ }
+
+ if (env->env_subject != NULL) {
+ char * subject;
+
+ // subject
+ subject = env->env_subject;
+ setSubject(String::stringByDecodingMIMEHeaderValue(subject));
+ }
+
+ if (env->env_sender != NULL) {
+ if (env->env_sender->snd_list != NULL) {
+ Array * addresses;
+
+ addresses = imap_mailbox_list_to_address_array(env->env_sender->snd_list);
+ if (addresses->count() > 0) {
+ setSender((Address *) addresses->objectAtIndex(0));
+ }
+ }
+ }
+
+ if (env->env_from != NULL) {
+ if (env->env_from->frm_list != NULL) {
+ Array * addresses;
+
+ addresses = imap_mailbox_list_to_address_array(env->env_from->frm_list);
+ if (addresses->count() > 0) {
+ setFrom((Address *) addresses->objectAtIndex(0));
+ }
+ }
+ }
+
+ // skip Sender header
+
+ if (env->env_reply_to != NULL) {
+ if (env->env_reply_to->rt_list != NULL) {
+ Array * addresses;
+
+ addresses = imap_mailbox_list_to_address_array(env->env_reply_to->rt_list);
+ setReplyTo(addresses);
+ }
+ }
+
+ if (env->env_to != NULL) {
+ if (env->env_to->to_list != NULL) {
+ Array * addresses;
+
+ addresses = imap_mailbox_list_to_address_array(env->env_to->to_list);
+ setTo(addresses);
+ }
+ }
+
+ if (env->env_cc != NULL) {
+ if (env->env_cc->cc_list != NULL) {
+ Array * addresses;
+
+ addresses = imap_mailbox_list_to_address_array(env->env_cc->cc_list);
+ setCc(addresses);
+ }
+ }
+
+ if (env->env_bcc != NULL) {
+ if (env->env_bcc->bcc_list != NULL) {
+ Array * addresses;
+
+ addresses = imap_mailbox_list_to_address_array(env->env_bcc->bcc_list);
+ setBcc(addresses);
+ }
+ }
+
+ if (env->env_in_reply_to != NULL) {
+ size_t cur_token;
+ clist * msg_id_list;
+ int r;
+
+ cur_token = 0;
+ r = mailimf_msg_id_list_parse(env->env_in_reply_to,
+ strlen(env->env_in_reply_to), &cur_token, &msg_id_list);
+ if (r == MAILIMF_NO_ERROR) {
+ Array * msgids;
+
+ msgids = msg_id_to_string_array(msg_id_list);
+ setInReplyTo(msgids);
+ // in-reply-to
+ clist_foreach(msg_id_list, (clist_func) mailimf_msg_id_free, NULL);
+ clist_free(msg_id_list);
+ }
+ }
+
+ if (env->env_message_id != NULL) {
+ char * msgid;
+ size_t cur_token;
+ int r;
+
+ cur_token = 0;
+ r = mailimf_msg_id_parse(env->env_message_id, strlen(env->env_message_id),
+ &cur_token, &msgid);
+ if (r == MAILIMF_NO_ERROR) {
+ // msg id
+ String * str;
+
+ str = String::stringWithUTF8Characters(msgid);
+ setMessageID(str);
+ mailimf_msg_id_free(msgid);
+ }
+ }
+}
+
+void MessageHeader::importIMAPReferences(Data * data)
+{
+ size_t cur_token;
+ struct mailimf_fields * fields;
+ int r;
+ struct mailimf_single_fields single_fields;
+
+ cur_token = 0;
+ r = mailimf_fields_parse(data->bytes(), data->length(), &cur_token, &fields);
+ if (r != MAILIMF_NO_ERROR) {
+ return;
+ }
+
+ mailimf_single_fields_init(&single_fields, fields);
+ if (single_fields.fld_references != NULL) {
+ Array * msgids;
+
+ msgids = msg_id_to_string_array(single_fields.fld_references->mid_list);
+ setReferences(msgids);
+ }
+ if (single_fields.fld_subject != NULL) {
+ if (single_fields.fld_subject->sbj_value != NULL) {
+ bool broken;
+ char * value;
+ bool isASCII;
+
+ broken = false;
+ value = single_fields.fld_subject->sbj_value;
+
+ isASCII = true;
+ for(char * p = value ; * p != 0 ; p ++) {
+ if ((unsigned char) * p >= 128) {
+ isASCII = false;
+ }
+ }
+ if (strstr(value, "windows-1251") == NULL) {
+ if (isASCII) {
+ broken = true;
+ }
+ }
+
+ //MCLog("charset: %s %s", value, MCUTF8(charset));
+
+ if (!broken) {
+ setSubject(String::stringByDecodingMIMEHeaderValue(single_fields.fld_subject->sbj_value));
+ }
+ }
+ }
+
+ mailimf_fields_free(fields);
+}
+
+void MessageHeader::importIMAPInternalDate(struct mailimap_date_time * date)
+{
+ setReceivedDate(timestamp_from_imap_date(date));
+}
+
diff --git a/src/core/abstract/MCMessageHeader.h b/src/core/abstract/MCMessageHeader.h
new file mode 100644
index 00000000..5a7483e2
--- /dev/null
+++ b/src/core/abstract/MCMessageHeader.h
@@ -0,0 +1,90 @@
+#ifndef __MAILCORE_MCMESSAGEHEADER_H_
+
+#define __MAILCORE_MCMESSAGEHEADER_H_
+
+#include <mailcore/MCBaseTypes.h>
+#include <time.h>
+
+namespace mailcore {
+
+ class Address;
+
+ class MessageHeader : public Object {
+ private:
+ String * mMessageID;
+ Array * /* String */ mReferences;
+ Array * /* String */ mInReplyTo;
+ Address * mSender;
+ Address * mFrom;
+ Array * /* Address */ mTo;
+ Array * /* Address */ mCc;
+ Array * /* Address */ mBcc;
+ Array * /* Address */ mReplyTo;
+ String * mSubject;
+ time_t mDate;
+ time_t mReceivedDate;
+ String * mUserAgent;
+ void init(bool generateDate, bool generateMessageID);
+
+ public:
+ MessageHeader();
+ MessageHeader(MessageHeader * other);
+ virtual ~MessageHeader();
+
+ virtual String * description();
+ //virtual String * className();
+ virtual Object * copy();
+
+ virtual void setMessageID(String * messageID);
+ virtual String * messageID();
+
+ virtual void setReferences(Array * references);
+ virtual Array * references();
+
+ virtual void setInReplyTo(Array * inReplyTo);
+ virtual Array * inReplyTo();
+
+ virtual void setDate(time_t date);
+ virtual time_t date();
+
+ virtual void setReceivedDate(time_t date);
+ virtual time_t receivedDate();
+
+ virtual void setSender(Address * sender);
+ virtual Address * sender();
+
+ virtual void setFrom(Address * from);
+ virtual Address * from();
+
+ virtual void setTo(Array * to);
+ virtual Array * to();
+
+ virtual void setCc(Array * cc);
+ virtual Array * cc();
+
+ virtual void setBcc(Array * bcc);
+ virtual Array * bcc();
+
+ virtual void setReplyTo(Array * replyTo);
+ virtual Array * replyTo();
+
+ virtual void setSubject(String * subject);
+ virtual String * subject();
+
+ virtual void setUserAgent(String * userAgent);
+ virtual String * userAgent();
+
+ virtual String * extractedSubject();
+ virtual String * partialExtractedSubject();
+ virtual void importHeadersData(Data * data);
+ virtual void importIMAPEnvelope(struct mailimap_envelope * env);
+ virtual void importIMAPReferences(Data * data);
+ virtual void importIMAPInternalDate(struct mailimap_date_time * date);
+
+ virtual struct mailimf_fields * createIMFFieldsAndFilterBcc(bool filterBcc);
+ virtual void importIMFFields(struct mailimf_fields * fields);
+ };
+
+}
+
+#endif
diff --git a/src/core/basetypes/.DS_Store b/src/core/basetypes/.DS_Store
new file mode 100644
index 00000000..5008ddfc
--- /dev/null
+++ b/src/core/basetypes/.DS_Store
Binary files differ
diff --git a/src/core/basetypes/MCArray.cc b/src/core/basetypes/MCArray.cc
new file mode 100644
index 00000000..6b4df259
--- /dev/null
+++ b/src/core/basetypes/MCArray.cc
@@ -0,0 +1,229 @@
+#include "MCArray.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "MCAssert.h"
+#include "MCString.h"
+#include "MCLog.h"
+#include "MCUtils.h"
+
+using namespace mailcore;
+
+Array::Array()
+{
+ init();
+}
+
+Array::Array(Array * other) : Object()
+{
+ init();
+ for(unsigned int i = 0 ; i < other->count() ; i ++) {
+ Object * obj = other->objectAtIndex(i);
+ addObject(obj);
+ }
+}
+
+void Array::init()
+{
+ mArray = carray_new(4);
+}
+
+Array::~Array()
+{
+ removeAllObjects();
+ carray_free(mArray);
+}
+
+Array * Array::array()
+{
+ Array * result = new Array();
+ return (Array *) result->autorelease();
+}
+
+Array * Array::arrayWithObject(Object * obj)
+{
+ Array * result = new Array();
+ result->addObject(obj);
+ return (Array *) result->autorelease();
+}
+
+#if 0
+String * Array::className()
+{
+ return MCSTR("Array");
+}
+#endif
+
+String * Array::description()
+{
+ String * result = String::string();
+
+ result->appendUTF8Characters("[");
+ for(unsigned int i = 0 ; i < count() ; i ++) {
+ if (i != 0) {
+ result->appendUTF8Characters(",");
+ }
+ Object * obj = objectAtIndex(i);
+ result->appendString(obj->description());
+ }
+ result->appendUTF8Characters("]");
+
+ return result;
+}
+
+Object * Array::copy()
+{
+ return new Array(this);
+}
+
+unsigned int Array::count()
+{
+ return carray_count(mArray);
+}
+
+void Array::addObject(Object * obj)
+{
+ unsigned int idx;
+ obj->retain();
+ carray_add(mArray, obj, &idx);
+}
+
+void Array::removeObjectAtIndex(unsigned int idx)
+{
+ Object * obj = (Object *) carray_get(mArray, idx);
+ obj->release();
+ carray_delete_slow(mArray, idx);
+}
+
+void Array::removeObject(Object * obj)
+{
+ unsigned int idx = indexOfObject(obj);
+ removeObjectAtIndex(idx);
+}
+
+int Array::indexOfObject(Object * obj)
+{
+ for(unsigned int i = 0 ; i < count() ; i ++) {
+ Object * currentObj = objectAtIndex(i);
+ if (currentObj->isEqual(obj)) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+Object * Array::objectAtIndex(unsigned int idx)
+{
+ Object * obj = (Object *) carray_get(mArray, idx);
+ return obj;
+}
+
+void Array::replaceObject(unsigned int idx, Object * obj)
+{
+ if (idx < count()) {
+ Object * previousObject = (Object *) carray_get(mArray, idx);
+ previousObject->release();
+ obj->retain();
+ carray_set(mArray, idx, obj);
+ }
+ else if (idx == count()) {
+ addObject(obj);
+ }
+ else {
+ MCAssert(0);
+ }
+}
+
+void Array::insertObject(unsigned int idx, Object * obj)
+{
+ if (idx < count()) {
+ int count = carray_count(mArray) - idx;
+ carray_set_size(mArray, count + 1);
+ void ** p = carray_data(mArray);
+ memmove(p + idx + 1, p + idx, count * sizeof(* p));
+ obj->retain();
+ carray_set(mArray, idx, obj);
+ }
+ else if (idx == count()) {
+ addObject(obj);
+ }
+ else {
+ MCAssert(0);
+ }
+}
+
+void Array::removeAllObjects()
+{
+ for(unsigned int i = 0 ; i < count() ; i ++) {
+ Object * obj = objectAtIndex(i);
+ obj->release();
+ }
+ carray_set_size(mArray, 0);
+}
+
+void Array::addObjectsFromArray(Array * array)
+{
+ if (array == NULL)
+ return;
+
+ for(unsigned int i = 0 ; i < array->count() ; i ++) {
+ Object * obj = array->objectAtIndex(i);
+ addObject(obj);
+ }
+}
+
+Object * Array::lastObject()
+{
+ if (count() == 0)
+ return NULL;
+
+ return objectAtIndex(count() - 1);
+}
+
+bool Array::containsObject(Object * obj)
+{
+ return (indexOfObject(obj) != -1);
+}
+
+struct sortData {
+ int (* compare)(void *, void *, void *);
+ void * context;
+};
+
+static int sortCompare(struct sortData * data, Object ** pa, Object ** pb)
+{
+ Object * a;
+ Object * b;
+
+ a = * pa;
+ b = * pb;
+
+ return data->compare(a, b, data->context);
+}
+
+Array * Array::sortedArray(int (* compare)(void *, void *, void *), void * context)
+{
+ struct sortData data;
+ Array * result = (Array *) this->copy()->autorelease();
+ data.compare = compare;
+ data.context = context;
+ qsort_r(carray_data(result->mArray), carray_count(result->mArray),
+ sizeof(* carray_data(result->mArray)), this,
+ (int (*)(void *, const void *, const void *)) sortCompare);
+ return result;
+}
+
+String * Array::componentsJoinedByString(String * delimiter)
+{
+ String * result = String::string();
+ for(unsigned int i = 0 ; i < count() ; i ++) {
+ Object * obj = objectAtIndex(i);
+ if (result != 0) {
+ result->appendString(delimiter);
+ }
+ result->appendString(obj->description());
+ }
+ return result;
+}
diff --git a/src/core/basetypes/MCArray.h b/src/core/basetypes/MCArray.h
new file mode 100644
index 00000000..a0abc243
--- /dev/null
+++ b/src/core/basetypes/MCArray.h
@@ -0,0 +1,49 @@
+#ifndef __MAILCORE_MCARRAY_H_
+
+#define __MAILCORE_MCARRAY_H_
+
+#include <mailcore/MCObject.h>
+
+#include <libetpan/libetpan.h>
+
+namespace mailcore {
+
+ class String;
+
+ class Array : public Object {
+ private:
+ carray * mArray;
+ void init();
+ public:
+ Array();
+ Array(Array * o);
+ virtual ~Array();
+
+ static Array * array();
+ static Array * arrayWithObject(Object * obj);
+
+ //virtual String * className();
+ virtual String * description();
+ virtual Object * copy();
+
+ virtual unsigned int count();
+ virtual void addObject(Object * obj);
+ virtual void removeObjectAtIndex(unsigned int idx);
+ virtual void removeObject(Object * obj);
+ virtual int indexOfObject(Object * obj);
+ virtual Object * objectAtIndex(unsigned int idx);
+ virtual void replaceObject(unsigned int idx, Object * obj);
+ virtual void insertObject(unsigned int idx, Object * obj);
+ virtual void removeAllObjects();
+
+ virtual void addObjectsFromArray(Array * array);
+ virtual Object * lastObject();
+ virtual bool containsObject(Object * obj);
+
+ virtual Array * sortedArray(int (* compare)(void *, void *, void *), void * context);
+ virtual String * componentsJoinedByString(String * delimiter);
+ };
+
+}
+
+#endif
diff --git a/src/core/basetypes/MCAssert.cc b/src/core/basetypes/MCAssert.cc
new file mode 100644
index 00000000..afe9bfd5
--- /dev/null
+++ b/src/core/basetypes/MCAssert.cc
@@ -0,0 +1,12 @@
+#include "MCAssert.h"
+
+#include <stdio.h>
+
+void mailcore::assertInteral(const char * filename, unsigned int line, int cond, const char * condString)
+{
+ if (cond) {
+ return;
+ }
+
+ fprintf(stderr, "%s:%i: assert %s\n", filename, line, condString);
+}
diff --git a/src/core/basetypes/MCAssert.h b/src/core/basetypes/MCAssert.h
new file mode 100644
index 00000000..cc13aba8
--- /dev/null
+++ b/src/core/basetypes/MCAssert.h
@@ -0,0 +1,13 @@
+#ifndef __MAILCORE_MCASSERT_H_
+
+#define __MAILCORE_MCASSERT_H_
+
+#define MCAssert(cond) mailcore::assertInteral(__FILE__, __LINE__, cond, #cond)
+
+namespace mailcore {
+
+ void assertInteral(const char * filename, unsigned int line, int cond, const char * condString);
+
+}
+
+#endif
diff --git a/src/core/basetypes/MCAutoreleasePool.cc b/src/core/basetypes/MCAutoreleasePool.cc
new file mode 100644
index 00000000..7e43734f
--- /dev/null
+++ b/src/core/basetypes/MCAutoreleasePool.cc
@@ -0,0 +1,119 @@
+#include "MCAutoreleasePool.h"
+
+#include "MCString.h"
+#include "MCLog.h"
+#include "MCUtils.h"
+
+using namespace mailcore;
+
+pthread_key_t AutoreleasePool::autoreleasePoolStackKey;
+
+void AutoreleasePool::init()
+{
+ static pthread_once_t once = PTHREAD_ONCE_INIT;
+ pthread_once(&once, initAutoreleasePoolStackKey);
+}
+
+AutoreleasePool::AutoreleasePool()
+{
+ mPoolObjects = carray_new(4);
+
+ unsigned int idx;
+ carray * stack = createAutoreleasePoolStackIfNeeded();
+ carray_add(stack, this, &idx);
+}
+
+AutoreleasePool::~AutoreleasePool()
+{
+ carray * stack = createAutoreleasePoolStackIfNeeded();
+ carray_delete_slow(stack, carray_count(stack) - 1);
+
+ unsigned int count = carray_count(mPoolObjects);
+ for(unsigned int i = 0 ; i < count ; i ++) {
+ Object * obj = (Object *) carray_get(mPoolObjects, i);
+ obj->release();
+ }
+ carray_free(mPoolObjects);
+}
+
+carray * AutoreleasePool::createAutoreleasePoolStackIfNeeded()
+{
+ init();
+ carray * stack = (carray *) pthread_getspecific(autoreleasePoolStackKey);
+ if (stack != NULL) {
+ return stack;
+ }
+
+ stack = carray_new(4);
+ pthread_setspecific(autoreleasePoolStackKey, stack);
+
+ return stack;
+}
+
+void AutoreleasePool::destroyAutoreleasePoolStack(void *)
+{
+ init();
+ carray * stack = (carray *) pthread_getspecific(autoreleasePoolStackKey);
+ if (carray_count(stack) != 0) {
+ MCLog("some autoreleasepool have not been released\n");
+ }
+ carray_free(stack);
+}
+
+void AutoreleasePool::initAutoreleasePoolStackKey()
+{
+ pthread_key_create(&autoreleasePoolStackKey, destroyAutoreleasePoolStack);
+}
+
+AutoreleasePool * AutoreleasePool::currentAutoreleasePool()
+{
+ init();
+ carray * stack;
+ stack = createAutoreleasePoolStackIfNeeded();
+ if (carray_count(stack) == 0) {
+ //fprintf(stderr, "no current autoreleasepool\n");
+ return NULL;
+ }
+
+ AutoreleasePool * pool;
+ pool = (AutoreleasePool *) carray_get(stack, carray_count(stack) - 1);
+ return pool;
+}
+
+void AutoreleasePool::add(Object * obj)
+{
+ unsigned int idx;
+ carray_add(mPoolObjects, obj, &idx);
+}
+
+void AutoreleasePool::autorelease(Object * obj)
+{
+ AutoreleasePool * pool = AutoreleasePool::currentAutoreleasePool();
+ if (pool == NULL) {
+ MCLog("-autorelease called with no current autoreleasepool\n");
+ return;
+ }
+ pool->add(obj);
+}
+
+String * AutoreleasePool::className()
+{
+ return MCSTR("AutoreleasePool");
+}
+
+String * AutoreleasePool::description()
+{
+ String * result = String::string();
+ result->appendUTF8Format("<%p:%p ", className(), this);
+ unsigned int count = carray_count(mPoolObjects);
+ for(unsigned int i = 0 ; i < count ; i ++) {
+ Object * obj = (Object *) carray_get(mPoolObjects, i);
+ if (i != 0) {
+ result->appendUTF8Characters(" ");
+ }
+ result->appendString(obj->description());
+ }
+ result->appendUTF8Characters(">");
+
+ return result;
+}
diff --git a/src/core/basetypes/MCAutoreleasePool.h b/src/core/basetypes/MCAutoreleasePool.h
new file mode 100644
index 00000000..ee30de87
--- /dev/null
+++ b/src/core/basetypes/MCAutoreleasePool.h
@@ -0,0 +1,34 @@
+#ifndef __MAILCORE_MCAUTORELEASEPOOL_H_
+
+#define __MAILCORE_MCAUTORELEASEPOOL_H_
+
+#include <mailcore/MCObject.h>
+#include <libetpan/libetpan.h>
+#include <pthread.h>
+
+namespace mailcore {
+
+ class AutoreleasePool : public Object {
+ private:
+ static void init();
+ static pthread_key_t autoreleasePoolStackKey;
+ carray * mPoolObjects;
+ static carray * createAutoreleasePoolStackIfNeeded();
+ static void destroyAutoreleasePoolStack(void *);
+ static void initAutoreleasePoolStackKey();
+ static AutoreleasePool * currentAutoreleasePool();
+ virtual void add(Object * obj);
+
+ public:
+ AutoreleasePool();
+ virtual ~AutoreleasePool();
+
+ virtual String * className();
+ virtual String * description();
+
+ static void autorelease(Object * obj);
+ };
+
+}
+
+#endif
diff --git a/src/core/basetypes/MCBaseTypes.h b/src/core/basetypes/MCBaseTypes.h
new file mode 100644
index 00000000..0f86dfb7
--- /dev/null
+++ b/src/core/basetypes/MCBaseTypes.h
@@ -0,0 +1,21 @@
+#ifndef __MAILCORE_MCBASETYPES_H_
+
+#define __MAILCORE_MCBASETYPES_H_
+
+#include <mailcore/MCAutoreleasePool.h>
+#include <mailcore/MCObject.h>
+#include <mailcore/MCValue.h>
+#include <mailcore/MCString.h>
+#include <mailcore/MCData.h>
+#include <mailcore/MCArray.h>
+#include <mailcore/MCHashMap.h>
+#include <mailcore/MCHash.h>
+#include <mailcore/MCLog.h>
+#include <mailcore/MCAssert.h>
+#include <mailcore/MCUtils.h>
+#include <mailcore/MCRange.h>
+#include <mailcore/MCOperation.h>
+#include <mailcore/MCOperationQueue.h>
+#include <mailcore/MCOperationCallback.h>
+
+#endif
diff --git a/src/core/basetypes/MCData.cc b/src/core/basetypes/MCData.cc
new file mode 100644
index 00000000..4550bff8
--- /dev/null
+++ b/src/core/basetypes/MCData.cc
@@ -0,0 +1,526 @@
+#include "MCData.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unicode/ucsdet.h>
+#include <libetpan/libetpan.h>
+
+#include "MCString.h"
+#include "MCHash.h"
+#include "MCUtils.h"
+
+#define DEFAULT_CHARSET "iso-8859-1"
+
+using namespace mailcore;
+
+void Data::allocate(unsigned int length)
+{
+ length ++;
+ if (length < mAllocated)
+ return;
+
+ if (mAllocated == 0) {
+ mAllocated = 4;
+ }
+ while (length > mAllocated) {
+ mAllocated *= 2;
+ }
+
+ mBytes = (char *) realloc(mBytes, mAllocated);
+}
+
+void Data::reset()
+{
+ free(mBytes);
+ mAllocated = 0;
+ mLength = 0;
+ mBytes = NULL;
+}
+
+Data::Data()
+{
+ mBytes = NULL;
+ reset();
+}
+
+Data::Data(Data * otherData) : Object()
+{
+ mBytes = NULL;
+ reset();
+ appendData(otherData);
+}
+
+Data::Data(const char * bytes, unsigned int length)
+{
+ mBytes = NULL;
+ reset();
+ appendBytes(bytes, length);
+}
+
+Data::Data(int capacity)
+{
+ mBytes = NULL;
+ reset();
+ allocate(capacity);
+}
+
+Data::~Data()
+{
+ reset();
+}
+
+Data * Data::dataWithBytes(const char * bytes, unsigned int length)
+{
+ Data * result = new Data(bytes, length);
+ return (Data *) result->autorelease();
+}
+
+char * Data::bytes()
+{
+ return mBytes;
+}
+
+unsigned int Data::length()
+{
+ return mLength;
+}
+
+void Data::appendData(Data * otherData)
+{
+ appendBytes(otherData->bytes(), otherData->length());
+}
+
+void Data::appendBytes(const char * bytes, unsigned int length)
+{
+ allocate(mLength + length);
+ memcpy(&mBytes[mLength], bytes, length);
+ mLength += length;
+}
+
+void Data::setBytes(const char * bytes, unsigned int length)
+{
+ reset();
+ appendBytes(bytes, length);
+}
+
+void Data::setData(Data * otherData)
+{
+ reset();
+ appendData(otherData);
+}
+
+#if 0
+String * Data::className()
+{
+ return MCSTR("Data");
+}
+#endif
+
+String * Data::description()
+{
+ return String::stringWithUTF8Format("<%s:%p %i bytes>", MCUTF8(className()), this, length());
+}
+
+Object * Data::copy()
+{
+ return new Data(this);
+}
+
+bool Data::isEqual(Object * otherObject)
+{
+ Data * otherData = (Data *) otherObject;
+ if (length() != otherData->length())
+ return false;
+ if (memcmp(bytes(), otherData->bytes(), mLength) != 0)
+ return false;
+ return true;
+}
+
+unsigned int Data::hash()
+{
+ return hashCompute(mBytes, mLength);
+}
+
+String * Data::stringWithDetectedCharset()
+{
+ String * charset;
+ String * result;
+
+ charset = charsetWithFilteredHTML(false);
+ if (charset == NULL) {
+ charset = MCSTR(DEFAULT_CHARSET);
+ }
+ result = emailStringWithCharset(charset);
+ if (result == NULL) {
+ result = stringWithCharset("utf-8");
+ }
+ return result;
+}
+
+String * Data::normalizeCharset(String * charset)
+{
+ if ((charset->caseInsensitiveCompare(MCSTR("iso-2022-jp")) == 0) ||
+ (charset->caseInsensitiveCompare(MCSTR("iso-2022-jp-2")) == 0)) {
+ charset = MCSTR("iso-2022-jp-2");
+ }
+ else if (charset->caseInsensitiveCompare(MCSTR("ks_c_5601-1987")) == 0) {
+ charset = MCSTR("euckr");
+ }
+ else if ((charset->caseInsensitiveCompare(MCSTR("iso-8859-8-i")) == 0) ||
+ (charset->caseInsensitiveCompare(MCSTR("iso-8859-8-e")) == 0)) {
+ charset = MCSTR("iso-8859-8");
+ }
+ else if ((charset->caseInsensitiveCompare(MCSTR("GB2312")) == 0) ||
+ (charset->caseInsensitiveCompare(MCSTR("GB_2312-80")) == 0)) {
+ charset = MCSTR("GBK");
+ }
+
+ return charset->lowercaseString();
+}
+
+String * Data::stringWithCharset(const char * charset)
+{
+ String * result = new String(this, charset);
+ return (String *) result->autorelease();
+}
+
+String * Data::emailStringWithCharset(String * charset)
+{
+ String * result;
+
+ charset = normalizeCharset(charset);
+
+ if (charset->isEqual(MCSTR("iso-2022-jp-2"))) {
+ const char * theBytes;
+ Data * data;
+
+ theBytes = bytes();
+ data = this;
+ if (length() > 0) {
+ unsigned int idx;
+
+ idx = length();
+ while ((theBytes[idx - 1] == '\n') || (theBytes[idx - 1] == '\r')) {
+ idx --;
+ if (idx == 0)
+ break;
+ }
+
+ if (idx != length()) {
+ data = Data::dataWithBytes(theBytes, idx);
+ }
+ }
+ result = data->stringWithCharset("iso-2022-jp-2");
+ if (result == NULL) {
+ result = data->stringWithCharset("iso-2022-jp");
+ }
+
+ return result;
+ }
+
+ result = stringWithCharset(charset->UTF8Characters());
+ return result;
+}
+
+String * Data::charsetWithFilteredHTMLWithoutHint(bool filterHTML)
+{
+ UCharsetDetector * detector;
+ const UCharsetMatch * match;
+ UErrorCode err = U_ZERO_ERROR;
+ const char * cName;
+ String * result;
+
+ detector = ucsdet_open(&err);
+ ucsdet_setText(detector, bytes(), length(), &err);
+ ucsdet_enableInputFilter(detector, filterHTML);
+ match = ucsdet_detect(detector, &err);
+ if (match == NULL) {
+ ucsdet_close(detector);
+ return NULL;
+ }
+
+ cName = ucsdet_getName(match, &err);
+
+ result = String::stringWithUTF8Characters(cName);
+ ucsdet_close(detector);
+
+ return result;
+}
+
+String * Data::charsetWithFilteredHTML(bool filterHTML, String * hintCharset)
+{
+ if (hintCharset == NULL)
+ return charsetWithFilteredHTMLWithoutHint(filterHTML);
+
+ const UCharsetMatch ** matches;
+ int32_t matchesCount;
+ UCharsetDetector * detector;
+ UErrorCode err = U_ZERO_ERROR;
+ String * result;
+
+ hintCharset = hintCharset->lowercaseString();
+
+ detector = ucsdet_open(&err);
+ ucsdet_setText(detector, bytes(), length(), &err);
+ ucsdet_enableInputFilter(detector, filterHTML);
+ matches = ucsdet_detectAll(detector, &matchesCount, &err);
+ if (matches == NULL) {
+ ucsdet_close(detector);
+ return hintCharset;
+ }
+ if (matchesCount == 0) {
+ ucsdet_close(detector);
+ return hintCharset;
+ }
+
+ result = NULL;
+
+ for(int32_t i = 0 ; i < matchesCount ; i ++) {
+ const char * cName;
+ String * name;
+ int32_t confidence;
+
+ cName = ucsdet_getName(matches[i], &err);
+ name = String::stringWithUTF8Characters(cName);
+ name = name->lowercaseString();
+ confidence = ucsdet_getConfidence(matches[i], &err);
+ if ((confidence >= 50) && name->isEqual(hintCharset)) {
+ result = name;
+ break;
+ }
+ }
+
+ if (result == NULL) {
+ int32_t maxConfidence;
+
+ maxConfidence = 49;
+
+ for(int32_t i = 0 ; i < matchesCount ; i ++) {
+ const char * cName;
+ String * name;
+ int32_t confidence;
+
+ cName = ucsdet_getName(matches[i], &err);
+ confidence = ucsdet_getConfidence(matches[i], &err);
+ name = String::stringWithUTF8Characters(cName);
+ if (confidence > maxConfidence) {
+ result = name;
+ maxConfidence = confidence;
+ }
+ }
+ }
+ ucsdet_close(detector);
+
+ if (result == NULL)
+ result = hintCharset;
+
+ return result;
+}
+
+Data * Data::dataWithContentsOfFile(String * filename)
+{
+ int r;
+ size_t read_items;
+ struct stat stat_buf;
+ FILE * f;
+ char * buf;
+ Data * data;
+
+ f = fopen(filename->fileSystemRepresentation(), "rb");
+ if (f == NULL) {
+ return NULL;
+ }
+
+ r = fstat(fileno(f), &stat_buf);
+ if (r < 0) {
+ fclose(f);
+ return NULL;
+ }
+
+ buf = (char *) malloc(stat_buf.st_size);
+
+ read_items = fread(buf, 1, stat_buf.st_size, f);
+ if ((off_t) read_items != stat_buf.st_size) {
+ free(buf);
+ fclose(f);
+ return NULL;
+ }
+
+ data = Data::dataWithBytes(buf, (unsigned int) stat_buf.st_size);
+ free(buf);
+
+ fclose(f);
+
+ return data;
+}
+
+static size_t uudecode(char * text, size_t size)
+{
+ unsigned int count = 0;
+ char *b = text; /* beg */
+ char *s = b; /* src */
+ char *d = b; /* dst */
+ char *e = b+size; /* end */
+ int out = (*s++ & 0x7f) - 0x20;
+
+ /* don't process lines without leading count character */
+ if (out < 0)
+ 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)
+ {
+ 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;
+ }
+ *d = (char) '\0';
+ return count;
+}
+
+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::dataWithBytes(decoded, (unsigned int) decoded_length);
+ mailmime_decoded_part_free(decoded);
+ return data;
+ }
+ case EncodingUUEncode:
+ {
+ char * dup_data;
+ size_t decoded_length;
+ Data * data;
+ char * current_p;
+
+ data = Data::dataWithCapacity((unsigned int) text_length);
+
+ dup_data = (char *) malloc(text_length);
+ memcpy(dup_data, text, text_length);
+
+ current_p = dup_data;
+ while (1) {
+ size_t length;
+ char * p;
+ char * p1;
+ char * p2;
+ 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 - dup_data) < text_length) {
+ if ((* p != '\r') && (* p != '\n')) {
+ break;
+ }
+ p ++;
+ }
+ }
+ if (p == NULL) {
+ length = text_length - (current_p - dup_data);
+ }
+ else {
+ length = end_line - current_p;
+ }
+ if (length == 0) {
+ break;
+ }
+ decoded_length = uudecode(current_p, length);
+ if (decoded_length != 0 && decoded_length < length) {
+ data->appendBytes(current_p, (unsigned int) decoded_length);
+ }
+
+ if (p == NULL)
+ break;
+
+ current_p = p;
+ while ((size_t) (current_p - dup_data) < text_length) {
+ if ((* current_p != '\r') && (* current_p != '\n')) {
+ break;
+ }
+ current_p ++;
+ }
+ }
+ free(dup_data);
+
+ return data;
+ }
+ }
+}
+
+Data * Data::data()
+{
+ return dataWithCapacity(0);
+}
+
+Data * Data::dataWithCapacity(int capacity)
+{
+ Data * result = new Data(capacity);
+ return (Data *) result->autorelease();
+}
diff --git a/src/core/basetypes/MCData.h b/src/core/basetypes/MCData.h
new file mode 100644
index 00000000..52232383
--- /dev/null
+++ b/src/core/basetypes/MCData.h
@@ -0,0 +1,58 @@
+#ifndef __MAILCORE_MCDATA_H_
+
+#define __MAILCORE_MCDATA_H_
+
+#include <mailcore/MCObject.h>
+#include <mailcore/MCMessageConstants.h>
+
+namespace mailcore {
+
+ class String;
+
+ class Data : public Object {
+ private:
+ char * mBytes;
+ unsigned int mLength;
+ unsigned int mAllocated;
+ void allocate(unsigned int length);
+ void reset();
+ static String * normalizeCharset(String * charset);
+ String * charsetWithFilteredHTMLWithoutHint(bool filterHTML);
+
+ public:
+ Data();
+ Data(int capacity);
+ Data(Data * otherData);
+ Data(const char * bytes, unsigned int length);
+ virtual ~Data();
+
+ //virtual String * className();
+ virtual String * description();
+ virtual Object * copy();
+ virtual bool isEqual(Object * otherObject);
+ virtual unsigned int hash();
+
+ static Data * data();
+ static Data * dataWithCapacity(int capacity);
+ static Data * dataWithContentsOfFile(String * filename);
+ static Data * dataWithBytes(const char * bytes, unsigned int length);
+
+ virtual char * bytes();
+ virtual unsigned int length();
+
+ virtual void appendData(Data * otherData);
+ virtual void appendBytes(const char * bytes, unsigned int length);
+ virtual void setBytes(const char * bytes, unsigned int length);
+ virtual void setData(Data * otherData);
+
+ // Helpers
+ virtual String * stringWithDetectedCharset();
+ virtual String * emailStringWithCharset(String * charset);
+ virtual String * stringWithCharset(const char * charset);
+ virtual String * charsetWithFilteredHTML(bool filterHTML, String * hintCharset = NULL);
+ virtual Data * decodedDataUsingEncoding(Encoding encoding);
+ };
+
+}
+
+#endif
diff --git a/src/core/basetypes/MCHash.cc b/src/core/basetypes/MCHash.cc
new file mode 100644
index 00000000..116557e5
--- /dev/null
+++ b/src/core/basetypes/MCHash.cc
@@ -0,0 +1,12 @@
+#include "MCHash.h"
+
+unsigned int mailcore::hashCompute(const char * key, unsigned int len) {
+ register unsigned int c = 5381;
+ register const char * k = key;
+
+ while (len--) {
+ c = ((c << 5) + c) + *k++;
+ }
+
+ return c;
+}
diff --git a/src/core/basetypes/MCHash.h b/src/core/basetypes/MCHash.h
new file mode 100644
index 00000000..ecce9639
--- /dev/null
+++ b/src/core/basetypes/MCHash.h
@@ -0,0 +1,11 @@
+#ifndef __MAILCORE_MCHASH_H_
+
+#define __MAILCORE_MCHASH_H_
+
+namespace mailcore {
+
+ unsigned int hashCompute(const char * key, unsigned int len);
+
+}
+
+#endif
diff --git a/src/core/basetypes/MCHashMap.cc b/src/core/basetypes/MCHashMap.cc
new file mode 100644
index 00000000..8dcf0f30
--- /dev/null
+++ b/src/core/basetypes/MCHashMap.cc
@@ -0,0 +1,283 @@
+#include "MCHashMap.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MCArray.h"
+#include "MCString.h"
+#include "MCUtils.h"
+#include "MCLog.h"
+
+using namespace mailcore;
+
+namespace mailcore {
+ struct HashMapCell {
+ unsigned int func;
+ Object * key;
+ Object * value;
+ HashMapCell * next;
+ };
+}
+
+#define CHASH_DEFAULTSIZE 13
+#define CHASH_MAXDEPTH 3
+
+void HashMap::init()
+{
+ mCount = 0;
+ mCells = (void **) (HashMapCell **) calloc(CHASH_DEFAULTSIZE, sizeof(HashMapCell *));
+ mAllocated = CHASH_DEFAULTSIZE;
+}
+
+HashMap::HashMap()
+{
+ init();
+}
+
+HashMap::HashMap(HashMap * other)
+{
+ init();
+ Array * keys = other->allKeys();
+ for(unsigned int i = 0 ; i < keys->count() ; i ++) {
+ Object * key = keys->objectAtIndex(i);
+ Object * value = other->objectForKey(key);
+ setObjectForKey(key, value);
+ }
+}
+
+HashMap::~HashMap()
+{
+ for(unsigned int indx = 0; indx < mAllocated; indx++) {
+ HashMapIter * iter, * next;
+ iter = (HashMapIter *) mCells[indx];
+ while (iter) {
+ next = iter->next;
+ iter->key->release();
+ iter->value->release();
+ free(iter);
+ iter = next;
+ }
+ }
+ free(mCells);
+}
+
+void HashMap::allocate(unsigned int size)
+{
+ HashMapCell ** cells;
+ unsigned int indx, nindx;
+ HashMapIter * iter, * next;
+
+ if (mAllocated == size)
+ return;
+
+ cells = (HashMapCell **) calloc(size, sizeof(HashMapCell *));
+ /* iterate over initial hash and copy items in second hash */
+ for(indx = 0 ; indx < mAllocated ; indx ++) {
+ iter = (HashMapIter *) mCells[indx];
+ while (iter) {
+ next = iter->next;
+ nindx = iter->func % size;
+ iter->next = cells[nindx];
+ cells[nindx] = iter;
+ iter = next;
+ }
+ }
+ free(mCells);
+ mAllocated = size;
+ mCells = (void **) cells;
+}
+
+HashMap * HashMap::hashMap()
+{
+ HashMap * result = new HashMap();
+ return (HashMap *) result->autorelease();
+}
+
+#if 0
+String * HashMap::className()
+{
+ return MCSTR("HashMap");
+}
+#endif
+
+String * HashMap::description()
+{
+ String * result = String::string();
+ Array * keys = allKeys();
+ result->appendUTF8Characters("{");
+ for(unsigned int i = 0 ; i < keys->count() ; i ++) {
+ Object * key = keys->objectAtIndex(i);
+ if (i != 0) {
+ result->appendUTF8Characters(",");
+ }
+ result->appendString(key->description());
+ result->appendUTF8Characters(":");
+ Object * value = objectForKey(key);
+ result->appendString(value->description());
+ }
+ result->appendUTF8Characters("}");
+
+ return result;
+}
+
+Object * HashMap::copy()
+{
+ return new HashMap(this);
+}
+
+unsigned int HashMap::count()
+{
+ return mCount;
+}
+
+void HashMap::setObjectForKey(Object * key, Object * value)
+{
+ unsigned int func, indx;
+ HashMapIter * iter, * cell;
+
+ if (mCount > mAllocated * CHASH_MAXDEPTH) {
+ allocate((mCount / CHASH_MAXDEPTH) * 2 + 1);
+ }
+
+ func = key->hash();
+ indx = func % mAllocated;
+
+ /* look for the key in existing cells */
+ iter = (HashMapIter *) mCells[indx];
+ while (iter) {
+ if (iter->func == func && iter->key->isEqual(key)) {
+ /* found, replacing entry */
+ value->retain();
+ iter->value->release();
+ iter->value = value;
+ return;
+ }
+ iter = iter->next;
+ }
+
+ /* not found, adding entry */
+ cell = (HashMapCell *) malloc(sizeof(HashMapCell));
+ cell->key = key->copy();
+ cell->value = value->retain();
+ cell->func = func;
+ cell->next = (HashMapCell *) mCells[indx];
+ mCells[indx] = cell;
+ mCount ++;
+}
+
+void HashMap::removeObjectForKey(Object * key)
+{
+ unsigned int func, indx;
+ HashMapIter * iter, * old;
+
+ func = key->hash();;
+ indx = func % mAllocated;
+
+ /* look for the key in existing cells */
+ old = NULL;
+ iter = (HashMapIter *) mCells[indx];
+ while (iter) {
+ if (iter->func == func && iter->key->isEqual(key)) {
+ /* found, deleting */
+ if (old)
+ old->next = iter->next;
+ else
+ mCells[indx] = iter->next;
+ iter->key->release();
+ iter->value->release();
+ free(iter);
+ mCount --;
+ return;
+ }
+ old = iter;
+ iter = iter->next;
+ }
+ // Not found.
+}
+
+Object * HashMap::objectForKey(Object * key)
+{
+ unsigned int func;
+ HashMapIter * iter;
+
+ func = key->hash();
+
+ /* look for the key in existing cells */
+ iter = (HashMapIter *) mCells[func % mAllocated];
+ while (iter) {
+ if (iter->func == func && key->isEqual(iter->key)) {
+ return iter->value; /* found */
+ }
+ iter = iter->next;
+ }
+ return NULL;
+}
+
+HashMapIter * HashMap::iteratorBegin()
+{
+ HashMapIter * iter;
+ unsigned int indx = 0;
+
+ iter = (HashMapIter *) mCells[0];
+ while (!iter) {
+ indx ++;
+ if (indx >= mAllocated)
+ return NULL;
+ iter = (HashMapIter *) mCells[indx];
+ }
+ return iter;
+}
+
+HashMapIter * HashMap::iteratorNext(HashMapIter * iter)
+{
+ unsigned int indx;
+
+ if (!iter)
+ return NULL;
+
+ indx = iter->func % mAllocated;
+ iter = iter->next;
+
+ while(!iter) {
+ indx++;
+ if (indx >= mAllocated)
+ return NULL;
+ iter = (HashMapIter *) mCells[indx];
+ }
+ return iter;
+}
+
+Array * HashMap::allKeys()
+{
+ Array * keys = Array::array();
+ for(HashMapIter * iter = iteratorBegin() ; iter != NULL ; iter = iteratorNext(iter)) {
+ keys->addObject(iter->key);
+ }
+ return keys;
+}
+
+Array * HashMap::allValues()
+{
+ Array * values = Array::array();
+ for(HashMapIter * iter = iteratorBegin() ; iter != NULL ; iter = iteratorNext(iter)) {
+ values->addObject(iter->value);
+ }
+ return values;
+}
+
+void HashMap::removeAllObjects()
+{
+ for(unsigned int indx = 0 ; indx < mAllocated ; indx++) {
+ HashMapIter * iter, * next;
+ iter = (HashMapIter *) mCells[indx];
+ while (iter) {
+ next = iter->next;
+ iter->key->release();
+ iter->value->release();
+ free(iter);
+ iter = next;
+ }
+ }
+ memset(mCells, 0, mAllocated * sizeof(* mCells));
+ mCount = 0;
+}
diff --git a/src/core/basetypes/MCHashMap.h b/src/core/basetypes/MCHashMap.h
new file mode 100644
index 00000000..99e8db52
--- /dev/null
+++ b/src/core/basetypes/MCHashMap.h
@@ -0,0 +1,45 @@
+#ifndef __MAILCORE_MCHASHMAP_H_
+
+#define __MAILCORE_MCHASHMAP_H_
+
+#include <mailcore/MCObject.h>
+
+namespace mailcore {
+
+ class String;
+ class Array;
+ struct HashMapCell;
+ typedef HashMapCell HashMapIter;
+
+ class HashMap : public Object {
+ private:
+ unsigned int mAllocated;
+ unsigned int mCount;
+ void ** mCells;
+ HashMapIter * iteratorBegin();
+ HashMapIter * iteratorNext(HashMapIter * iter);
+ void allocate(unsigned int size);
+ void init();
+ public:
+ HashMap();
+ HashMap(HashMap * o);
+ virtual ~HashMap();
+
+ static HashMap * hashMap();
+
+ //virtual String * className();
+ virtual String * description();
+ virtual Object * copy();
+
+ virtual unsigned int count();
+ virtual void setObjectForKey(Object * key, Object * value);
+ virtual void removeObjectForKey(Object * key);
+ virtual Object * objectForKey(Object * key);
+ virtual Array * allKeys();
+ virtual Array * allValues();
+ virtual void removeAllObjects();
+ };
+
+}
+
+#endif
diff --git a/src/core/basetypes/MCLog.cc b/src/core/basetypes/MCLog.cc
new file mode 100644
index 00000000..2ceceecc
--- /dev/null
+++ b/src/core/basetypes/MCLog.cc
@@ -0,0 +1,30 @@
+#include "MCLog.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+static void logInternalv(FILE * file,
+ const char * user, const char * filename, unsigned int line,
+ int dumpStack, const char * format, va_list argp);
+
+void mailcore::logInternal(const char * user,
+ const char * filename,
+ unsigned int line,
+ int dumpStack,
+ const char * format, ...)
+{
+ va_list argp;
+
+ va_start(argp, format);
+ logInternalv(stderr, user, filename, line, dumpStack, format, argp);
+ va_end(argp);
+}
+
+static void logInternalv(FILE * file,
+ const char * user, const char * filename, unsigned int line,
+ int dumpStack, const char * format, va_list argp)
+{
+ fprintf(file, "%s:%i: ", filename, line);
+ vfprintf(file, format, argp);
+ fprintf(file, "\n");
+}
diff --git a/src/core/basetypes/MCLog.h b/src/core/basetypes/MCLog.h
new file mode 100644
index 00000000..42246e61
--- /dev/null
+++ b/src/core/basetypes/MCLog.h
@@ -0,0 +1,19 @@
+#ifndef __MAILCORE_MCLOG_H_
+
+#define __MAILCORE_MCLOG_H_
+
+#include <stdio.h>
+
+#define MCLog(...) mailcore::logInternal(NULL, __FILE__, __LINE__, 0, __VA_ARGS__)
+
+namespace mailcore {
+
+ void logInternal(const char * user,
+ const char * filename,
+ unsigned int line,
+ int dumpStack,
+ const char * format, ...) __printflike(5, 6);
+
+}
+
+#endif
diff --git a/src/core/basetypes/MCMainThread.h b/src/core/basetypes/MCMainThread.h
new file mode 100644
index 00000000..db8e1141
--- /dev/null
+++ b/src/core/basetypes/MCMainThread.h
@@ -0,0 +1,11 @@
+#ifndef __MAILCORE_MCMAINTHREAD_H
+
+#define __MAILCORE_MCMAINTHREAD_H
+
+namespace mailcore {
+ void callOnMainThread(void (*)(void *), void * context);
+ void callOnMainThreadAndWait(void (*)(void *), void * context);
+ void callAfterDelay(void (*)(void *), void * context, double time);
+}
+
+#endif
diff --git a/src/core/basetypes/MCMainThread.mm b/src/core/basetypes/MCMainThread.mm
new file mode 100644
index 00000000..31d83b5e
--- /dev/null
+++ b/src/core/basetypes/MCMainThread.mm
@@ -0,0 +1,60 @@
+#include "MCMainThread.h"
+
+#import <Foundation/Foundation.h>
+
+using namespace mailcore;
+
+@interface LEPPPMainThreadCaller : NSObject {
+ void (* _function)(void *);
+ void * _context;
+}
+
+@property (nonatomic, assign) void (* function)(void *);
+@property (nonatomic, assign) void * context;
+
+- (void) call;
+
+@end
+
+@implementation LEPPPMainThreadCaller
+
+@synthesize function = _function;
+@synthesize context = _context;
+
+- (void) call
+{
+ _function(_context);
+}
+
+@end
+
+void mailcore::callOnMainThread(void (* function)(void *), void * context)
+{
+ LEPPPMainThreadCaller * caller;
+ caller = [[LEPPPMainThreadCaller alloc] init];
+ [caller setFunction:function];
+ [caller setContext:context];
+ [caller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:NO];
+ [caller release];
+}
+
+void mailcore::callOnMainThreadAndWait(void (* function)(void *), void * context)
+{
+ LEPPPMainThreadCaller * caller;
+ caller = [[LEPPPMainThreadCaller alloc] init];
+ [caller setFunction:function];
+ [caller setContext:context];
+ [caller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:YES];
+ [caller release];
+}
+
+void mailcore::callAfterDelay(void (* function)(void *), void * context, double time)
+{
+ LEPPPMainThreadCaller * caller;
+ caller = [[LEPPPMainThreadCaller alloc] init];
+ [caller setFunction:function];
+ [caller setContext:context];
+ [caller performSelector:@selector(call) withObject:nil afterDelay:time];
+ [caller release];
+}
+
diff --git a/src/core/basetypes/MCObject.cc b/src/core/basetypes/MCObject.cc
new file mode 100644
index 00000000..220a5a16
--- /dev/null
+++ b/src/core/basetypes/MCObject.cc
@@ -0,0 +1,180 @@
+#include "MCObject.h"
+
+#include <stdlib.h>
+#include <typeinfo>
+#include <cxxabi.h>
+
+#include "MCAutoreleasePool.h"
+#include "MCString.h"
+#include "MCHash.h"
+#include "MCLog.h"
+#include "MCUtils.h"
+#include "MCAssert.h"
+#include "MCMainThread.h"
+
+using namespace mailcore;
+
+Object::Object()
+{
+ init();
+}
+
+Object::~Object()
+{
+}
+
+void Object::init()
+{
+ pthread_mutex_init(&mLock, NULL);
+ mCounter = 1;
+}
+
+int Object::retainCount()
+{
+ pthread_mutex_lock(&mLock);
+ int value = mCounter;
+ pthread_mutex_unlock(&mLock);
+
+ return value;
+}
+
+Object * Object::retain()
+{
+ pthread_mutex_lock(&mLock);
+ mCounter ++;
+ pthread_mutex_unlock(&mLock);
+ return this;
+}
+
+void Object::release()
+{
+ bool shouldRelease = false;
+
+ pthread_mutex_lock(&mLock);
+ mCounter --;
+ if (mCounter == 0) {
+ shouldRelease = true;
+ }
+ pthread_mutex_unlock(&mLock);
+
+ if (shouldRelease) {
+ //MCLog("dealloc %s", className()->description()->UTF8Characters());
+ delete this;
+ }
+}
+
+Object * Object::autorelease()
+{
+ AutoreleasePool::autorelease(this);
+ return this;
+}
+
+String * Object::className()
+{
+ int status;
+ char * unmangled = abi::__cxa_demangle(typeid(* this).name(), NULL, NULL, &status);
+ //return mailcore::String::uniquedStringWithUTF8Characters(typeid(* this).name());
+ return mailcore::String::uniquedStringWithUTF8Characters(unmangled);
+}
+
+/*
+String * Object::className()
+{
+ return MCSTR("Object");
+}
+*/
+
+String * Object::description()
+{
+ return String::stringWithUTF8Format("<%s:%p>", className()->UTF8Characters(), this);
+}
+
+bool Object::isEqual(Object * otherObject)
+{
+ return this == otherObject;
+}
+
+unsigned int Object::hash()
+{
+ return hashCompute((const char *) this, sizeof(this));
+}
+
+Object * Object::copy()
+{
+ MCAssert(0);
+ return NULL;
+}
+
+void Object::performMethod(Object::Method method, void * context)
+{
+ (this->*method)(context);
+}
+
+struct mainThreadCallData {
+ Object * obj;
+ void * context;
+ Object::Method method;
+};
+
+static void performOnMainThread(void * info)
+{
+ struct mainThreadCallData * data;
+ void * context;
+ Object * obj;
+ Object::Method method;
+
+ data = (struct mainThreadCallData *) info;
+ obj = data->obj;
+ context = data->context;
+ method = data->method;
+
+ (obj->*method)(context);
+
+ free(data);
+}
+
+static void callAfterDelay(void * info)
+{
+ struct mainThreadCallData * data;
+ void * context;
+ Object * obj;
+ Object::Method method;
+
+ data = (struct mainThreadCallData *) info;
+ obj = data->obj;
+ context = data->context;
+ method = data->method;
+
+ (obj->*method)(context);
+
+ free(data);
+}
+
+void Object::performMethodOnMainThread(Method method, void * context, bool waitUntilDone)
+{
+ struct mainThreadCallData * data;
+
+ data = (struct mainThreadCallData *) calloc(sizeof(* data), 1);
+ data->obj = this;
+ data->context = context;
+ data->method = method;
+
+ if (waitUntilDone) {
+ callOnMainThreadAndWait(performOnMainThread, data);
+ }
+ else {
+ callOnMainThread(performOnMainThread, data);
+ }
+}
+
+void Object::performMethodAfterDelay(Method method, void * context, double delay)
+{
+ struct mainThreadCallData * data;
+
+ data = (struct mainThreadCallData *) calloc(sizeof(* data), 1);
+ data->obj = this;
+ data->context = context;
+ data->method = method;
+
+ callAfterDelay(performOnMainThread, data, delay);
+}
diff --git a/src/core/basetypes/MCObject.h b/src/core/basetypes/MCObject.h
new file mode 100644
index 00000000..9e323ebf
--- /dev/null
+++ b/src/core/basetypes/MCObject.h
@@ -0,0 +1,41 @@
+#ifndef __MAILCORE_MCOBJECT_H_
+
+#define __MAILCORE_MCOBJECT_H_
+
+#include <pthread.h>
+
+namespace mailcore {
+
+ class String;
+
+ class Object {
+ private:
+ pthread_mutex_t mLock;
+ int mCounter;
+ void init();
+ public:
+ Object();
+ virtual ~Object();
+
+ virtual int retainCount();
+ virtual Object * retain();
+ virtual void release();
+ virtual Object * autorelease();
+ virtual String * description();
+ virtual String * className();
+
+ virtual bool isEqual(Object * otherObject);
+ virtual unsigned int hash();
+
+ // optional
+ virtual Object * copy();
+
+ typedef void (Object::*Method) (void *);
+ virtual void performMethod(Method method, void * context);
+ virtual void performMethodOnMainThread(Method method, void * context, bool waitUntilDone = false);
+ virtual void performMethodAfterDelay(Method method, void * context, double delay);
+ };
+
+}
+
+#endif
diff --git a/src/core/basetypes/MCOperation.cc b/src/core/basetypes/MCOperation.cc
new file mode 100644
index 00000000..61dd48e6
--- /dev/null
+++ b/src/core/basetypes/MCOperation.cc
@@ -0,0 +1,45 @@
+#include "MCOperation.h"
+
+using namespace mailcore;
+
+Operation::Operation()
+{
+ mCallback = NULL;
+ mCancelled = false;
+ pthread_mutex_init(&mLock, NULL);
+}
+
+Operation::~Operation()
+{
+ pthread_mutex_destroy(&mLock);
+}
+
+void Operation::setCallback(OperationCallback * callback)
+{
+ mCallback = callback;
+}
+
+OperationCallback * Operation::callback()
+{
+ return mCallback;
+}
+
+void Operation::cancel()
+{
+ pthread_mutex_lock(&mLock);
+ mCancelled = true;
+ pthread_mutex_unlock(&mLock);
+}
+
+bool Operation::isCancelled()
+{
+ pthread_mutex_lock(&mLock);
+ bool value = mCancelled;
+ pthread_mutex_unlock(&mLock);
+
+ return value;
+}
+
+void Operation::main()
+{
+}
diff --git a/src/core/basetypes/MCOperation.h b/src/core/basetypes/MCOperation.h
new file mode 100644
index 00000000..80bd8d30
--- /dev/null
+++ b/src/core/basetypes/MCOperation.h
@@ -0,0 +1,33 @@
+#ifndef __MAILCORE_MCOPERATION_H_
+
+#define __MAILCORE_MCOPERATION_H_
+
+#include <pthread.h>
+#include <mailcore/MCObject.h>
+
+namespace mailcore {
+
+ class OperationCallback;
+
+ class Operation : public Object {
+ private:
+ OperationCallback * mCallback;
+ bool mCancelled;
+ pthread_mutex_t mLock;
+
+ public:
+ Operation();
+ virtual ~Operation();
+
+ virtual void setCallback(OperationCallback * callback);
+ virtual OperationCallback * callback();
+
+ virtual void cancel();
+ virtual bool isCancelled();
+
+ virtual void main();
+ };
+
+}
+
+#endif
diff --git a/src/core/basetypes/MCOperationCallback.h b/src/core/basetypes/MCOperationCallback.h
new file mode 100644
index 00000000..e9623c76
--- /dev/null
+++ b/src/core/basetypes/MCOperationCallback.h
@@ -0,0 +1,16 @@
+#ifndef __MAILCORE_MCOPERATIONCALLBACK_H_
+
+#define __MAILCORE_MCOPERATIONCALLBACK_H_
+
+namespace mailcore {
+
+ class Operation;
+
+ class OperationCallback {
+ public:
+ virtual void operationFinished(Operation * op) {}
+ };
+
+}
+
+#endif
diff --git a/src/core/basetypes/MCOperationQueue.cc b/src/core/basetypes/MCOperationQueue.cc
new file mode 100644
index 00000000..3c22b89c
--- /dev/null
+++ b/src/core/basetypes/MCOperationQueue.cc
@@ -0,0 +1,179 @@
+#include "MCOperationQueue.h"
+
+#include "MCOperation.h"
+#include "MCOperationCallback.h"
+#include "MCMainThread.h"
+#include "MCUtils.h"
+#include "MCArray.h"
+#include "MCLog.h"
+#include <libetpan/libetpan.h>
+
+using namespace mailcore;
+
+OperationQueue::OperationQueue()
+{
+ mOperations = new Array();
+ mStarted = false;
+ //sem_init(&mOperationSem, 0, 0);
+ //sem_init(&mStartSem, 0, 0);
+ //sem_init(&mStopSem, 0, 0);
+ pthread_mutex_init(&mLock, NULL);
+ mWaiting = false;
+ //sem_init(&mWaitingFinishedSem, 0, 0);
+ mOperationSem = mailsem_new();
+ mStartSem = mailsem_new();
+ mStopSem = mailsem_new();
+ mWaitingFinishedSem = mailsem_new();
+}
+
+OperationQueue::~OperationQueue()
+{
+ MC_SAFE_RELEASE(mOperations);
+ //sem_destroy(&mOperationSem);
+ //sem_destroy(&mStartSem);
+ //sem_destroy(&mStopSem);
+ pthread_mutex_destroy(&mLock);
+ //sem_destroy(&mWaitingFinishedSem);
+ mailsem_free(mOperationSem);
+ mailsem_free(mStartSem);
+ mailsem_free(mStopSem);
+ mailsem_free(mWaitingFinishedSem);
+}
+
+void OperationQueue::addOperation(Operation * op)
+{
+ pthread_mutex_lock(&mLock);
+ mOperations->addObject(op);
+ pthread_mutex_unlock(&mLock);
+ //sem_post(&mOperationSem);
+ mailsem_up(mOperationSem);
+ startThread();
+}
+
+void OperationQueue::runOperationsOnThread(OperationQueue * queue)
+{
+ queue->runOperations();
+}
+
+void OperationQueue::runOperations()
+{
+ MCLog("start thread");
+ //sem_post(&mStartSem);
+ mailsem_up(mStartSem);
+
+ while (true) {
+ Operation * op = NULL;
+ bool needsCheckRunning = false;
+
+ //int value = 0;
+ //int r;
+
+ //r = sem_getvalue(&mOperationSem, &value);
+ //MCLog("x before sem %i %i", value, r);
+ //sem_wait(&mOperationSem);
+ mailsem_down(mOperationSem);
+ //sem_getvalue(&mOperationSem, &value);
+ //MCLog("x after sem %i", value);
+
+ pthread_mutex_lock(&mLock);
+ if (mOperations->count() > 0) {
+ op = (Operation *) mOperations->objectAtIndex(0);
+ }
+ pthread_mutex_unlock(&mLock);
+
+ if (op == NULL) {
+ //sem_post(&mStopSem);
+ mailsem_up(mStopSem);
+ break;
+ }
+
+ op->main();
+
+ if (op->callback() != NULL) {
+ performMethodOnMainThread((Object::Method) &OperationQueue::callbackOnMainThread, op, true);
+ }
+
+ pthread_mutex_lock(&mLock);
+ mOperations->removeObjectAtIndex(0);
+ if (mOperations->count() == 0) {
+ if (mWaiting) {
+ //sem_post(&mWaitingFinishedSem);
+ mailsem_up(mWaitingFinishedSem);
+ }
+ needsCheckRunning = true;
+ }
+ pthread_mutex_unlock(&mLock);
+
+ if (needsCheckRunning) {
+ retain(); // (1)
+ performMethodOnMainThread((Object::Method) &OperationQueue::checkRunningOnMainThread, this);
+ }
+ }
+ MCLog("cleanup thread");
+}
+
+void OperationQueue::callbackOnMainThread(Operation * op)
+{
+ if (op->callback() != NULL) {
+ op->callback()->operationFinished(op);
+ }
+}
+
+void OperationQueue::checkRunningOnMainThread(void * context)
+{
+ performMethodAfterDelay((Object::Method) &OperationQueue::checkRunningAfterDelay, NULL, 1);
+}
+
+void OperationQueue::checkRunningAfterDelay(void * context)
+{
+ bool quitting = false;
+
+ pthread_mutex_lock(&mLock);
+ if (mOperations->count() == 0) {
+ //sem_post(&mOperationSem);
+ mailsem_up(mOperationSem);
+ quitting = true;
+ }
+ pthread_mutex_unlock(&mLock);
+
+ // Number of operations can't be changed because it runs on main thread.
+ // And addOperation() should also be called from main thread.
+
+ if (quitting) {
+ //sem_wait(&mStopSem);
+ mailsem_down(mStopSem);
+ mStarted = false;
+ }
+
+ release(); // (1)
+}
+
+void OperationQueue::startThread()
+{
+ if (mStarted)
+ return;
+
+ mStarted = true;
+ pthread_create(&mThreadID, NULL, (void * (*)(void *)) OperationQueue::runOperationsOnThread, this);
+ //sem_wait(&mStartSem);
+ mailsem_down(mStartSem);
+}
+
+#if 0
+void OperationQueue::waitUntilAllOperationsAreFinished()
+{
+ bool waiting = false;
+
+ pthread_mutex_lock(&mLock);
+ if (mOperations->count() > 0) {
+ mWaiting = true;
+ waiting = true;
+ }
+ pthread_mutex_unlock(&mLock);
+
+ if (waiting) {
+ sem_wait(&mWaitingFinishedSem);
+ }
+ mWaiting = false;
+}
+#endif
diff --git a/src/core/basetypes/MCOperationQueue.h b/src/core/basetypes/MCOperationQueue.h
new file mode 100644
index 00000000..b858aebc
--- /dev/null
+++ b/src/core/basetypes/MCOperationQueue.h
@@ -0,0 +1,45 @@
+#ifndef __MAILCORE_MCOPERATIONQUEUE_H_
+
+#define __MAILCORE_MCOPERATIONQUEUE_H_
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <mailcore/MCObject.h>
+#include <libetpan/libetpan.h>
+
+namespace mailcore {
+
+ class Operation;
+ class Array;
+
+ class OperationQueue : public Object {
+ private:
+ Array * mOperations;
+ pthread_t mThreadID;
+ bool mStarted;
+ struct mailsem * mOperationSem;
+ struct mailsem * mStartSem;
+ struct mailsem * mStopSem;
+ pthread_mutex_t mLock;
+ bool mWaiting;
+ struct mailsem * mWaitingFinishedSem;
+
+ void startThread();
+ static void runOperationsOnThread(OperationQueue * queue);
+ void runOperations();
+ void callbackOnMainThread(Operation * op);
+ void checkRunningOnMainThread(void * context);
+ void checkRunningAfterDelay(void * context);
+
+ public:
+ OperationQueue();
+ virtual ~OperationQueue();
+
+ virtual void addOperation(Operation * op);
+
+ //virtual void waitUntilAllOperationsAreFinished();
+ };
+
+}
+
+#endif
diff --git a/src/core/basetypes/MCRange.cc b/src/core/basetypes/MCRange.cc
new file mode 100644
index 00000000..ead5c189
--- /dev/null
+++ b/src/core/basetypes/MCRange.cc
@@ -0,0 +1,12 @@
+#include "MCRange.h"
+
+using namespace mailcore;
+
+Range mailcore::RangeMake(unsigned int index, unsigned int length)
+{
+ Range range;
+ range.index = index;
+ range.length = length;
+ return range;
+}
+
diff --git a/src/core/basetypes/MCRange.h b/src/core/basetypes/MCRange.h
new file mode 100644
index 00000000..752c4bec
--- /dev/null
+++ b/src/core/basetypes/MCRange.h
@@ -0,0 +1,15 @@
+#ifndef __MAILCORE_MCRANGE_H_
+
+#define __MAILCORE_MCRANGE_H_
+
+namespace mailcore {
+
+ struct Range {
+ unsigned int index;
+ unsigned int length;
+ };
+
+ Range RangeMake(unsigned int index, unsigned int length);
+}
+
+#endif
diff --git a/src/core/basetypes/MCSet.cc b/src/core/basetypes/MCSet.cc
new file mode 100644
index 00000000..fcda7f62
--- /dev/null
+++ b/src/core/basetypes/MCSet.cc
@@ -0,0 +1,106 @@
+#include "MCSet.h"
+
+#include "MCHashMap.h"
+#include "MCString.h"
+#include "MCUtils.h"
+#include "MCArray.h"
+#include "MCLog.h"
+
+using namespace mailcore;
+
+void Set::init()
+{
+ mHash = new HashMap();
+}
+
+Set::Set()
+{
+ init();
+}
+
+Set::Set(Set * o)
+{
+ init();
+ MC_SAFE_REPLACE_COPY(HashMap, mHash, o->mHash);
+}
+
+Set::~Set()
+{
+ delete mHash;
+}
+
+Set * Set::set()
+{
+ Set * result = new Set();
+ return (Set *) result->autorelease();
+}
+
+Set * Set::setWithArray(Array * objects)
+{
+ Set * result = new Set();
+ result->addObjectsFromArray(objects);
+ return (Set *) result->autorelease();
+}
+
+#if 0
+String * Set::className()
+{
+ return MCSTR("Set");
+}
+#endif
+
+String * Set::description()
+{
+ String * result = String::string();
+ result->appendUTF8Format("<%s:%p ", className(), this);
+ result->appendString(mHash->allKeys()->description());
+ result->appendUTF8Characters(">");
+ return result;
+}
+
+Object * Set::copy()
+{
+ return new Set(this);
+}
+
+unsigned int Set::count()
+{
+ return mHash->count();
+}
+
+void Set::addObject(Object * obj)
+{
+ mHash->setObjectForKey(obj, obj);
+}
+
+void Set::removeObject(Object * obj)
+{
+ mHash->removeObjectForKey(obj);
+}
+
+Object * Set::member(Object * obj)
+{
+ return mHash->objectForKey(obj);
+}
+
+bool Set::containsObject(Object * obj)
+{
+ return (mHash->objectForKey(obj) != NULL);
+}
+
+Array * Set::allObjects()
+{
+ return mHash->allKeys();
+}
+
+void Set::removeAllObjects()
+{
+ mHash->removeAllObjects();
+}
+
+void Set::addObjectsFromArray(Array * objects)
+{
+ for(unsigned int i= 0 ; i < objects->count() ; i ++) {
+ addObject(objects->objectAtIndex(i));
+ }
+}
diff --git a/src/core/basetypes/MCSet.h b/src/core/basetypes/MCSet.h
new file mode 100644
index 00000000..0f1ab360
--- /dev/null
+++ b/src/core/basetypes/MCSet.h
@@ -0,0 +1,42 @@
+#ifndef __MAILCORE_CSET_H_
+
+#define __MAILCORE_CSET_H_
+
+#include <mailcore/MCObject.h>
+
+namespace mailcore {
+
+ class String;
+ class Array;
+ class HashMap;
+
+ class Set : public Object {
+ private:
+ HashMap * mHash;
+ void init();
+ public:
+ Set();
+ Set(Set * o);
+ virtual ~Set();
+
+ static Set * set();
+ static Set * setWithArray(Array * objects);
+
+ //virtual String * className();
+ virtual String * description();
+ virtual Object * copy();
+
+ virtual unsigned int count();
+ virtual void addObject(Object * obj);
+ virtual void removeObject(Object * obj);
+ virtual bool containsObject(Object * obj);
+ virtual Object * member(Object * obj);
+
+ virtual Array * allObjects();
+ virtual void removeAllObjects();
+ virtual void addObjectsFromArray(Array * objects);
+ };
+
+}
+
+#endif
diff --git a/src/core/basetypes/MCString.cc b/src/core/basetypes/MCString.cc
new file mode 100644
index 00000000..5f6948d6
--- /dev/null
+++ b/src/core/basetypes/MCString.cc
@@ -0,0 +1,1958 @@
+#include "MCString.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <unicode/ustring.h>
+#include <unicode/ucnv.h>
+#include <uuid/uuid.h>
+#include <pthread.h>
+#include <libetpan/libetpan.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/HTMLparser.h>
+
+#include "MCData.h"
+#include "MCHash.h"
+#include "MCLog.h"
+#include "MCUtils.h"
+#include "MCRange.h"
+#include "MCArray.h"
+#include "MCSet.h"
+#include "MCHashMap.h"
+#include "MCAutoreleasePool.h"
+#include "MCValue.h"
+
+using namespace mailcore;
+
+#pragma mark quote headers string
+
+static inline int to_be_quoted(const char * word, size_t size, int subject)
+{
+ int do_quote;
+ const char * cur;
+ size_t i;
+
+ do_quote = 0;
+ cur = word;
+ for(i = 0 ; i < size ; i ++) {
+ if (* cur == '=')
+ do_quote = 1;
+
+ if (!subject) {
+ switch (* cur) {
+ case ',':
+ case ':':
+ case '!':
+ case '"':
+ case '#':
+ case '$':
+ case '@':
+ case '[':
+ case '\\':
+ case ']':
+ case '^':
+ case '`':
+ case '{':
+ case '|':
+ case '}':
+ case '~':
+ case '=':
+ case '?':
+ case '_':
+ do_quote = 1;
+ break;
+ }
+ }
+ if (((unsigned char) * cur) >= 128)
+ do_quote = 1;
+
+ cur ++;
+ }
+
+ return do_quote;
+}
+
+#define MAX_IMF_LINE 72
+
+static inline void quote_word(const char * display_charset,
+ MMAPString * mmapstr, const char * word, size_t size)
+{
+ const char * cur;
+ size_t i;
+ char hex[4];
+ int col;
+
+ mmap_string_append(mmapstr, "=?");
+ mmap_string_append(mmapstr, display_charset);
+ mmap_string_append(mmapstr, "?Q?");
+
+ col = (int) mmapstr->len;
+
+ cur = word;
+ for(i = 0 ; i < size ; i ++) {
+ int do_quote_char;
+
+ do_quote_char = 0;
+ switch (* cur) {
+ case ',':
+ case ':':
+ case '!':
+ case '"':
+ case '#':
+ case '$':
+ case '@':
+ case '[':
+ case '\\':
+ case ']':
+ case '^':
+ case '`':
+ case '{':
+ case '|':
+ case '}':
+ case '~':
+ case '=':
+ case '?':
+ case '_':
+ do_quote_char = 1;
+ break;
+
+ default:
+ if (((unsigned char) * cur) >= 128)
+ do_quote_char = 1;
+ break;
+ }
+
+ if (do_quote_char) {
+ snprintf(hex, 4, "=%2.2X", (unsigned char) * cur);
+ mmap_string_append(mmapstr, hex);
+ col += 3;
+ }
+ else {
+ if (* cur == ' ') {
+ mmap_string_append_c(mmapstr, '_');
+ }
+ else {
+ mmap_string_append_c(mmapstr, * cur);
+ }
+ col += 3;
+ }
+ cur ++;
+ }
+
+ mmap_string_append(mmapstr, "?=");
+}
+
+static inline void get_word(const char * begin, const char ** pend, int subject, int * pto_be_quoted)
+{
+ const char * cur;
+
+ cur = begin;
+
+ while ((* cur != ' ') && (* cur != '\t') && (* cur != '\0')) {
+ cur ++;
+ }
+ while (((* cur == ' ') || (* cur == '\t')) && (* cur != '\0')) {
+ cur ++;
+ }
+
+ if (cur - begin +
+ 1 /* minimum column of string in a
+ folded header */ > MAX_IMF_LINE)
+ * pto_be_quoted = 1;
+ else
+ * pto_be_quoted = to_be_quoted(begin, cur - begin, subject);
+
+ * pend = cur;
+}
+
+static char * etpan_make_full_quoted_printable(const char * display_charset,
+ const char * phrase)
+{
+ int needs_quote;
+ char * str;
+
+ needs_quote = to_be_quoted(phrase, strlen(phrase), 0);
+ if (needs_quote) {
+ MMAPString * mmapstr;
+
+ mmapstr = mmap_string_new("");
+ quote_word(display_charset, mmapstr, phrase, strlen(phrase));
+ str = strdup(mmapstr->str);
+ mmap_string_free(mmapstr);
+ }
+ else {
+ str = strdup(phrase);
+ }
+
+ return str;
+}
+
+static char * etpan_make_quoted_printable(const char * display_charset,
+ const char * phrase, int subject)
+{
+ char * str;
+ const char * cur;
+ MMAPString * mmapstr;
+
+ mmapstr = mmap_string_new("");
+
+ cur = phrase;
+ while (* cur != '\0') {
+ const char * begin;
+ const char * end;
+ int do_quote;
+ int quote_words;
+
+ begin = cur;
+ end = begin;
+ quote_words = 0;
+ do_quote = 1;
+
+ while (* cur != '\0') {
+ get_word(cur, &cur, subject, &do_quote);
+ if (do_quote) {
+ quote_words = 1;
+ end = cur;
+ }
+ else
+ break;
+ if (* cur != '\0')
+ cur ++;
+ }
+
+ if (quote_words) {
+ quote_word(display_charset, mmapstr, begin, end - begin);
+
+ if ((* end == ' ') || (* end == '\t')) {
+ mmap_string_append_c(mmapstr, * end);
+ end ++;
+ }
+
+ if (* end != '\0') {
+ mmap_string_append_len(mmapstr, end, cur - end);
+ }
+ }
+ else {
+ mmap_string_append_len(mmapstr, begin, cur - begin);
+ }
+
+ if ((* cur == ' ') || (* cur == '\t')) {
+ mmap_string_append_c(mmapstr, * cur);
+ cur ++;
+ }
+ }
+
+ str = strdup(mmapstr->str);
+ mmap_string_free(mmapstr);
+
+ return str;
+}
+
+#pragma mark extract subject
+
+static inline int skip_subj_blob(char * subj, size_t * begin,
+ size_t length, int keep_bracket)
+{
+ if (keep_bracket)
+ return 0;
+
+ /* subj-blob = "[" *BLOBCHAR "]" *WSP */
+ size_t cur_token;
+
+ cur_token = * begin;
+
+ if (subj[cur_token] != '[')
+ return 0;
+
+ cur_token ++;
+
+ while (1) {
+ if (cur_token >= length)
+ return 0;
+
+ if (subj[cur_token] == '[')
+ return 0;
+
+ if (subj[cur_token] == ']')
+ break;
+
+ cur_token ++;
+ }
+
+ cur_token ++;
+
+ while (1) {
+ if (cur_token >= length)
+ break;
+
+ if (subj[cur_token] != ' ')
+ break;
+
+ cur_token ++;
+ }
+
+ * begin = cur_token;
+
+ return 1;
+}
+
+static inline int skip_subj_refwd(char * subj, size_t * begin,
+ size_t length, int keep_bracket)
+{
+ /* subj-refwd = ("re" / ("fw" ["d"])) *WSP [subj-blob] ":" */
+ size_t cur_token;
+ int prefix;
+ int has_suffix;
+
+ cur_token = * begin;
+ prefix = 0;
+ if (!prefix) {
+ if (length - cur_token >= 18) {
+ if (strncasecmp(subj + cur_token, "Переслать", 18) == 0) {
+ cur_token += 18;
+ prefix = 1;
+ }
+ }
+ }
+ if (!prefix) {
+ if (length - cur_token >= 10) {
+ if (strncasecmp(subj + cur_token, "Ответ", 10) == 0) {
+ cur_token += 10;
+ prefix = 1;
+ }
+ }
+ }
+ if (!prefix) {
+ if (length - cur_token >= 7) {
+ if (strncasecmp(subj + cur_token, "Antwort", 7) == 0) {
+ cur_token += 7;
+ prefix = 1;
+ }
+ }
+ }
+ if (!prefix) {
+ if (length - cur_token >= 6) {
+ if (strncasecmp(subj + cur_token, "回复", 6) == 0) {
+ cur_token += 6;
+ prefix = 1;
+ }
+ else if (strncasecmp(subj + cur_token, "转发", 6) == 0) {
+ cur_token += 6;
+ prefix = 1;
+ }
+ }
+ }
+ if (!prefix) {
+ if (length - cur_token >= 5) {
+ // é is 2 chars in utf-8
+ if (strncasecmp(subj + cur_token, "réf.", 5) == 0) {
+ cur_token += 5;
+ prefix = 1;
+ }
+ else if (strncasecmp(subj + cur_token, "rép.", 5) == 0) {
+ cur_token += 5;
+ prefix = 1;
+ }
+ else if (strncasecmp(subj + cur_token, "trans", 5) == 0) {
+ cur_token += 5;
+ prefix = 1;
+ }
+ }
+ }
+ if (!prefix) {
+ if (length - cur_token >= 4) {
+ if (strncasecmp(subj + cur_token, "antw", 4) == 0) {
+ cur_token += 4;
+ prefix = 1;
+ }
+ }
+ }
+ if (!prefix) {
+ if (length - cur_token >= 3) {
+ if (strncasecmp(subj + cur_token, "fwd", 3) == 0) {
+ cur_token += 3;
+ prefix = 1;
+ }
+ else if (strncasecmp(subj + cur_token, "ogg", 3) == 0) {
+ cur_token += 3;
+ prefix = 1;
+ }
+ else if (strncasecmp(subj + cur_token, "odp", 3) == 0) {
+ cur_token += 3;
+ prefix = 1;
+ }
+ else if (strncasecmp(subj + cur_token, "res", 3) == 0) {
+ cur_token += 3;
+ prefix = 1;
+ }
+ else if (strncasecmp(subj + cur_token, "end", 3) == 0) {
+ cur_token += 3;
+ prefix = 1;
+ }
+ }
+ }
+ if (!prefix) {
+ if (length - cur_token >= 2) {
+ if (strncasecmp(subj + cur_token, "fw", 2) == 0) {
+ cur_token += 2;
+ prefix = 1;
+ }
+ else if (strncasecmp(subj + cur_token, "re", 2) == 0) {
+ cur_token += 2;
+ prefix = 1;
+ }
+ else if (strncasecmp(subj + cur_token, "tr", 2) == 0) {
+ cur_token += 2;
+ prefix = 1;
+ }
+ else if (strncasecmp(subj + cur_token, "aw", 2) == 0) {
+ cur_token += 2;
+ prefix = 1;
+ }
+ else if (strncasecmp(subj + cur_token, "sv", 2) == 0) {
+ cur_token += 2;
+ prefix = 1;
+ }
+ else if (strncasecmp(subj + cur_token, "rv", 2) == 0) {
+ cur_token += 2;
+ prefix = 1;
+ }
+ }
+ }
+ if (!prefix) {
+ if (length - cur_token >= 1) {
+ if (strncasecmp(subj + cur_token, "r", 1) == 0) {
+ cur_token += 1;
+ prefix = 1;
+ }
+ }
+ }
+
+ if (!prefix)
+ return 0;
+
+ while (1) {
+ if (cur_token >= length)
+ break;
+
+ if (subj[cur_token] != ' ')
+ break;
+
+ cur_token ++;
+ }
+
+ skip_subj_blob(subj, &cur_token, length, keep_bracket);
+
+ has_suffix = 0;
+
+ if (!has_suffix) {
+ if (length - cur_token >= 3) {
+ if (strncasecmp(subj + cur_token, ":", 3) == 0) {
+ cur_token += 3;
+ has_suffix = 1;
+ }
+ }
+ }
+
+ if (!has_suffix) {
+ if (cur_token < length) {
+ if (subj[cur_token] == ':') {
+ cur_token ++;
+ has_suffix = 1;
+ }
+ }
+ }
+
+ if (!has_suffix) {
+ return 0;
+ }
+
+ * begin = cur_token;
+
+ return 1;
+}
+
+static inline int skip_subj_leader(char * subj, size_t * begin,
+ size_t length, int keep_bracket)
+{
+ size_t cur_token;
+
+ cur_token = * begin;
+
+ /* subj-leader = (*subj-blob subj-refwd) / WSP */
+
+ if (subj[cur_token] == ' ') {
+ cur_token ++;
+ }
+ else {
+ while (cur_token < length) {
+ if (!skip_subj_blob(subj, &cur_token, length, keep_bracket))
+ break;
+ }
+ if (!skip_subj_refwd(subj, &cur_token, length, keep_bracket))
+ return 0;
+ }
+
+ * begin = cur_token;
+
+ return 1;
+}
+
+static char * extract_subject(char * str, int keep_bracket)
+{
+ char * subj;
+ char * cur;
+ char * write_pos;
+ size_t len;
+ size_t begin;
+ int do_repeat_5;
+ int do_repeat_6;
+
+ /*
+ (1) Convert any RFC 2047 encoded-words in the subject to
+ UTF-8.
+ We work on UTF-8 string -- DVH
+ */
+
+ subj = strdup(str);
+ if (subj == NULL)
+ return NULL;
+
+ len = strlen(subj);
+
+ /*
+ Convert all tabs and continuations to space.
+ Convert all multiple spaces to a single space.
+ */
+
+ cur = subj;
+ write_pos = subj;
+ while (* cur != '\0') {
+ int cont;
+
+ switch (* cur) {
+ case '\t':
+ case '\r':
+ case '\n':
+ cont = 1;
+
+ cur ++;
+ while (* cur && cont) {
+ switch (* cur) {
+ case '\t':
+ case '\r':
+ case '\n':
+ cont = 1;
+ break;
+ default:
+ cont = 0;
+ break;
+ }
+ cur ++;
+ }
+
+ * write_pos = ' ';
+ write_pos ++;
+
+ break;
+
+ default:
+ * write_pos = * cur;
+ write_pos ++;
+
+ cur ++;
+
+ break;
+ }
+ }
+ * write_pos = '\0';
+
+ begin = 0;
+
+ do {
+ do_repeat_6 = 0;
+
+ /*
+ (2) Remove all trailing text of the subject that matches
+ the subj-trailer ABNF, repeat until no more matches are
+ possible.
+ */
+
+ while (len > 0) {
+ int chg;
+
+ chg = 0;
+
+ /* subj-trailer = "(fwd)" / WSP */
+ if (subj[len - 1] == ' ') {
+ subj[len - 1] = '\0';
+ len --;
+ }
+ else {
+ if (len < 5)
+ break;
+
+ if (strncasecmp(subj + len - 5, "(fwd)", 5) != 0)
+ break;
+
+ subj[len - 5] = '\0';
+ len -= 5;
+ }
+ }
+
+ do {
+ size_t saved_begin;
+
+ do_repeat_5 = 0;
+
+ /*
+ (3) Remove all prefix text of the subject that matches the
+ subj-leader ABNF.
+ */
+
+ if (skip_subj_leader(subj, &begin, len, keep_bracket))
+ do_repeat_5 = 1;
+
+ /*
+ (4) If there is prefix text of the subject that matches the
+ subj-blob ABNF, and removing that prefix leaves a non-empty
+ subj-base, then remove the prefix text.
+ */
+
+ saved_begin = begin;
+ if (skip_subj_blob(subj, &begin, len, keep_bracket)) {
+ if (begin == len) {
+ /* this will leave a empty subject base */
+ begin = saved_begin;
+ }
+ else
+ do_repeat_5 = 1;
+ }
+
+ /*
+ (5) Repeat (3) and (4) until no matches remain.
+ Note: it is possible to defer step (2) until step (6),
+ but this requires checking for subj-trailer in step (4).
+ */
+
+ }
+ while (do_repeat_5);
+
+ /*
+ (6) If the resulting text begins with the subj-fwd-hdr ABNF
+ and ends with the subj-fwd-trl ABNF, remove the
+ subj-fwd-hdr and subj-fwd-trl and repeat from step (2).
+ */
+
+ if (len >= 5) {
+ size_t saved_begin;
+
+ saved_begin = begin;
+ if (strncasecmp(subj + begin, "[fwd:", 5) == 0) {
+ begin += 5;
+
+ if (subj[len - 1] != ']')
+ saved_begin = begin;
+ else {
+ subj[len - 1] = '\0';
+ len --;
+ do_repeat_6 = 1;
+ }
+ }
+ }
+
+ }
+ while (do_repeat_6);
+
+ /*
+ (7) The resulting text is the "base subject" used in
+ threading.
+ */
+
+ /* convert to upper case */
+
+ cur = subj + begin;
+ write_pos = subj;
+
+ while (* cur != '\0') {
+ * write_pos = * cur;
+ cur ++;
+ write_pos ++;
+ }
+ * write_pos = '\0';
+
+ return subj;
+}
+
+String::String(const UChar * unicodeChars)
+{
+ mUnicodeChars = NULL;
+ reset();
+ appendCharacters(unicodeChars);
+}
+
+String::String(const UChar * unicodeChars, unsigned int length)
+{
+ mUnicodeChars = NULL;
+ reset();
+ appendCharactersLength(unicodeChars, length);
+}
+
+String::String(const char * UTF8Characters)
+{
+ mUnicodeChars = NULL;
+ reset();
+ appendUTF8Characters(UTF8Characters);
+}
+
+String::String(String * otherString)
+{
+ mUnicodeChars = NULL;
+ reset();
+ appendString(otherString);
+}
+
+String::String(Data * data, const char * charset)
+{
+ mUnicodeChars = NULL;
+ reset();
+ appendBytes(data->bytes(), data->length(), charset);
+}
+
+String::String(const char * bytes, unsigned int length, const char * charset)
+{
+ mUnicodeChars = NULL;
+ reset();
+ if (charset == NULL) {
+ appendUTF8CharactersLength(bytes, length);
+ }
+ else {
+ appendBytes(bytes, length, charset);
+ }
+}
+
+String::~String()
+{
+ reset();
+}
+
+void String::allocate(unsigned int length)
+{
+ length ++;
+ if (length < mAllocated)
+ return;
+
+ if (mAllocated == 0) {
+ mAllocated = 4;
+ }
+ while (length > mAllocated) {
+ mAllocated *= 2;
+ }
+
+ mUnicodeChars = (UChar *) realloc(mUnicodeChars, mAllocated * sizeof(* mUnicodeChars));
+}
+
+String * String::string()
+{
+ return stringWithCharacters(NULL);
+}
+
+String * String::stringWithUTF8Format(const char * format, ...)
+{
+ va_list argp;
+
+ va_start(argp, format);
+ String * result = stringWithVUTF8Format(format, argp);
+ va_end(argp);
+
+ return result;
+}
+
+String * String::stringWithVUTF8Format(const char * format, va_list ap)
+{
+ char * result;
+ vasprintf(&result, format, ap);
+ return stringWithUTF8Characters(result);
+}
+
+String * String::stringWithUTF8Characters(const char * UTF8Characters)
+{
+ String * result = new String(UTF8Characters);
+ return (String *) result->autorelease();
+}
+
+String * String::stringWithCharacters(const UChar * characters)
+{
+ String * result = new String(characters);
+ return (String *) result->autorelease();
+}
+
+String * String::stringWithCharacters(const UChar * characters, unsigned int length)
+{
+ String * result = new String(characters, length);
+ return (String *) result->autorelease();
+}
+
+void String::appendCharactersLength(const UChar * unicodeCharacters, unsigned int length)
+{
+ allocate(mLength + length);
+ u_strncpy(&mUnicodeChars[mLength], unicodeCharacters, length);
+ mLength += length;
+ mUnicodeChars[mLength] = 0;
+}
+
+void String::appendString(String * otherString)
+{
+ appendCharactersLength(otherString->unicodeCharacters(), otherString->length());
+}
+
+void String::appendUTF8Format(const char * format, ...)
+{
+ va_list argp;
+
+ va_start(argp, format);
+ String * otherString = stringWithVUTF8Format(format, argp);
+ va_end(argp);
+
+ this->appendString(otherString);
+}
+
+void String::appendUTF8CharactersLength(const char * UTF8Characters, unsigned int length)
+{
+ if (UTF8Characters == NULL)
+ return;
+
+ UChar * dest;
+ int32_t destLength;
+ int32_t destCapacity;
+ UErrorCode err;
+
+ err = U_ZERO_ERROR;
+ u_strFromUTF8WithSub(NULL, 0, &destLength, UTF8Characters, length, 0xFFFD, NULL, &err);
+ destCapacity = destLength + 1;
+ dest = (UChar *) malloc(destCapacity * sizeof(* dest));
+ err = U_ZERO_ERROR;
+ u_strFromUTF8WithSub(dest, destCapacity, &destLength, UTF8Characters, length, 0xFFFD, NULL, &err);
+ dest[destLength] = 0;
+ // Fix in case of bad conversion.
+ for(int32_t i = 0 ; i < destLength ; i ++) {
+ if (dest[i] == 0) {
+ dest[i] = ' ';
+ }
+ }
+
+ appendCharactersLength(dest, destLength);
+
+ free(dest);
+}
+
+void String::appendUTF8Characters(const char * UTF8Characters)
+{
+ appendUTF8CharactersLength(UTF8Characters, (unsigned int) strlen(UTF8Characters));
+}
+
+void String::appendCharacters(const UChar * unicodeCharacters)
+{
+ if (unicodeCharacters == NULL)
+ return;
+
+ appendCharactersLength(unicodeCharacters, u_strlen(unicodeCharacters));
+}
+
+const UChar * String::unicodeCharacters()
+{
+ return mUnicodeChars;
+}
+
+const char * String::UTF8Characters()
+{
+ char * dest;
+ int32_t destLength;
+ int32_t destCapacity;
+ UErrorCode err;
+
+ err = U_ZERO_ERROR;
+ u_strToUTF8(NULL, 0, &destLength, mUnicodeChars, mLength, &err);
+ destCapacity = destLength + 1;
+ dest = (char *) malloc(destCapacity * sizeof(* dest));
+ err = U_ZERO_ERROR;
+ u_strToUTF8(dest, destCapacity, &destLength, mUnicodeChars, mLength, &err);
+ dest[destLength] = 0;
+
+ Data * data = Data::dataWithBytes(dest, destLength + 1);
+ free(dest);
+
+ return data->bytes();
+}
+
+unsigned int String::length()
+{
+ return mLength;
+}
+
+String * String::stringByAppendingString(String * otherString)
+{
+ String * result = new String(this);
+ result->appendString(otherString);
+ return (String *) result->autorelease();
+}
+
+String * String::stringByAppendingUTF8Format(const char * format, ...)
+{
+ va_list argp;
+
+ va_start(argp, format);
+ String * otherString = stringWithVUTF8Format(format, argp);
+ va_end(argp);
+
+ return this->stringByAppendingString(otherString);
+}
+
+String * String::stringByAppendingUTF8Characters(const char * UTF8Characters)
+{
+ String * otherString = stringWithUTF8Characters(UTF8Characters);
+ return this->stringByAppendingString(otherString);
+}
+
+String * String::stringByAppendingCharacters(const UChar * unicodeCharacters)
+{
+ String * otherString = stringWithCharacters(unicodeCharacters);
+ return this->stringByAppendingString(otherString);
+}
+
+void String::reset()
+{
+ free(mUnicodeChars);
+ mUnicodeChars = NULL;
+ mLength = 0;
+ mAllocated = 0;
+}
+
+void String::setString(String * otherString)
+{
+ reset();
+ appendString(otherString);
+}
+
+void String::setUTF8Characters(const char * UTF8Characters)
+{
+ reset();
+ appendUTF8Characters(UTF8Characters);
+}
+
+void String::setCharacters(const UChar * unicodeCharacters)
+{
+ reset();
+ appendCharacters(unicodeCharacters);
+}
+
+#if 0
+String * String::className()
+{
+ return MCSTR("String");
+}
+#endif
+
+String * String::description()
+{
+ return this;
+}
+
+Object * String::copy()
+{
+ return new String(this);
+}
+
+bool String::isEqual(Object * otherObject)
+{
+ String * otherString = (String *) otherObject;
+ if (length() != otherString->length())
+ return false;
+ return compare(otherString) == 0;
+}
+
+unsigned int String::hash()
+{
+ return hashCompute((const char *) mUnicodeChars, mLength * sizeof(* mUnicodeChars));
+}
+
+#define DEFAULT_INCOMING_CHARSET "iso-8859-1"
+#define DEFAULT_DISPLAY_CHARSET "utf-8"
+
+String * String::stringByDecodingMIMEHeaderValue(const char * phrase)
+{
+ size_t cur_token;
+ char * decoded;
+ String * result;
+ bool hasEncoding;
+
+ if (phrase == NULL)
+ return string();
+
+ if (* phrase == '\0') {
+ return string();
+ }
+
+ hasEncoding = false;
+ if (strstr(phrase, "=?") != NULL) {
+ if ((strcasestr(phrase, "?Q?") != NULL) || (strcasestr(phrase, "?B?") != NULL)) {
+ hasEncoding = true;
+ }
+ }
+
+ if (!hasEncoding) {
+ return Data::dataWithBytes(phrase, (unsigned int) strlen(phrase))->stringWithDetectedCharset();
+ }
+
+ cur_token = 0;
+ decoded = NULL;
+ mailmime_encoded_phrase_parse(DEFAULT_INCOMING_CHARSET,
+ phrase, strlen(phrase),
+ &cur_token, DEFAULT_DISPLAY_CHARSET,
+ &decoded);
+
+ result = NULL;
+ if (decoded != NULL) {
+ result = stringWithUTF8Characters(decoded);
+ }
+ else {
+ MCLog("could not decode: %s\n", phrase);
+ }
+
+ free(decoded);
+
+ return result;
+}
+
+Data * String::encodedAddressDisplayNameValue()
+{
+ char * str;
+ Data * result;
+
+ str = etpan_make_full_quoted_printable(DEFAULT_DISPLAY_CHARSET, UTF8Characters());
+ result = Data::dataWithBytes(str, (unsigned int) strlen(str) + 1);
+ free(str);
+
+ return result;
+}
+
+Data * String::encodedMIMEHeaderValue()
+{
+ char * str;
+ Data * result;
+
+ str = etpan_make_quoted_printable(DEFAULT_DISPLAY_CHARSET, UTF8Characters(), 0);
+ result = Data::dataWithBytes(str, (unsigned int) strlen(str) + 1);
+ free(str);
+
+ return result;
+}
+
+Data * String::encodedMIMEHeaderValueForSubject()
+{
+ char * str;
+ Data * result;
+
+ str = etpan_make_quoted_printable(DEFAULT_DISPLAY_CHARSET, UTF8Characters(), 1);
+ result = Data::dataWithBytes(str, (unsigned int) strlen(str) + 1);
+ free(str);
+
+ return result;
+}
+
+int String::compareWithCaseSensitive(String * otherString, bool caseSensitive)
+{
+ if ((unicodeCharacters() == NULL) && (otherString->unicodeCharacters() != NULL)) {
+ return 0;
+ }
+
+ if (unicodeCharacters() == NULL) {
+ return -1;
+ }
+
+ if (otherString->unicodeCharacters() == NULL) {
+ return -1;
+ }
+
+ if (caseSensitive) {
+ return u_strcmp(unicodeCharacters(), otherString->unicodeCharacters());
+ }
+ else {
+ return u_strcasecmp(unicodeCharacters(), otherString->unicodeCharacters(), 0);
+ }
+}
+
+int String::compare(String * otherString)
+{
+ return compareWithCaseSensitive(otherString, true);
+}
+
+int String::caseInsensitiveCompare(String * otherString)
+{
+ return compareWithCaseSensitive(otherString, false);
+}
+
+String * String::lowercaseString()
+{
+ UErrorCode err;
+ String * result = (String *) copy()->autorelease();
+ err = U_ZERO_ERROR;
+ u_strToLower(result->mUnicodeChars, result->mLength,
+ result->mUnicodeChars, result->mLength,
+ NULL, &err);
+ return result;
+}
+
+String * String::uppercaseString()
+{
+ UErrorCode err;
+ String * result = (String *) copy()->autorelease();
+ err = U_ZERO_ERROR;
+ u_strToUpper(result->mUnicodeChars, result->mLength,
+ result->mUnicodeChars, result->mLength,
+ NULL, &err);
+ return result;
+}
+
+void String::appendBytes(const char * bytes, unsigned int length, const char * charset)
+{
+ UErrorCode err;
+
+ err = U_ZERO_ERROR;
+ UConverter * converter = ucnv_open(charset, &err);
+ if (converter == NULL) {
+ MCLog("invalid charset %s %i", charset, err);
+ return;
+ }
+
+ err = U_ZERO_ERROR;
+ int32_t destLength = ucnv_toUChars(converter, NULL, 0,
+ bytes, length, &err);
+ int32_t destCapacity = destLength + 1;
+ UChar * dest = (UChar *) malloc(destCapacity * sizeof(* dest));
+ err = U_ZERO_ERROR;
+ destLength = ucnv_toUChars(converter, dest, destCapacity, bytes, length, &err);
+ dest[destLength] = 0;
+
+ // Fix in case of bad conversion.
+ for(int32_t i = 0 ; i < destLength ; i ++) {
+ if (dest[i] == 0) {
+ dest[i] = ' ';
+ }
+ }
+
+ appendCharactersLength(dest, destLength);
+ free(dest);
+
+ ucnv_close(converter);
+}
+
+String * String::extractedSubject()
+{
+ return extractedSubjectAndKeepBracket(false);
+}
+
+String * String::extractedSubjectAndKeepBracket(bool keepBracket)
+{
+ char * result;
+ String * str;
+
+ result = extract_subject((char *) UTF8Characters(), keepBracket);
+ str = String::stringWithUTF8Characters(result);
+ free(result);
+
+ return str;
+}
+
+String * String::uuidString()
+{
+ uuid_t uuid;
+ uuid_string_t uuidString;
+
+ uuid_generate(uuid);
+ uuid_unparse_lower(uuid, uuidString);
+ return String::stringWithUTF8Characters(uuidString);
+}
+
+unsigned int String::replaceOccurrencesOfString(String * occurrence, String * replacement)
+{
+ unsigned int count;
+
+ if (occurrence->length() == 0)
+ return 0;
+
+ count = 0;
+ UChar * p = mUnicodeChars;
+ while (1) {
+ UChar * location;
+ location = u_strstr(p, occurrence->unicodeCharacters());
+ if (location == NULL)
+ break;
+ p = location + 1;
+ count ++;
+ }
+
+ UChar * unicodeChars;
+ int delta = replacement->length() - occurrence->length();
+ int modifiedLength = mLength + delta * count + 1;
+ unicodeChars = (UChar *) malloc(modifiedLength * sizeof(* unicodeChars));
+ UChar * dest_p = unicodeChars;
+ p = mUnicodeChars;
+ while (1) {
+ UChar * location;
+ unsigned int count;
+
+ location = u_strstr(p, occurrence->unicodeCharacters());
+ if (location == NULL)
+ break;
+ count = (unsigned int) (location - p);
+ u_memcpy(dest_p, p, count);
+ dest_p += count;
+ p += count;
+ u_memcpy(dest_p, p, replacement->length());
+ p += occurrence->length();
+ dest_p += replacement->length();
+ }
+ // copy remaining
+ u_strcpy(dest_p, p);
+
+ return count;
+}
+
+UChar String::characterAtIndex(unsigned int index)
+{
+ return mUnicodeChars[index];
+}
+
+void String::deleteCharactersInRange(Range range)
+{
+ if (range.index > mLength)
+ return;
+
+ if (range.index + range.length > mLength) {
+ range.length = mLength - range.index;
+ }
+
+ int32_t count = mLength - (range.index + range.length);
+ u_memmove(&mUnicodeChars[range.index], &mUnicodeChars[range.index + range.length], count);
+}
+
+int String::locationOfString(String * occurrence)
+{
+ UChar * location;
+ location = u_strstr(mUnicodeChars, occurrence->unicodeCharacters());
+ if (location == NULL) {
+ return -1;
+ }
+
+ return (int) (location - mUnicodeChars);
+}
+
+#pragma mark strip HTML
+
+struct parserState {
+ int level;
+ int enabled;
+ int disabledLevel;
+ String * result;
+ int logEnabled;
+ int hasQuote;
+ int quoteLevel;
+ bool hasText;
+ bool lastCharIsWhitespace;
+ bool showBlockQuote;
+ bool showLink;
+ bool hasReturnToLine;
+ Array * linkStack;
+ Array * paragraphSpacingStack;
+};
+
+static void appendQuote(struct parserState * state);
+
+static void charactersParsed(void * context,
+ const xmlChar * ch, int len)
+/*" Callback function for stringByStrippingHTML. "*/
+{
+ struct parserState * state;
+
+ state = (struct parserState *) context;
+ String * result = state->result;
+
+ if (!state->enabled) {
+ return;
+ }
+
+ if (state->logEnabled) {
+ MCLog("text %s", ch);
+ }
+ String * modifiedString;
+ modifiedString = new String((const char *) ch, len);
+ //modifiedString->replaceOccurrencesOfString(MCSTR("\r\n"), MCSTR(" "));
+ modifiedString->replaceOccurrencesOfString(MCSTR("\n"), MCSTR(" "));
+ modifiedString->replaceOccurrencesOfString(MCSTR("\r"), MCSTR(" "));
+ modifiedString->replaceOccurrencesOfString(MCSTR("\t"), MCSTR(" "));
+
+ UChar specialCh[2];
+ specialCh[0] = 133;
+ specialCh[1] = 0;
+ modifiedString->replaceOccurrencesOfString(String::stringWithCharacters(specialCh), MCSTR(" "));
+
+ while (modifiedString->replaceOccurrencesOfString(MCSTR(" "), MCSTR(" ")) > 0) {
+ }
+
+ if (modifiedString->length() > 0) {
+ if (state->lastCharIsWhitespace) {
+ if (modifiedString->characterAtIndex(0) == ' ') {
+ modifiedString->deleteCharactersInRange(RangeMake(0, 1));
+ }
+ }
+ }
+
+ if (modifiedString->length() > 0) {
+ bool lastIsWhiteSpace;
+ bool isWhiteSpace;
+
+ isWhiteSpace = false;
+ lastIsWhiteSpace = false;
+ if (modifiedString->length() > 0) {
+ if (modifiedString->characterAtIndex(modifiedString->length() - 1) == ' ') {
+ lastIsWhiteSpace = true;
+ }
+ }
+ if (lastIsWhiteSpace && (modifiedString->length() == 1)) {
+ isWhiteSpace = true;
+ }
+
+ if (isWhiteSpace) {
+ if (state->lastCharIsWhitespace) {
+ // do nothing
+ }
+ else if (!state->hasText) {
+ // do nothing
+ }
+ else {
+ result->appendString(MCSTR(" "));
+ state->lastCharIsWhitespace = true;
+ state->hasText = true;
+ }
+ }
+ else {
+ if (!state->hasQuote) {
+ appendQuote(state);
+ state->hasQuote = true;
+ }
+ result->appendString(modifiedString);
+ state->lastCharIsWhitespace = lastIsWhiteSpace;
+ state->hasText = true;
+ }
+ }
+ modifiedString->release();
+}
+
+/* GCS: custom error function to ignore errors */
+static void structuredError(void * userData,
+ xmlErrorPtr error)
+{
+ /* ignore all errors */
+ (void)userData;
+ (void)error;
+}
+
+static void appendQuote(struct parserState * state)
+{
+ if (state->quoteLevel < 0) {
+ MCLog("error consistency in quote level");
+ state->lastCharIsWhitespace = true;
+ return;
+ }
+ for(int i = 0 ; i < state->quoteLevel ; i ++) {
+ state->result->appendString(MCSTR("> "));
+ }
+ state->lastCharIsWhitespace = true;
+}
+
+static void returnToLine(struct parserState * state)
+{
+ if (!state->hasQuote) {
+ appendQuote(state);
+ state->hasQuote = true;
+ }
+ state->result->appendString(MCSTR("\n"));
+ state->hasText = false;
+ state->lastCharIsWhitespace = true;
+ state->hasQuote = false;
+ state->hasReturnToLine = false;
+}
+
+static void returnToLineAtBeginningOfBlock(struct parserState * state)
+{
+ if (state->hasText) {
+ returnToLine(state);
+ }
+ state->hasQuote = false;
+}
+
+static Set * blockElements(void)
+{
+ static Set * elements = NULL;
+ pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+ pthread_mutex_lock(&lock);
+ if (elements == NULL) {
+ elements = new Set();
+ elements->addObject(MCSTR("address"));
+ elements->addObject(MCSTR("div"));
+ elements->addObject(MCSTR("p"));
+ elements->addObject(MCSTR("h1"));
+ elements->addObject(MCSTR("h2"));
+ elements->addObject(MCSTR("h3"));
+ elements->addObject(MCSTR("h4"));
+ elements->addObject(MCSTR("h5"));
+ elements->addObject(MCSTR("h6"));
+ elements->addObject(MCSTR("pre"));
+ elements->addObject(MCSTR("ul"));
+ elements->addObject(MCSTR("ol"));
+ elements->addObject(MCSTR("li"));
+ elements->addObject(MCSTR("dl"));
+ elements->addObject(MCSTR("dt"));
+ elements->addObject(MCSTR("dd"));
+ elements->addObject(MCSTR("form"));
+ // tables
+ elements->addObject(MCSTR("col"));
+ elements->addObject(MCSTR("colgroup"));
+ elements->addObject(MCSTR("th"));
+ elements->addObject(MCSTR("tbody"));
+ elements->addObject(MCSTR("thead"));
+ elements->addObject(MCSTR("tfoot"));
+ elements->addObject(MCSTR("table"));
+ elements->addObject(MCSTR("tr"));
+ elements->addObject(MCSTR("td"));
+ }
+ pthread_mutex_unlock(&lock);
+
+ return elements;
+}
+
+static HashMap * dictionaryFromAttributes(const xmlChar ** atts)
+{
+ HashMap * result;
+
+ if (atts == NULL)
+ return NULL;
+
+ result = HashMap::hashMap();
+ for(const xmlChar ** curAtt = atts ; * curAtt != NULL ; curAtt += 2) {
+ const xmlChar * attrName;
+ const xmlChar * attrValue;
+ String * name;
+
+ attrName = * curAtt;
+ attrValue = * (curAtt + 1);
+ if ((attrName == NULL) || (attrValue == NULL))
+ continue;
+
+ name = String::stringWithUTF8Characters((const char *) attrName);
+ name = name->lowercaseString();
+ result->setObjectForKey(name, String::stringWithUTF8Characters((const char *) attrValue));
+ }
+
+ return result;
+}
+
+static void elementStarted(void * ctx, const xmlChar * name, const xmlChar ** atts)
+{
+ struct parserState * state;
+
+ state = (struct parserState *) ctx;
+
+ if (state->logEnabled) {
+ MCLog("parsed element %s", name);
+ }
+
+ if (strcasecmp((const char *) name, "blockquote") == 0) {
+ state->quoteLevel ++;
+ }
+ else if (strcasecmp((const char *) name, "a") == 0) {
+ AutoreleasePool * pool;
+ String * link;
+ HashMap * attributes;
+
+ pool = new AutoreleasePool();
+ attributes = dictionaryFromAttributes(atts);
+ link = (String *) attributes->objectForKey(MCSTR("href"));
+ if (link == NULL)
+ link = MCSTR("");
+
+ Array * item;
+ item = new Array();
+ item->addObject(link);
+ item->addObject(Value::valueWithUnsignedIntValue(state->result->length()));
+ state->linkStack->addObject(item);
+ item->release();
+ pool->release();
+ }
+ else if (strcasecmp((const char *) name, "p") == 0) {
+ bool hasSpacing;
+ String * style;
+ AutoreleasePool * pool;
+ HashMap * attributes;
+
+ hasSpacing = true;
+
+ pool = new AutoreleasePool();
+ attributes = dictionaryFromAttributes(atts);
+ style = (String *) attributes->objectForKey(MCSTR("style"));
+ if (style->locationOfString(MCSTR("margin: 0.0px 0.0px 0.0px 0.0px;")) != -1) {
+ hasSpacing = false;
+ }
+ else if (style->locationOfString(MCSTR("margin: 0px 0px 0px 0px;")) != -1) {
+ hasSpacing = false;
+ }
+ else if (style->locationOfString(MCSTR("margin: 0.0px;")) != -1) {
+ hasSpacing = false;
+ }
+ else if (style->locationOfString(MCSTR("margin: 0px;")) != -1) {
+ hasSpacing = false;
+ }
+ pool->release();
+
+ state->paragraphSpacingStack->addObject(Value::valueWithBoolValue(hasSpacing));
+ }
+
+ if (state->enabled) {
+ if (state->level == 1) {
+ if (strcasecmp((const char *) name, "head") == 0) {
+ state->enabled = 0;
+ state->disabledLevel = state->level;
+ }
+ }
+ if (strcasecmp((const char *) name, "style") == 0) {
+ state->enabled = 0;
+ state->disabledLevel = state->level;
+ }
+ else if (strcasecmp((const char *) name, "script") == 0) {
+ state->enabled = 0;
+ state->disabledLevel = state->level;
+ }
+ else if (strcasecmp((const char *) name, "p") == 0) {
+ returnToLineAtBeginningOfBlock(state);
+ if (((Value *) state->paragraphSpacingStack->lastObject())->boolValue()) {
+ returnToLine(state);
+ }
+ }
+ else if (blockElements()->containsObject(String::stringWithUTF8Characters((const char *) name)->lowercaseString())) {
+ returnToLineAtBeginningOfBlock(state);
+ }
+ else if (strcasecmp((const char *) name, "blockquote") == 0) {
+ if (!state->showBlockQuote) {
+ AutoreleasePool * pool;
+ String * type;
+ bool cite;
+ HashMap * attributes;
+
+ cite = false;
+ pool = new AutoreleasePool();
+ attributes = dictionaryFromAttributes(atts);
+ type = (String *) attributes->objectForKey(MCSTR("type"));
+ if (type->caseInsensitiveCompare(MCSTR("cite")) == 0) {
+ cite = true;
+ }
+ pool->release();
+
+ if (cite) {
+ state->enabled = 0;
+ state->disabledLevel = state->level;
+ }
+ else {
+ returnToLineAtBeginningOfBlock(state);
+ }
+ }
+ else {
+ returnToLineAtBeginningOfBlock(state);
+ }
+ }
+ else if (strcasecmp((const char *) name, "br") == 0) {
+ returnToLine(state);
+ state->hasReturnToLine = true;
+ }
+ }
+
+ state->level ++;
+}
+
+static void elementEnded(void * ctx, const xmlChar * name)
+{
+ struct parserState * state;
+
+ state = (struct parserState *) ctx;
+
+ if (state->logEnabled) {
+ MCLog("ended element %s", name);
+ }
+
+ if (strcasecmp((const char *) name, "blockquote") == 0) {
+ state->quoteLevel --;
+ }
+
+ state->level --;
+ if (!state->enabled) {
+ if (state->level == state->disabledLevel) {
+ state->enabled = 1;
+ }
+ }
+
+ bool hasReturnToLine;
+
+ hasReturnToLine = false;
+ if (strcasecmp((const char *) name, "a") == 0) {
+ if (state->enabled) {
+ Array * item;
+ String * link;
+ unsigned int offset;
+
+ item = (Array *) state->linkStack->lastObject();
+ link = (String *) item->objectAtIndex(0);
+ offset = ((Value *) item->objectAtIndex(1))->unsignedIntValue();
+ if (state->showLink) {
+ if (offset != state->result->length()) {
+ if (link->length() > 0) {
+ if (!state->result->hasSuffix(link)) {
+ state->result->appendUTF8Characters("(");
+ state->result->appendString(link);
+ state->result->appendUTF8Characters(")");
+ state->hasText = true;
+ state->lastCharIsWhitespace = false;
+ }
+ }
+ }
+ }
+ }
+
+ state->linkStack->removeObjectAtIndex(state->linkStack->count() - 1);
+ }
+ else if (strcasecmp((const char *) name, "p") == 0) {
+ if (state->enabled) {
+ if (((Value *) state->paragraphSpacingStack->lastObject())->boolValue()) {
+ returnToLine(state);
+ }
+ }
+ state->paragraphSpacingStack->removeObjectAtIndex(state->paragraphSpacingStack->count() - 1);
+ hasReturnToLine = true;
+ }
+ else if (blockElements()->containsObject(String::stringWithUTF8Characters((const char *) name)->lowercaseString())) {
+ hasReturnToLine = true;
+ }
+ else if (strcasecmp((const char *) name, "blockquote") == 0) {
+ hasReturnToLine = true;
+ }
+
+ if (hasReturnToLine) {
+ if (state->enabled) {
+ if (!state->hasReturnToLine) {
+ returnToLine(state);
+ }
+ }
+ }
+}
+
+static void commentParsed(void * ctx, const xmlChar * value)
+{
+ struct parserState * state;
+
+ state = (struct parserState *) ctx;
+
+ if (state->logEnabled) {
+ MCLog("comments %s", value);
+ }
+}
+
+void initializeLibXML()
+{
+ static bool initDone = false;
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+ pthread_mutex_lock(&lock);
+ if (!initDone) {
+ initDone = true;
+ xmlInitParser();
+
+ /* GCS: override structuredErrorFunc to mine so
+ I can ignore errors */
+ xmlSetStructuredErrorFunc(xmlGenericErrorContext,
+ &structuredError);
+ }
+ pthread_mutex_unlock(&lock);
+}
+
+String * String::flattenHTMLAndShowBlockquoteAndLink(bool showBlockquote, bool showLink)
+/*" Interpretes the receiver als HTML, removes all tags
+ and returns the plain text. "*/
+{
+ initializeLibXML();
+
+ int mem_base = xmlMemBlocks();
+ String * result = String::string();
+ xmlSAXHandler handler;
+ bzero(&handler, sizeof(xmlSAXHandler));
+ handler.characters = &charactersParsed;
+ handler.startElement = elementStarted;
+ handler.endElement = elementEnded;
+ handler.comment = commentParsed;
+ struct parserState state;
+ state.result = result;
+ state.level = 0;
+ state.enabled = 1;
+ state.logEnabled = 0;
+ state.disabledLevel = 0;
+ state.quoteLevel = 0;
+ state.hasText = false;
+ state.hasQuote = false;
+ state.hasReturnToLine = false;
+ state.showBlockQuote = showBlockquote;
+ state.showLink = showLink;
+ state.lastCharIsWhitespace = true;
+ state.linkStack = new Array();
+ state.paragraphSpacingStack = new Array();
+
+ htmlSAXParseDoc((xmlChar*) UTF8Characters(), "utf-8", &handler, &state);
+
+ if (mem_base != xmlMemBlocks()) {
+ MCLog("Leak of %d blocks found in htmlSAXParseDoc",
+ xmlMemBlocks() - mem_base);
+ }
+
+ state.paragraphSpacingStack->release();
+ state.linkStack->release();
+
+ UChar ch[2];
+ ch[0] = 160;
+ ch[1] = 0;
+ result->replaceOccurrencesOfString(String::stringWithCharacters(ch), MCSTR(" "));
+
+ return result;
+}
+
+String * String::flattenHTMLAndShowBlockquote(bool showBlockquote)
+{
+ return flattenHTMLAndShowBlockquoteAndLink(showBlockquote, true);
+}
+
+String * String::flattenHTML()
+{
+ return flattenHTMLAndShowBlockquote(true);
+}
+
+bool String::hasSuffix(String * suffix)
+{
+ if (mLength > suffix->mLength) {
+ if (u_memcmp(suffix->mUnicodeChars + (mLength - suffix->mLength),
+ mUnicodeChars, suffix->mLength) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool String::hasPrefix(String * prefix)
+{
+ if (mLength > prefix->mLength) {
+ if (u_memcmp(prefix->mUnicodeChars, mUnicodeChars, prefix->mLength) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+String * String::lastPathComponent()
+{
+ UChar * component = u_strrchr(mUnicodeChars, '/');
+ if (component == NULL)
+ return (String *) this->copy()->autorelease();
+ return String::stringWithCharacters(component + 1);
+}
+
+String * String::pathExtension()
+{
+ UChar * component = u_strrchr(mUnicodeChars, '.');
+ if (component == NULL)
+ return MCSTR("");
+ return String::stringWithCharacters(component + 1);
+}
+
+Data * String::dataUsingEncoding(const char * charset)
+{
+ UErrorCode err;
+ Data * data;
+
+ if (charset == NULL) {
+ charset = "utf-8";
+ }
+
+ err = U_ZERO_ERROR;
+ UConverter * converter = ucnv_open(charset, &err);
+ if (converter == NULL) {
+ MCLog("invalid charset %s %i", charset, err);
+ return NULL;
+ }
+
+ err = U_ZERO_ERROR;
+ int32_t destLength = ucnv_fromUChars(converter, NULL, 0, mUnicodeChars, mLength, &err);
+ int32_t destCapacity = destLength + 1;
+ char * dest = (char *) malloc(destCapacity * sizeof(* dest));
+ err = U_ZERO_ERROR;
+ destLength = ucnv_fromUChars(converter, dest, destCapacity, mUnicodeChars, mLength, &err);
+ dest[destLength] = 0;
+
+ // Fix in case of bad conversion.
+ for(int32_t i = 0 ; i < destLength ; i ++) {
+ if (dest[i] == 0) {
+ dest[i] = ' ';
+ }
+ }
+
+ data = Data::dataWithBytes(dest, destLength);
+
+ free(dest);
+
+ ucnv_close(converter);
+
+ return data;
+}
+
+const char * String::fileSystemRepresentation()
+{
+ return UTF8Characters();
+}
+
+String * String::stringWithFileSystemRepresentation(const char * filename)
+{
+ return stringWithUTF8Characters(filename);
+}
+
+Array * String::componentsSeparatedByString(String * separator)
+{
+ UChar * p;
+ Array * result;
+
+ result = Array::array();
+ p = mUnicodeChars;
+ while (1) {
+ UChar * location;
+ location = u_strstr(p, separator->unicodeCharacters());
+ if (location == NULL) {
+ break;
+ }
+
+ unsigned int length = (unsigned int) (p - location);
+ String * value = new String(p, length);
+ result->addObject(value);
+ value->release();
+
+ p = location + separator->length();
+ }
+
+ return result;
+}
+
+int String::intValue()
+{
+ return (int) strtol(UTF8Characters(), NULL, 10);
+}
+
+unsigned int String::unsignedIntValue()
+{
+ return (unsigned int) strtoul(UTF8Characters(), NULL, 10);
+}
+
+long String::longValue()
+{
+ return strtol(UTF8Characters(), NULL, 10);
+}
+
+unsigned long String::unsignedLongValue()
+{
+ return strtoul(UTF8Characters(), NULL, 10);
+}
+
+long long String::longLongValue()
+{
+ return strtoll(UTF8Characters(), NULL, 10);
+}
+
+unsigned long long String::unsignedLongLongValue()
+{
+ return strtoull(UTF8Characters(), NULL, 10);
+}
+
+Data * String::mUTF7EncodedData()
+{
+ return dataUsingEncoding("mutf-7");
+}
+
+String * String::stringWithMUTF7Data(Data * data)
+{
+ return data->stringWithCharset("mutf-7");
+}
+
+String * String::mUTF7EncodedString()
+{
+ Data * data = mUTF7EncodedData();
+ return data->stringWithCharset("ascii");
+}
+
+String * String::mUTF7DecodedString()
+{
+ Data * data = dataUsingEncoding("utf-8");
+ return stringWithMUTF7Data(data);
+}
+
+String * String::substringFromIndex(unsigned int idx)
+{
+ return substringWithRange(RangeMake(idx, length() - idx));
+}
+
+String * String::substringToIndex(unsigned int idx)
+{
+ return substringWithRange(RangeMake(0, idx));
+}
+
+String * String::substringWithRange(Range range)
+{
+ if (range.index > length()) {
+ return MCSTR("");
+ }
+
+ if (range.index + range.length > length()) {
+ range.length = length() - range.index;
+ }
+
+ return stringWithCharacters(unicodeCharacters() + range.index, range.length);
+}
+
+static chash * uniquedStringHash = NULL;
+
+static void initUniquedStringHash()
+{
+ uniquedStringHash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
+}
+
+String * String::uniquedStringWithUTF8Characters(const char * UTF8Characters)
+{
+ chashdatum key;
+ chashdatum value;
+ static pthread_once_t once = PTHREAD_ONCE_INIT;
+ int r;
+
+ pthread_once(&once, initUniquedStringHash);
+ key.data = (void *) UTF8Characters;
+ key.len = (unsigned int) strlen(UTF8Characters);
+ r = chash_get(uniquedStringHash, &key, &value);
+ if (r == 0) {
+ return (String *) value.data;
+ }
+ else {
+ value.data = new String(UTF8Characters);
+ value.len = 0;
+ chash_set(uniquedStringHash, &key, &value, NULL);
+ return (String *) value.data;
+ }
+}
diff --git a/src/core/basetypes/MCString.h b/src/core/basetypes/MCString.h
new file mode 100644
index 00000000..9ff04390
--- /dev/null
+++ b/src/core/basetypes/MCString.h
@@ -0,0 +1,123 @@
+#ifndef __MAILCORE_MCSTR_H_
+
+#define __MAILCORE_MCSTR_H_
+
+#include <mailcore/MCObject.h>
+#include <mailcore/MCRange.h>
+
+#include <stdarg.h>
+#include <unicode/utypes.h>
+
+namespace mailcore {
+
+ class Data;
+ class Array;
+
+ class String : public Object {
+ private:
+ UChar * mUnicodeChars;
+ unsigned int mLength;
+ unsigned int mAllocated;
+ void allocate(unsigned int length);
+ void appendCharactersLength(const UChar * unicodeCharacters, unsigned int length);
+ void reset();
+ int compareWithCaseSensitive(String * otherString, bool caseSensitive);
+ void appendBytes(const char * bytes, unsigned int length, const char * charset);
+ void appendUTF8CharactersLength(const char * UTF8Characters, unsigned int length);
+
+ public:
+ String(const UChar * unicodeChars = NULL);
+ String(const UChar * unicodeChars, unsigned int length);
+ String(const char * UTF8Characters);
+ String(String * otherString);
+ String(Data * data, const char * charset);
+ String(const char * bytes, unsigned int length, const char * charset = NULL);
+ virtual ~String();
+
+ //virtual String * className();
+ virtual String * description();
+ virtual Object * copy();
+ virtual bool isEqual(Object * otherObject);
+ virtual unsigned int hash();
+
+ static String * string();
+ static String * stringWithUTF8Format(const char * format, ...);
+ static String * stringWithVUTF8Format(const char * format, va_list ap);
+ static String * stringWithUTF8Characters(const char * UTF8Characters);
+ static String * stringWithCharacters(const UChar * characters);
+ static String * stringWithCharacters(const UChar * characters, unsigned int length);
+
+ virtual const UChar * unicodeCharacters();
+ virtual const char * UTF8Characters();
+ virtual unsigned int length();
+
+ virtual void appendString(String * otherString);
+ virtual void appendUTF8Format(const char * format, ...);
+ virtual void appendCharacters(const UChar * unicodeCharacters);
+ virtual void appendUTF8Characters(const char * UTF8Characters);
+ virtual void setString(String * otherString);
+ virtual void setUTF8Characters(const char * UTF8Characters);
+ virtual void setCharacters(const UChar * unicodeCharacters);
+
+ virtual String * stringByAppendingString(String * otherString);
+ virtual String * stringByAppendingUTF8Format(const char * format, ...);
+ virtual String * stringByAppendingUTF8Characters(const char * UTF8Characters);
+ virtual String * stringByAppendingCharacters(const UChar * unicodeCharacters);
+
+ virtual int compare(String * otherString);
+ virtual int caseInsensitiveCompare(String * otherString);
+ virtual String * lowercaseString();
+ virtual String * uppercaseString();
+
+ virtual UChar characterAtIndex(unsigned int idx);
+ virtual void deleteCharactersInRange(Range range);
+ virtual unsigned int replaceOccurrencesOfString(String * occurrence, String * replacement);
+ virtual int locationOfString(String * occurrence);
+
+ virtual Array * componentsSeparatedByString(String * separator);
+
+ // Additions
+ static String * stringByDecodingMIMEHeaderValue(const char * phrase);
+ virtual Data * encodedAddressDisplayNameValue();
+ virtual Data * encodedMIMEHeaderValue();
+ virtual Data * encodedMIMEHeaderValueForSubject();
+ virtual String * extractedSubject();
+ virtual String * extractedSubjectAndKeepBracket(bool keepBracket);
+ static String * uuidString();
+
+ virtual bool hasSuffix(String * suffix);
+ virtual bool hasPrefix(String * prefix);
+
+ virtual String * substringFromIndex(unsigned int idx);
+ virtual String * substringToIndex(unsigned int idx);
+ virtual String * substringWithRange(Range range);
+
+ virtual String * flattenHTML();
+ virtual String * flattenHTMLAndShowBlockquote(bool showBlockquote);
+ virtual String * flattenHTMLAndShowBlockquoteAndLink(bool showBlockquote, bool showLink);
+
+ virtual String * lastPathComponent();
+ virtual String * pathExtension();
+ virtual Data * dataUsingEncoding(const char * charset = NULL);
+
+ virtual const char * fileSystemRepresentation();
+ static String * stringWithFileSystemRepresentation(const char * filename);
+
+ int intValue();
+ unsigned int unsignedIntValue();
+ long longValue();
+ unsigned long unsignedLongValue();
+ long long longLongValue();
+ unsigned long long unsignedLongLongValue();
+
+ virtual Data * mUTF7EncodedData();
+ static String * stringWithMUTF7Data(Data * data);
+ virtual String * mUTF7EncodedString();
+ virtual String * mUTF7DecodedString();
+
+ static String * uniquedStringWithUTF8Characters(const char * UTF8Characters);
+ };
+
+}
+
+#endif
diff --git a/src/core/basetypes/MCUtils.h b/src/core/basetypes/MCUtils.h
new file mode 100644
index 00000000..8dbbf5f4
--- /dev/null
+++ b/src/core/basetypes/MCUtils.h
@@ -0,0 +1,34 @@
+#ifndef __MAILCORE_MCUTILS_H
+
+#define __MAILCORE_MCUTILS_H
+
+#define MC_SAFE_RETAIN(o) ((o) != NULL ? (o)->retain() : NULL)
+#define MC_SAFE_COPY(o) ((o) != NULL ? (o)->copy() : NULL)
+
+#define MC_SAFE_RELEASE(o) \
+ do { \
+ if ((o) != NULL) { \
+ (o)->release(); \
+ (o) = NULL; \
+ } \
+ } while (0)
+
+#define MC_SAFE_REPLACE_RETAIN(type, mField, value) \
+ do { \
+ MC_SAFE_RELEASE(mField); \
+ mField = (type *) MC_SAFE_RETAIN(value); \
+ } while (0)
+
+#define MC_SAFE_REPLACE_COPY(type, mField, value) \
+ do { \
+ MC_SAFE_RELEASE(mField); \
+ mField = (type *) MC_SAFE_COPY(value); \
+ } while (0)
+
+#define MCSTR(str) mailcore::String::uniquedStringWithUTF8Characters("" str "")
+
+#define MCUTF8(str) ((str) != NULL ? (str)->UTF8Characters() : NULL )
+#define MMCUTF8(str) MCUTF8(str)
+#define MCUTF8DESC(obj) ((obj) != NULL ? (obj)->description()->UTF8Characters() : NULL )
+
+#endif
diff --git a/src/core/basetypes/MCValue.cc b/src/core/basetypes/MCValue.cc
new file mode 100644
index 00000000..d275d3df
--- /dev/null
+++ b/src/core/basetypes/MCValue.cc
@@ -0,0 +1,314 @@
+#include "MCValue.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "MCString.h"
+#include "MCHash.h"
+#include "MCUtils.h"
+
+using namespace mailcore;
+
+enum {
+ VALUE_TYPE_NONE,
+ VALUE_TYPE_BOOL_VALUE,
+ VALUE_TYPE_CHAR_VALUE,
+ VALUE_TYPE_UNSIGNED_CHAR_VALUE,
+ VALUE_TYPE_SHORT_VALUE,
+ VALUE_TYPE_UNSIGNED_SHORT_VALUE,
+ VALUE_TYPE_INT_VALUE,
+ VALUE_TYPE_UNSIGNED_INT_VALUE,
+ VALUE_TYPE_LONG_VALUE,
+ VALUE_TYPE_UNSIGNED_LONG_VALUE,
+ VALUE_TYPE_LONG_LONG_VALUE,
+ VALUE_TYPE_UNSIGNED_LONG_LONG_VALUE,
+ VALUE_TYPE_FLOAT_VALUE,
+ VALUE_TYPE_DOUBLE_VALUE,
+ VALUE_TYPE_POINTER_VALUE,
+ VALUE_TYPE_DATA_VALUE,
+};
+
+Value::Value()
+{
+ mType = VALUE_TYPE_NONE;
+ memset(&mValue, 0, sizeof(mValue));
+}
+
+Value::Value(Value * other)
+{
+ memcpy(&mValue, &other->mValue, sizeof(mValue));
+ mType = other->mType;
+ if (mType == VALUE_TYPE_DATA_VALUE) {
+ mValue.dataValue.data = (char *) malloc(mValue.dataValue.length);
+ memcpy(mValue.dataValue.data, other->mValue.dataValue.data, mValue.dataValue.length);
+ }
+}
+
+Value::~Value()
+{
+ if (mType == VALUE_TYPE_DATA_VALUE) {
+ free(mValue.dataValue.data);
+ }
+}
+
+String * Value::description()
+{
+ switch (mType) {
+ case VALUE_TYPE_BOOL_VALUE:
+ if (mValue.boolValue) {
+ return MCSTR("true");
+ }
+ else {
+ return MCSTR("false");
+ }
+ case VALUE_TYPE_CHAR_VALUE:
+ return String::stringWithUTF8Format("%i", (int) mValue.charValue);
+ case VALUE_TYPE_UNSIGNED_CHAR_VALUE:
+ return String::stringWithUTF8Format("%u", (unsigned int) mValue.unsignedCharValue);
+ case VALUE_TYPE_SHORT_VALUE:
+ return String::stringWithUTF8Format("%i", (int) mValue.shortValue);
+ case VALUE_TYPE_UNSIGNED_SHORT_VALUE:
+ return String::stringWithUTF8Format("%u", (unsigned int) mValue.unsignedShortValue);
+ case VALUE_TYPE_INT_VALUE:
+ return String::stringWithUTF8Format("%i", mValue.intValue);
+ case VALUE_TYPE_UNSIGNED_INT_VALUE:
+ return String::stringWithUTF8Format("%u", mValue.unsignedIntValue);
+ case VALUE_TYPE_LONG_VALUE:
+ return String::stringWithUTF8Format("%li", mValue.longValue);
+ case VALUE_TYPE_UNSIGNED_LONG_VALUE:
+ return String::stringWithUTF8Format("%lu", mValue.unsignedLongValue);
+ case VALUE_TYPE_LONG_LONG_VALUE:
+ return String::stringWithUTF8Format("%lli", mValue.longLongValue);
+ case VALUE_TYPE_UNSIGNED_LONG_LONG_VALUE:
+ return String::stringWithUTF8Format("%llu", mValue.unsignedLongLongValue);
+ case VALUE_TYPE_FLOAT_VALUE:
+ return String::stringWithUTF8Format("%f", (double) mValue.floatValue);
+ case VALUE_TYPE_DOUBLE_VALUE:
+ return String::stringWithUTF8Format("%f", mValue.doubleValue);
+ case VALUE_TYPE_POINTER_VALUE:
+ return String::stringWithUTF8Format("%p", mValue.pointerValue);
+ case VALUE_TYPE_DATA_VALUE:
+ return String::stringWithUTF8Format("<Value:%p:data>", this);
+ default:
+ return String::stringWithUTF8Format("<Value:%p:unknown>", this);
+ }
+}
+
+#if 0
+String * Value::className()
+{
+ return MCSTR("Value");
+}
+#endif
+
+bool Value::isEqual(Object * otherObject)
+{
+ Value * otherValue = (Value *) otherObject;
+ if (otherValue->mType != mType)
+ return false;
+ if (mType == VALUE_TYPE_DATA_VALUE) {
+ if (mValue.dataValue.length != otherValue->mValue.dataValue.length)
+ return false;
+ if (memcmp(&otherValue->mValue.dataValue.data, &mValue.dataValue.data, mValue.dataValue.length) != 0)
+ return false;
+ }
+ else {
+ if (memcmp(&otherValue->mValue, &mValue, sizeof(mValue)) != 0)
+ return false;
+ }
+ return true;
+}
+
+unsigned int Value::hash()
+{
+ return hashCompute((const char *) &mValue, sizeof(mValue));
+}
+
+Object * Value::copy()
+{
+ return new Value(this);
+}
+
+Value * Value::valueWithBoolValue(bool value)
+{
+ Value * result = new Value();
+ result->mType = VALUE_TYPE_BOOL_VALUE;
+ result->mValue.boolValue = value;
+ return (Value *) result->autorelease();
+}
+
+Value * Value::valueWithCharValue(char value)
+{
+ Value * result = new Value();
+ result->mType = VALUE_TYPE_CHAR_VALUE;
+ result->mValue.charValue = value;
+ return (Value *) result->autorelease();
+}
+
+Value * Value::valueWithUnsignedCharValue(unsigned char value)
+{
+ Value * result = new Value();
+ result->mType = VALUE_TYPE_UNSIGNED_CHAR_VALUE;
+ result->mValue.unsignedCharValue = value;
+ return (Value *) result->autorelease();
+}
+
+///////////////////////
+
+Value * Value::valueWithIntValue(int value)
+{
+ Value * result = new Value();
+ result->mType = VALUE_TYPE_INT_VALUE;
+ result->mValue.intValue = value;
+ return (Value *) result->autorelease();
+}
+
+Value * Value::valueWithUnsignedIntValue(unsigned int value)
+{
+ Value * result = new Value();
+ result->mType = VALUE_TYPE_UNSIGNED_INT_VALUE;
+ result->mValue.unsignedIntValue = value;
+ return (Value *) result->autorelease();
+}
+
+Value * Value::valueWithLongValue(long value)
+{
+ Value * result = new Value();
+ result->mType = VALUE_TYPE_LONG_VALUE;
+ result->mValue.longValue = value;
+ return (Value *) result->autorelease();
+}
+
+Value * Value::valueWithUnsignedLongValue(unsigned long value)
+{
+ Value * result = new Value();
+ result->mType = VALUE_TYPE_UNSIGNED_LONG_VALUE;
+ result->mValue.unsignedLongValue = value;
+ return (Value *) result->autorelease();
+}
+
+Value * Value::valueWithLongLongValue(long long value)
+{
+ Value * result = new Value();
+ result->mType = VALUE_TYPE_LONG_LONG_VALUE;
+ result->mValue.longLongValue = value;
+ return (Value *) result->autorelease();
+}
+
+Value * Value::valueWithUnsignedLongLongValue(unsigned long long value)
+{
+ Value * result = new Value();
+ result->mType = VALUE_TYPE_UNSIGNED_LONG_LONG_VALUE;
+ result->mValue.unsignedLongLongValue = value;
+ return (Value *) result->autorelease();
+}
+
+Value * Value::valueWithFloatValue(float value)
+{
+ Value * result = new Value();
+ result->mType = VALUE_TYPE_FLOAT_VALUE;
+ result->mValue.floatValue = value;
+ return (Value *) result->autorelease();
+}
+
+Value * Value::valueWithDoubleValue(double value)
+{
+ Value * result = new Value();
+ result->mType = VALUE_TYPE_DOUBLE_VALUE;
+ result->mValue.doubleValue = value;
+ return (Value *) result->autorelease();
+}
+
+Value * Value::valueWithPointerValue(void * value)
+{
+ Value * result = new Value();
+ result->mType = VALUE_TYPE_POINTER_VALUE;
+ result->mValue.pointerValue = value;
+ return (Value *) result->autorelease();
+}
+
+Value * Value::valueWithData(const char * value, int length)
+{
+ Value * result = new Value();
+ result->mType = VALUE_TYPE_DATA_VALUE;
+ result->mValue.dataValue.data = (char *) malloc(length);
+ memcpy(result->mValue.dataValue.data, value, length);
+ result->mValue.dataValue.length = length;
+ return (Value *) result->autorelease();
+}
+
+bool Value::boolValue()
+{
+ return mValue.boolValue;
+}
+
+char Value::charValue()
+{
+ return mValue.charValue;
+}
+
+unsigned char Value::unsignedCharValue()
+{
+ return mValue.unsignedCharValue;
+}
+
+short Value::shortValue()
+{
+ return mValue.shortValue;
+}
+
+unsigned short Value::unsignedShortValue()
+{
+ return mValue.unsignedShortValue;
+}
+
+int Value::intValue()
+{
+ return mValue.intValue;
+}
+
+unsigned int Value::unsignedIntValue()
+{
+ return mValue.unsignedIntValue;
+}
+
+long Value::longValue()
+{
+ return mValue.longValue;
+}
+
+unsigned long Value::unsignedLongValue()
+{
+ return mValue.unsignedLongValue;
+}
+
+long long Value::longLongValue()
+{
+ return mValue.longLongValue;
+}
+
+unsigned long long Value::unsignedLongLongValue()
+{
+ return mValue.unsignedLongLongValue;
+}
+
+float Value::floatValue()
+{
+ return mValue.floatValue;
+}
+
+double Value::doubleValue()
+{
+ return mValue.doubleValue;
+}
+
+void * Value::pointerValue()
+{
+ return mValue.pointerValue;
+}
+
+void Value::dataValue(const char ** p_value, int * p_length)
+{
+ * p_value = mValue.dataValue.data;
+ * p_length = mValue.dataValue.length;
+}
diff --git a/src/core/basetypes/MCValue.h b/src/core/basetypes/MCValue.h
new file mode 100644
index 00000000..cc776b24
--- /dev/null
+++ b/src/core/basetypes/MCValue.h
@@ -0,0 +1,81 @@
+#ifndef __MAILCORE_MCVALUE_H_
+
+#define __MAILCORE_MCVALUE_H_
+
+#include <mailcore/MCObject.h>
+
+namespace mailcore {
+
+ class String;
+
+ class Value : public Object {
+ private:
+ int mType;
+ union {
+ bool boolValue;
+ char charValue;
+ unsigned char unsignedCharValue;
+ short shortValue;
+ unsigned short unsignedShortValue;
+ int intValue;
+ unsigned int unsignedIntValue;
+ long longValue;
+ unsigned long unsignedLongValue;
+ long long longLongValue;
+ unsigned long long unsignedLongLongValue;
+ float floatValue;
+ double doubleValue;
+ void * pointerValue;
+ struct {
+ char * data;
+ int length;
+ } dataValue;
+ } mValue;
+ Value();
+
+ public:
+ Value(Value * other);
+ virtual ~Value();
+
+ virtual String * description();
+ //virtual String * className();
+
+ virtual bool isEqual(Object * otherObject);
+ virtual unsigned int hash();
+
+ Object * copy();
+
+ static Value * valueWithBoolValue(bool value);
+ static Value * valueWithCharValue(char value);
+ static Value * valueWithUnsignedCharValue(unsigned char value);
+ static Value * valueWithIntValue(int value);
+ static Value * valueWithUnsignedIntValue(unsigned int value);
+ static Value * valueWithLongValue(long value);
+ static Value * valueWithUnsignedLongValue(unsigned long value);
+ static Value * valueWithLongLongValue(long long value);
+ static Value * valueWithUnsignedLongLongValue(unsigned long long value);
+ static Value * valueWithFloatValue(float value);
+ static Value * valueWithDoubleValue(double value);
+ static Value * valueWithPointerValue(void * value);
+ static Value * valueWithData(const char * value, int length);
+
+ virtual bool boolValue();
+ virtual char charValue();
+ virtual unsigned char unsignedCharValue();
+ virtual short shortValue();
+ virtual unsigned short unsignedShortValue();
+ virtual int intValue();
+ virtual unsigned int unsignedIntValue();
+ virtual long longValue();
+ virtual unsigned long unsignedLongValue();
+ virtual long long longLongValue();
+ virtual unsigned long long unsignedLongLongValue();
+ virtual float floatValue();
+ virtual double doubleValue();
+ virtual void * pointerValue();
+ virtual void dataValue(const char ** p_value, int * p_length);
+ };
+
+}
+
+#endif
diff --git a/src/core/imap/.DS_Store b/src/core/imap/.DS_Store
new file mode 100644
index 00000000..5008ddfc
--- /dev/null
+++ b/src/core/imap/.DS_Store
Binary files differ
diff --git a/src/core/imap/MCIMAP.h b/src/core/imap/MCIMAP.h
new file mode 100644
index 00000000..34b2d435
--- /dev/null
+++ b/src/core/imap/MCIMAP.h
@@ -0,0 +1,16 @@
+#ifndef __MAILCORE_MCIMAP_H_
+
+#define __MAILCORE_MCIMAP_H_
+
+#include <mailcore/MCIMAPFolder.h>
+#include <mailcore/MCIMAPMessage.h>
+#include <mailcore/MCIMAPMessagePart.h>
+#include <mailcore/MCIMAPMultipart.h>
+#include <mailcore/MCIMAPNamespace.h>
+#include <mailcore/MCIMAPNamespaceItem.h>
+#include <mailcore/MCIMAPPart.h>
+#include <mailcore/MCIMAPProgressCallback.h>
+#include <mailcore/MCIMAPSearchExpression.h>
+#include <mailcore/MCIMAPSession.h>
+
+#endif
diff --git a/src/core/imap/MCIMAPFolder.cc b/src/core/imap/MCIMAPFolder.cc
new file mode 100644
index 00000000..0f1b2105
--- /dev/null
+++ b/src/core/imap/MCIMAPFolder.cc
@@ -0,0 +1,71 @@
+#include "MCIMAPFolder.h"
+
+using namespace mailcore;
+
+void IMAPFolder::init()
+{
+ mPath = NULL;
+ mDelimiter = 0;
+ mFlags = IMAPFolderFlagNone;
+}
+
+IMAPFolder::IMAPFolder()
+{
+ init();
+}
+
+IMAPFolder::IMAPFolder(IMAPFolder * other)
+{
+ init();
+ setPath(other->path());
+ setDelimiter(other->delimiter());
+ setFlags(other->flags());
+}
+
+IMAPFolder::~IMAPFolder()
+{
+ MC_SAFE_RELEASE(mPath);
+}
+
+#if 0
+String * IMAPFolder::className()
+{
+ return MCSTR("IMAPFolder");
+}
+#endif
+
+Object * IMAPFolder::copy()
+{
+ return new IMAPFolder(this);
+}
+
+void IMAPFolder::setPath(String * path)
+{
+ MC_SAFE_REPLACE_COPY(String, mPath, path);
+}
+
+String * IMAPFolder::path()
+{
+ return mPath;
+}
+
+void IMAPFolder::setDelimiter(char delimiter)
+{
+ mDelimiter = delimiter;
+}
+
+char IMAPFolder::delimiter()
+{
+ return mDelimiter;
+}
+
+void IMAPFolder::setFlags(IMAPFolderFlag flags)
+{
+ mFlags = flags;
+}
+
+IMAPFolderFlag IMAPFolder::flags()
+{
+ return mFlags;
+}
+
diff --git a/src/core/imap/MCIMAPFolder.h b/src/core/imap/MCIMAPFolder.h
new file mode 100644
index 00000000..f68498c2
--- /dev/null
+++ b/src/core/imap/MCIMAPFolder.h
@@ -0,0 +1,36 @@
+#ifndef __MAILCORE_MCIMAPFOLDER_H
+
+#define __MAILCORE_MCIMAPFOLDER_H
+
+#include <mailcore/MCBaseTypes.h>
+#include <mailcore/MCMessageConstants.h>
+
+namespace mailcore {
+
+ class IMAPFolder : public Object {
+ private:
+ String * mPath;
+ char mDelimiter;
+ IMAPFolderFlag mFlags;
+ void init();
+ public:
+ IMAPFolder();
+ IMAPFolder(IMAPFolder * other);
+ virtual ~IMAPFolder();
+
+ //virtual String * className();
+ virtual Object * copy();
+
+ virtual void setPath(String * path);
+ virtual String * path();
+
+ virtual void setDelimiter(char delimiter);
+ virtual char delimiter();
+
+ virtual void setFlags(IMAPFolderFlag flags);
+ virtual IMAPFolderFlag flags();
+ };
+
+}
+
+#endif
diff --git a/src/core/imap/MCIMAPMessage.cc b/src/core/imap/MCIMAPMessage.cc
new file mode 100644
index 00000000..faf91c66
--- /dev/null
+++ b/src/core/imap/MCIMAPMessage.cc
@@ -0,0 +1,111 @@
+#include "MCIMAPMessage.h"
+
+#include "MCMessageHeader.h"
+
+using namespace mailcore;
+
+void IMAPMessage::init()
+{
+ mUid = NULL;
+ mFlags = MessageFlagNone;
+ mOriginalFlags = MessageFlagNone;
+ mMainPart = NULL;
+ mLabels = NULL;
+}
+
+IMAPMessage::IMAPMessage()
+{
+ init();
+}
+
+IMAPMessage::IMAPMessage(IMAPMessage * other)
+{
+ init();
+ setUid(other->uid());
+ setFlags(other->flags());
+ setOriginalFlags(other->originalFlags());
+ setMainPart((AbstractPart *) other->mainPart()->copy()->autorelease());
+ setGmailLabels(other->gmailLabels());
+}
+
+IMAPMessage::~IMAPMessage()
+{
+ MC_SAFE_RELEASE(mMainPart);
+ MC_SAFE_RELEASE(mLabels);
+}
+
+#if 0
+String * IMAPMessage::className()
+{
+ return MCSTR("IMAPMessage");
+}
+#endif
+
+Object * IMAPMessage::copy()
+{
+ return new IMAPMessage(this);
+}
+
+String * IMAPMessage::description()
+{
+ String * result = String::string();
+ result->appendUTF8Format("<%s:%p %u\n", className()->UTF8Characters(), this, (unsigned int) uid());
+ result->appendString(header()->description());
+ if (mainPart() != NULL) {
+ result->appendString(mainPart()->description());
+ result->appendUTF8Characters("\n");
+ }
+ result->appendUTF8Characters(">");
+ return result;
+}
+
+uint32_t IMAPMessage::uid()
+{
+ return mUid;
+}
+
+void IMAPMessage::setUid(uint32_t uid)
+{
+ mUid = uid;
+}
+
+void IMAPMessage::setFlags(MessageFlag flags)
+{
+ mFlags = flags;
+}
+
+MessageFlag IMAPMessage::flags()
+{
+ return mFlags;
+}
+
+void IMAPMessage::setOriginalFlags(MessageFlag flags)
+{
+ mOriginalFlags = flags;
+}
+
+MessageFlag IMAPMessage::originalFlags()
+{
+ return mOriginalFlags;
+}
+
+void IMAPMessage::setMainPart(AbstractPart * mainPart)
+{
+ MC_SAFE_REPLACE_RETAIN(AbstractPart, mMainPart, mainPart);
+}
+
+AbstractPart * IMAPMessage::mainPart()
+{
+ return mMainPart;
+}
+
+void IMAPMessage::setGmailLabels(Array * labels)
+{
+ MC_SAFE_REPLACE_COPY(Array, mLabels, labels);
+}
+
+Array * IMAPMessage::gmailLabels()
+{
+ return mLabels;
+}
+
diff --git a/src/core/imap/MCIMAPMessage.h b/src/core/imap/MCIMAPMessage.h
new file mode 100644
index 00000000..afaa07c8
--- /dev/null
+++ b/src/core/imap/MCIMAPMessage.h
@@ -0,0 +1,47 @@
+#ifndef __MAILCORE_IMAP_MESSAGE_H_
+
+#define __MAILCORE_IMAP_MESSAGE_H_
+
+#include <mailcore/MCBaseTypes.h>
+#include <mailcore/MCAbstractMessage.h>
+#include <mailcore/MCMessageConstants.h>
+#include <mailcore/MCAbstractPart.h>
+
+namespace mailcore {
+
+ class IMAPMessage : public AbstractMessage {
+ private:
+ uint32_t mUid;
+ MessageFlag mFlags;
+ MessageFlag mOriginalFlags;
+ AbstractPart * mMainPart;
+ Array * mLabels;
+ void init();
+ public:
+ IMAPMessage();
+ IMAPMessage(IMAPMessage * other);
+ ~IMAPMessage();
+
+ //virtual String * className();
+ virtual Object * copy();
+ virtual String * description();
+
+ virtual uint32_t uid();
+ virtual void setUid(uint32_t uid);
+
+ virtual void setFlags(MessageFlag flags);
+ virtual MessageFlag flags();
+
+ virtual void setOriginalFlags(MessageFlag flags);
+ virtual MessageFlag originalFlags();
+
+ virtual void setMainPart(AbstractPart * mainPart);
+ virtual AbstractPart * mainPart();
+
+ virtual void setGmailLabels(Array * labels);
+ virtual Array * gmailLabels();
+ };
+
+}
+
+#endif
diff --git a/src/core/imap/MCIMAPMessagePart.cc b/src/core/imap/MCIMAPMessagePart.cc
new file mode 100644
index 00000000..31a6f7e5
--- /dev/null
+++ b/src/core/imap/MCIMAPMessagePart.cc
@@ -0,0 +1,27 @@
+#include "MCIMAPMessagePart.h"
+
+using namespace mailcore;
+
+IMAPMessagePart::IMAPMessagePart()
+{
+}
+
+IMAPMessagePart::IMAPMessagePart(IMAPMessagePart * other) : AbstractMessagePart(other)
+{
+}
+
+IMAPMessagePart::~IMAPMessagePart()
+{
+}
+
+#if 0
+String * IMAPMessagePart::className()
+{
+ return MCSTR("IMAPMessagePart");
+}
+#endif
+
+Object * IMAPMessagePart::copy()
+{
+ return new IMAPMessagePart(this);
+}
diff --git a/src/core/imap/MCIMAPMessagePart.h b/src/core/imap/MCIMAPMessagePart.h
new file mode 100644
index 00000000..37e12fea
--- /dev/null
+++ b/src/core/imap/MCIMAPMessagePart.h
@@ -0,0 +1,23 @@
+#ifndef __MAILCORE_IMAPMESSAGEPART_H_
+
+#define __MAILCORE_IMAPMESSAGEPART_H_
+
+#include <mailcore/MCAbstractMessagePart.h>
+
+namespace mailcore {
+
+ class IMAPMessagePart : public AbstractMessagePart {
+ private:
+
+ public:
+ IMAPMessagePart();
+ IMAPMessagePart(IMAPMessagePart * other);
+ virtual ~IMAPMessagePart();
+
+ //virtual String * className();
+ virtual Object * copy();
+ };
+}
+
+
+#endif
diff --git a/src/core/imap/MCIMAPMultipart.cc b/src/core/imap/MCIMAPMultipart.cc
new file mode 100644
index 00000000..a941cbc4
--- /dev/null
+++ b/src/core/imap/MCIMAPMultipart.cc
@@ -0,0 +1,28 @@
+#include "MCIMAPMultipart.h"
+
+using namespace mailcore;
+
+IMAPMultipart::IMAPMultipart()
+{
+}
+
+IMAPMultipart::IMAPMultipart(IMAPMultipart * other) : AbstractMultipart(other)
+{
+}
+
+IMAPMultipart::~IMAPMultipart()
+{
+}
+
+#if 0
+String * IMAPMultipart::className()
+{
+ return MCSTR("IMAPMultipart");
+}
+#endif
+
+Object * IMAPMultipart::copy()
+{
+ return new IMAPMultipart(this);
+}
+
diff --git a/src/core/imap/MCIMAPMultipart.h b/src/core/imap/MCIMAPMultipart.h
new file mode 100644
index 00000000..bdb33470
--- /dev/null
+++ b/src/core/imap/MCIMAPMultipart.h
@@ -0,0 +1,22 @@
+#ifndef __MAILCORE_MCIMAPMULTIPART_H
+
+#define __MAILCORE_MCIMAPMULTIPART_H
+
+#include <mailcore/MCAbstractMultipart.h>
+
+namespace mailcore {
+
+ class IMAPMultipart : public AbstractMultipart {
+ private:
+
+ public:
+ IMAPMultipart();
+ IMAPMultipart(IMAPMultipart * other);
+ virtual ~IMAPMultipart();
+
+ //virtual String * className();
+ virtual Object * copy();
+ };
+}
+
+#endif
diff --git a/src/core/imap/MCIMAPNamespace.cc b/src/core/imap/MCIMAPNamespace.cc
new file mode 100644
index 00000000..b18752e4
--- /dev/null
+++ b/src/core/imap/MCIMAPNamespace.cc
@@ -0,0 +1,144 @@
+#include "MCIMAPNamespace.h"
+
+#include "MCIMAPNamespaceItem.h"
+
+using namespace mailcore;
+
+void IMAPNamespace::init()
+{
+ mItems = NULL;
+}
+
+IMAPNamespace::IMAPNamespace()
+{
+ init();
+ mItems = new Array();
+}
+
+IMAPNamespace::IMAPNamespace(IMAPNamespace * other)
+{
+ init();
+ mItems = (Array *) other->mItems->copy();
+}
+
+IMAPNamespace::~IMAPNamespace()
+{
+ MC_SAFE_RELEASE(mItems);
+}
+
+#if 0
+String * IMAPNamespace::className()
+{
+ return MCSTR("IMAPNamespace");
+}
+#endif
+
+String * IMAPNamespace::description()
+{
+ String * result = String::string();
+ result->appendUTF8Format("<%s:%p %s>", MCUTF8(className()), this,
+ MCUTF8DESC(mItems));
+ return result;
+}
+
+Object * IMAPNamespace::copy()
+{
+ return new IMAPNamespace(this);
+}
+
+IMAPNamespaceItem * IMAPNamespace::mainItem()
+{
+ if (mItems->count() == 0)
+ return NULL;
+
+ return (IMAPNamespaceItem *) mItems->objectAtIndex(0);
+}
+
+IMAPNamespaceItem * IMAPNamespace::itemForPath(String * path)
+{
+ for(unsigned int i = 0 ; i < mItems->count() ; i ++) {
+ IMAPNamespaceItem * item = (IMAPNamespaceItem *) mItems->objectAtIndex(i);
+ if (item->containsFolder(path))
+ return item;
+ }
+
+ return NULL;
+}
+
+String * IMAPNamespace::mainPrefix()
+{
+ if (mItems->count() == 0)
+ return NULL;
+
+ return mainItem()->prefix();
+}
+
+char IMAPNamespace::mainDelimiter()
+{
+ if (mItems->count() == 0)
+ return NULL;
+
+ return mainItem()->delimiter();
+}
+
+Array * IMAPNamespace::prefixes()
+{
+ Array * result = Array::array();
+ for(unsigned int i = 0 ; i < mItems->count() ; i ++) {
+ IMAPNamespaceItem * item = (IMAPNamespaceItem *) mItems->objectAtIndex(i);
+ result->addObject(item->prefix());
+ }
+ return result;
+}
+
+String * IMAPNamespace::pathForComponents(Array * components)
+{
+ return mainItem()->pathForComponents(components);
+}
+
+String * IMAPNamespace::pathForComponentsAndPrefix(Array * components, String * prefix)
+{
+ return itemForPath(prefix)->pathForComponents(components);
+}
+
+Array * IMAPNamespace::componentsFromPath(String * path)
+{
+ IMAPNamespaceItem * item = itemForPath(path);
+ return item->componentsForPath(path);
+}
+
+bool IMAPNamespace::containsFolderPath(String * path)
+{
+ return (itemForPath(path) != NULL);
+}
+
+IMAPNamespace * IMAPNamespace::namespaceWithPrefix(String * prefix, char delimiter)
+{
+ IMAPNamespace * ns;
+ IMAPNamespaceItem * item;
+
+ ns = new IMAPNamespace();
+ item = new IMAPNamespaceItem();
+ item->setDelimiter(delimiter);
+ item->setPrefix(prefix);
+ ns->mItems->addObject(item);
+ item->release();
+
+ return (IMAPNamespace *) ns->autorelease();
+}
+
+void IMAPNamespace::importIMAPNamespace(struct mailimap_namespace_item * item)
+{
+ clistiter * cur;
+
+ for(cur = clist_begin(item->ns_data_list) ; cur != NULL ; cur = clist_next(cur)) {
+ IMAPNamespaceItem * item;
+ struct mailimap_namespace_info * info;
+
+ info = (struct mailimap_namespace_info *) clist_content(cur);
+ item = new IMAPNamespaceItem();
+ item->importIMAPNamespaceInfo(info);
+ mItems->addObject(item);
+ item->release();
+ }
+}
diff --git a/src/core/imap/MCIMAPNamespace.h b/src/core/imap/MCIMAPNamespace.h
new file mode 100644
index 00000000..b9cbf92a
--- /dev/null
+++ b/src/core/imap/MCIMAPNamespace.h
@@ -0,0 +1,44 @@
+#ifndef __MAILCORE_MCIMAPNAMESPACE_H_
+
+#define __MAILCORE_MCIMAPNAMESPACE_H_
+
+#include <mailcore/MCBaseTypes.h>
+
+namespace mailcore {
+
+ class IMAPNamespaceItem;
+
+ class IMAPNamespace : public Object {
+ private:
+ Array * mItems;
+ void init();
+ IMAPNamespaceItem * mainItem();
+ IMAPNamespaceItem * itemForPath(String * path);
+ public:
+ IMAPNamespace();
+ IMAPNamespace(IMAPNamespace * other);
+ virtual ~IMAPNamespace();
+
+ //virtual String * className();
+ virtual String * description();
+ virtual Object * copy();
+
+ virtual String * mainPrefix();
+ virtual char mainDelimiter();
+
+ virtual Array * prefixes();
+
+ virtual String * pathForComponents(Array * components);
+ virtual String * pathForComponentsAndPrefix(Array * components, String * prefix);
+
+ virtual Array * componentsFromPath(String * path);
+
+ virtual bool containsFolderPath(String * path);
+
+ static IMAPNamespace * namespaceWithPrefix(String * prefix, char delimiter);
+ virtual void importIMAPNamespace(struct mailimap_namespace_item * item);
+ };
+
+}
+
+#endif
diff --git a/src/core/imap/MCIMAPNamespaceItem.cc b/src/core/imap/MCIMAPNamespaceItem.cc
new file mode 100644
index 00000000..62fca1f0
--- /dev/null
+++ b/src/core/imap/MCIMAPNamespaceItem.cc
@@ -0,0 +1,147 @@
+#include "MCIMAPNamespaceItem.h"
+
+using namespace mailcore;
+
+static Array * encodedComponents(Array * components);
+static Array * decodedComponents(Array * components);
+
+void IMAPNamespaceItem::init()
+{
+ mDelimiter = 0;
+ mPrefix = NULL;
+}
+
+IMAPNamespaceItem::IMAPNamespaceItem()
+{
+ init();
+}
+
+IMAPNamespaceItem::IMAPNamespaceItem(IMAPNamespaceItem * other)
+{
+ init();
+ setDelimiter(other->delimiter());
+ setPrefix(other->prefix());
+}
+
+IMAPNamespaceItem::~IMAPNamespaceItem()
+{
+ MC_SAFE_RELEASE(mPrefix);
+}
+
+#if 0
+String * IMAPNamespaceItem::className()
+{
+ return MCSTR("IMAPNamespaceItem");
+}
+#endif
+
+String * IMAPNamespaceItem::description()
+{
+ return String::stringWithUTF8Format("<%s:%p %s %c>",
+ MCUTF8(className()), this, MCUTF8(prefix()), delimiter());
+}
+
+Object * IMAPNamespaceItem::copy()
+{
+ return new IMAPNamespaceItem(this);
+}
+
+void IMAPNamespaceItem::setPrefix(String * prefix)
+{
+ MC_SAFE_REPLACE_COPY(String, mPrefix, prefix);
+}
+
+String * IMAPNamespaceItem::prefix()
+{
+ return mPrefix;
+}
+
+void IMAPNamespaceItem::setDelimiter(char delimiter)
+{
+ mDelimiter = delimiter;
+}
+
+char IMAPNamespaceItem::delimiter()
+{
+ return mDelimiter;
+}
+
+String * IMAPNamespaceItem::pathForComponents(Array * components)
+{
+ String * path;
+ String * prefix;
+
+ components = encodedComponents(components);
+ path = components->componentsJoinedByString(String::stringWithUTF8Format("%c", mDelimiter));
+
+ prefix = mPrefix;
+ if (prefix->length() > 0) {
+ if (!prefix->hasSuffix(String::stringWithUTF8Format("%c", mDelimiter))) {
+ prefix = prefix->stringByAppendingUTF8Format("%c", mDelimiter);
+ }
+ }
+ return prefix->stringByAppendingString(path);
+}
+
+Array * IMAPNamespaceItem::componentsForPath(String * path)
+{
+ Array * components;
+
+ if (path->hasPrefix(mPrefix)) {
+ path = path->substringFromIndex(mPrefix->length());
+ }
+ components = path->componentsSeparatedByString(String::stringWithUTF8Format("%c", mDelimiter));
+ components = decodedComponents(components);
+ if (components->count() > 0) {
+ if (((String *) components->objectAtIndex(0))->length() == 0) {
+ components->removeObjectAtIndex(0);
+ }
+ }
+
+ return components;
+}
+
+bool IMAPNamespaceItem::containsFolder(String * folder)
+{
+ if (mPrefix->length() == 0)
+ return true;
+ return folder->hasPrefix(mPrefix);
+}
+
+void IMAPNamespaceItem::importIMAPNamespaceInfo(struct mailimap_namespace_info * info)
+{
+ setPrefix(String::stringWithUTF8Characters(info->ns_prefix));
+ setDelimiter(info->ns_delimiter);
+}
+
+static Array * encodedComponents(Array * components)
+{
+ Array * result;
+
+ result = Array::array();
+ for(unsigned int i = 0 ; i < components->count() ; i ++) {
+ String * value = (String *) components->objectAtIndex(i);
+ result->addObject(value->mUTF7EncodedString());
+ }
+
+ return result;
+}
+
+static Array * decodedComponents(Array * components)
+{
+ Array * result;
+
+ result = Array::array();
+ for(unsigned int i = 0 ; i < components->count() ; i ++) {
+ String * value = (String *) components->objectAtIndex(i);
+ String * decoded;
+
+ decoded = value->mUTF7DecodedString();
+ if (decoded == NULL) {
+ decoded = value;
+ }
+ result->addObject(decoded);
+ }
+
+ return result;
+}
diff --git a/src/core/imap/MCIMAPNamespaceItem.h b/src/core/imap/MCIMAPNamespaceItem.h
new file mode 100644
index 00000000..3b40ae7c
--- /dev/null
+++ b/src/core/imap/MCIMAPNamespaceItem.h
@@ -0,0 +1,39 @@
+#ifndef __MAILCORE_MCIMAPNAMESPACEITEM_H
+
+#define __MAILCORE_MCIMAPNAMESPACEITEM_H
+
+#include <mailcore/MCBaseTypes.h>
+
+namespace mailcore {
+
+ class IMAPNamespaceItem : public Object {
+ private:
+ char mDelimiter;
+ String * mPrefix;
+ void init();
+ public:
+ IMAPNamespaceItem();
+ IMAPNamespaceItem(IMAPNamespaceItem * other);
+ virtual ~IMAPNamespaceItem();
+
+ //virtual String * className();
+ virtual String * description();
+ virtual Object * copy();
+
+ virtual void setPrefix(String * prefix);
+ virtual String * prefix();
+
+ virtual void setDelimiter(char delimiter);
+ virtual char delimiter();
+
+ virtual String * pathForComponents(Array * components);
+ virtual Array * componentsForPath(String * path);
+
+ virtual bool containsFolder(String * folder);
+
+ virtual void importIMAPNamespaceInfo(struct mailimap_namespace_info * info);
+ };
+
+}
+
+#endif
diff --git a/src/core/imap/MCIMAPPart.cc b/src/core/imap/MCIMAPPart.cc
new file mode 100644
index 00000000..110c8fa0
--- /dev/null
+++ b/src/core/imap/MCIMAPPart.cc
@@ -0,0 +1,285 @@
+#include "MCIMAPPart.h"
+
+#include <string.h>
+
+#include "MCIMAPMessagePart.h"
+#include "MCIMAPMultipart.h"
+#include "MCMessageHeader.h"
+
+using namespace mailcore;
+
+void IMAPPart::init()
+{
+ mPartID = NULL;
+ mEncoding = Encoding8Bit;
+ mSize = 0;
+}
+
+IMAPPart::IMAPPart()
+{
+ init();
+}
+
+IMAPPart::IMAPPart(IMAPPart * other) : AbstractPart(other)
+{
+ init();
+ MC_SAFE_REPLACE_COPY(String, mPartID, other->mPartID);
+ mEncoding = other->mEncoding;
+ mSize = other->mSize;
+}
+
+IMAPPart::~IMAPPart()
+{
+ MC_SAFE_RELEASE(mPartID);
+}
+
+#if 0
+String * IMAPPart::className()
+{
+ return MCSTR("IMAPPart");
+}
+#endif
+
+Object * IMAPPart::copy()
+{
+ return new IMAPPart(this);
+}
+
+void IMAPPart::setPartID(String * partID)
+{
+ MC_SAFE_REPLACE_COPY(String, mPartID, partID);
+}
+
+String * IMAPPart::partID()
+{
+ return mPartID;
+}
+
+void IMAPPart::setSize(unsigned int size)
+{
+ mSize = size;
+}
+
+unsigned int IMAPPart::size()
+{
+ return mSize;
+}
+
+void IMAPPart::setEncoding(Encoding encoding)
+{
+ mEncoding = encoding;
+}
+
+Encoding IMAPPart::encoding()
+{
+ return mEncoding;
+}
+
+unsigned int IMAPPart::decodedSize()
+{
+ switch (mEncoding) {
+ case MAILIMAP_BODY_FLD_ENC_BASE64:
+ return mSize * 3 / 4;
+
+ default:
+ return mSize;
+ }
+}
+
+AbstractPart * IMAPPart::attachmentWithIMAPBody(struct mailimap_body * body)
+{
+ String * partID;
+
+ partID = NULL;
+ if (body->bd_type == MAILIMAP_BODY_1PART) {
+ partID = MCSTR("1");
+ }
+ return attachmentWithIMAPBodyInternal(body, partID);
+}
+
+AbstractPart * IMAPPart::attachmentWithIMAPBodyInternal(struct mailimap_body * body, String * partID)
+{
+ switch (body->bd_type) {
+ case MAILIMAP_BODY_1PART:
+ return attachmentWithIMAPBody1Part(body->bd_data.bd_body_1part, partID);
+ case MAILIMAP_BODY_MPART:
+ return attachmentWithIMAPBodyMultipart(body->bd_data.bd_body_mpart, partID);
+ }
+
+ return NULL;
+}
+
+AbstractPart * IMAPPart::attachmentWithIMAPBody1Part(struct mailimap_body_type_1part * body_1part,
+ String * partID)
+{
+ switch (body_1part->bd_type) {
+ case MAILIMAP_BODY_TYPE_1PART_BASIC:
+ {
+ IMAPPart * attachment;
+
+ attachment = attachmentWithIMAPBody1PartBasic(body_1part->bd_data.bd_type_basic,
+ body_1part->bd_ext_1part);
+ attachment->setPartID(partID);
+ return attachment;
+ }
+ case MAILIMAP_BODY_TYPE_1PART_MSG:
+ {
+ return attachmentWithIMAPBody1PartMessage(body_1part->bd_data.bd_type_msg,
+ body_1part->bd_ext_1part, partID);
+ }
+ case MAILIMAP_BODY_TYPE_1PART_TEXT:
+ {
+ IMAPPart * attachment;
+
+ attachment = attachmentWithIMAPBody1PartText(body_1part->bd_data.bd_type_text,
+ body_1part->bd_ext_1part);
+ attachment->setPartID(partID);
+ MCLog("attachment %s", MCUTF8(partID));
+ return attachment;
+ }
+ }
+
+ return NULL;
+}
+
+IMAPMessagePart * IMAPPart::attachmentWithIMAPBody1PartMessage(struct mailimap_body_type_msg * message,
+ struct mailimap_body_ext_1part * extension,
+ String * partID)
+{
+ IMAPMessagePart * attachment;
+ AbstractPart * subAttachment;
+ String * nextPartID;
+
+ nextPartID = NULL;
+ if (message->bd_body->bd_type == MAILIMAP_BODY_1PART) {
+ // msg or 1part
+ nextPartID = partID->stringByAppendingUTF8Format(".1");
+ }
+ else if (message->bd_body->bd_type == MAILIMAP_BODY_MPART) {
+ // mpart
+ nextPartID = partID;
+ }
+
+ attachment = new IMAPMessagePart();
+ attachment->header()->importIMAPEnvelope(message->bd_envelope);
+ attachment->importIMAPFields(message->bd_fields, extension);
+
+ subAttachment = attachmentWithIMAPBodyInternal(message->bd_body, nextPartID);
+ attachment->setMainPart(subAttachment);
+
+ return (IMAPMessagePart *) attachment->autorelease();
+}
+
+void IMAPPart::importIMAPFields(struct mailimap_body_fields * fields,
+ struct mailimap_body_ext_1part * extension)
+{
+ AbstractPart::importIMAPFields(fields, extension);
+
+ setSize(fields->bd_size);
+ if (fields->bd_encoding != NULL) {
+ bool isUUEncode;
+
+ isUUEncode = false;
+ if (fields->bd_encoding->enc_type == MAILIMAP_BODY_FLD_ENC_OTHER) {
+ if (strcasecmp(fields->bd_encoding->enc_value, "x-uuencode") == 0) {
+ isUUEncode = true;
+ }
+ }
+ if (isUUEncode) {
+ setEncoding(EncodingUUEncode);
+ }
+ else {
+ setEncoding((Encoding) fields->bd_encoding->enc_type);
+ }
+ }
+}
+
+IMAPPart * IMAPPart::attachmentWithIMAPBody1PartBasic(struct mailimap_body_type_basic * basic,
+ struct mailimap_body_ext_1part * extension)
+{
+ IMAPPart * attachment;
+ String * mimeType;
+
+ attachment = new IMAPPart();
+ attachment->importIMAPFields(basic->bd_fields, extension);
+
+ mimeType = NULL;
+ switch (basic->bd_media_basic->med_type) {
+ case MAILIMAP_MEDIA_BASIC_APPLICATION:
+ mimeType = String::stringWithUTF8Format("application/%s", basic->bd_media_basic->med_subtype);
+ break;
+ case MAILIMAP_MEDIA_BASIC_AUDIO:
+ mimeType = String::stringWithUTF8Format("audio/%s", basic->bd_media_basic->med_subtype);
+ break;
+ case MAILIMAP_MEDIA_BASIC_IMAGE:
+ mimeType = String::stringWithUTF8Format("image/%s", basic->bd_media_basic->med_subtype);
+ break;
+ case MAILIMAP_MEDIA_BASIC_MESSAGE:
+ mimeType = String::stringWithUTF8Format("message/%s", basic->bd_media_basic->med_subtype);
+ break;
+ case MAILIMAP_MEDIA_BASIC_VIDEO:
+ mimeType = String::stringWithUTF8Format("video/%s", basic->bd_media_basic->med_subtype);
+ break;
+ case MAILIMAP_MEDIA_BASIC_OTHER:
+ mimeType = String::stringWithUTF8Format("other/%s", basic->bd_media_basic->med_subtype);
+ break;
+ }
+ attachment->setMimeType(mimeType);
+
+ return (IMAPPart *) attachment->autorelease();
+}
+
+IMAPPart * IMAPPart::attachmentWithIMAPBody1PartText(struct mailimap_body_type_text * text,
+ struct mailimap_body_ext_1part * extension)
+{
+ IMAPPart * attachment;
+
+ attachment = new IMAPPart();
+ attachment->importIMAPFields(text->bd_fields, extension);
+ attachment->setMimeType(String::stringWithUTF8Format("text/%s", text->bd_media_text));
+
+ return (IMAPPart *) attachment->autorelease();
+}
+
+IMAPMultipart * IMAPPart::attachmentWithIMAPBodyMultipart(struct mailimap_body_type_mpart * body_mpart,
+ String * partID)
+{
+ clistiter * cur;
+ IMAPMultipart * attachment;
+ unsigned int count;
+ Array * attachments;
+
+ attachments = new Array();
+
+ count = 1;
+ for(cur = clist_begin(body_mpart->bd_list) ; cur != NULL ; cur = clist_next(cur)) {
+ struct mailimap_body * body;
+ AbstractPart * subResult;
+ String * nextPartID;
+
+ if (partID == NULL) {
+ nextPartID = String::stringWithUTF8Format("%u", count);
+ }
+ else {
+ nextPartID = partID->stringByAppendingUTF8Format(".%u", count);
+ }
+ body = (struct mailimap_body *) clist_content(cur);
+ subResult = attachmentWithIMAPBodyInternal(body, nextPartID);
+ attachments->addObject(subResult);
+
+ count ++;
+ }
+
+ attachment = new IMAPMultipart();
+ if (strcasecmp(body_mpart->bd_media_subtype, "alternative") == 0) {
+ attachment->setPartType(PartTypeMultipartAlternative);
+ }
+ else if (strcasecmp(body_mpart->bd_media_subtype, "related") == 0) {
+ attachment->setPartType(PartTypeMultipartRelated);
+ }
+ attachment->setParts(attachments);
+
+ attachments->release();
+
+ return (IMAPMultipart *) attachment->autorelease();
+}
diff --git a/src/core/imap/MCIMAPPart.h b/src/core/imap/MCIMAPPart.h
new file mode 100644
index 00000000..b8b3625d
--- /dev/null
+++ b/src/core/imap/MCIMAPPart.h
@@ -0,0 +1,58 @@
+#ifndef __MAILCORE_MCIMAPPART_H_
+
+#define __MAILCORE_MCIMAPPART_H_
+
+#include <mailcore/MCBaseTypes.h>
+#include <libetpan/libetpan.h>
+#include <mailcore/MCAbstractPart.h>
+
+namespace mailcore {
+
+ class IMAPMessagePart;
+ class IMAPMultipart;
+
+ class IMAPPart : public AbstractPart {
+ private:
+ String * mPartID;
+ Encoding mEncoding;
+ unsigned int mSize;
+ void init();
+ static AbstractPart * attachmentWithIMAPBodyInternal(struct mailimap_body * body, String * partID);
+ static AbstractPart * attachmentWithIMAPBody1Part(struct mailimap_body_type_1part * body_1part,
+ String * partID);
+ static IMAPMessagePart * attachmentWithIMAPBody1PartMessage(struct mailimap_body_type_msg * message,
+ struct mailimap_body_ext_1part * extension,
+ String * partID);
+ static IMAPPart * attachmentWithIMAPBody1PartBasic(struct mailimap_body_type_basic * basic,
+ struct mailimap_body_ext_1part * extension);
+ static IMAPPart * attachmentWithIMAPBody1PartText(struct mailimap_body_type_text * text,
+ struct mailimap_body_ext_1part * extension);
+ static IMAPMultipart * attachmentWithIMAPBodyMultipart(struct mailimap_body_type_mpart * body_mpart,
+ String * partID);
+ public:
+ IMAPPart();
+ IMAPPart(IMAPPart * other);
+ virtual ~IMAPPart();
+
+ //virtual String * className();
+ virtual Object * copy();
+
+ virtual void setPartID(String * partID);
+ virtual String * partID();
+
+ virtual void setSize(unsigned int size);
+ virtual unsigned int size();
+
+ virtual void setEncoding(Encoding encoding);
+ virtual Encoding encoding();
+
+ unsigned int decodedSize();
+
+ static AbstractPart * attachmentWithIMAPBody(struct mailimap_body * body);
+
+ virtual void importIMAPFields(struct mailimap_body_fields * fields,
+ struct mailimap_body_ext_1part * extension);
+ };
+}
+
+#endif
diff --git a/src/core/imap/MCIMAPProgressCallback.h b/src/core/imap/MCIMAPProgressCallback.h
new file mode 100644
index 00000000..b39e0dbd
--- /dev/null
+++ b/src/core/imap/MCIMAPProgressCallback.h
@@ -0,0 +1,16 @@
+#ifndef __MAILCORE_MCIMAPPROGRESSCALLBACK_H_
+
+#define __MAILCORE_MCIMAPPROGRESSCALLBACK_H_
+
+namespace mailcore {
+
+ class IMAPSession;
+
+ class IMAPProgressCallback {
+ public:
+ virtual void bodyProgress(IMAPSession * session, unsigned int current, unsigned int maximum) {};
+ virtual void itemsProgress(IMAPSession * session, unsigned int current, unsigned int maximum) {};
+ };
+}
+
+#endif
diff --git a/src/core/imap/MCIMAPSearchExpression.cc b/src/core/imap/MCIMAPSearchExpression.cc
new file mode 100644
index 00000000..14875c43
--- /dev/null
+++ b/src/core/imap/MCIMAPSearchExpression.cc
@@ -0,0 +1,163 @@
+#include "MCIMAPSearchExpression.h"
+
+using namespace mailcore;
+
+void IMAPSearchExpression::init()
+{
+ mKind = IMAPSearchKindNone;
+ mHeader = NULL;
+ mValue = NULL;
+ mLeftExpression = NULL;
+ mRightExpression = NULL;
+}
+
+IMAPSearchExpression::IMAPSearchExpression()
+{
+ init();
+}
+
+IMAPSearchExpression::IMAPSearchExpression(IMAPSearchExpression * other)
+{
+ init();
+ mKind = IMAPSearchKindNone;
+ MC_SAFE_REPLACE_COPY(String, mHeader, other->mHeader);
+ MC_SAFE_REPLACE_COPY(String, mValue, other->mValue);
+ MC_SAFE_REPLACE_COPY(IMAPSearchExpression, mLeftExpression, other->mLeftExpression);
+ MC_SAFE_REPLACE_COPY(IMAPSearchExpression, mRightExpression, other->mRightExpression);
+}
+
+IMAPSearchExpression::~IMAPSearchExpression()
+{
+ MC_SAFE_RELEASE(mHeader);
+ MC_SAFE_RELEASE(mValue);
+ MC_SAFE_RELEASE(mLeftExpression);
+ MC_SAFE_RELEASE(mRightExpression);
+}
+
+String * IMAPSearchExpression::description()
+{
+ switch (mKind) {
+ default:
+ case IMAPSearchKindNone:
+ return String::stringWithUTF8Format("<%s:%p None>", MCUTF8(className()), this);
+ case IMAPSearchKindFrom:
+ return String::stringWithUTF8Format("<%s:%p From %s>", MCUTF8(className()), this,
+ MCUTF8(mValue->description()));
+ case IMAPSearchKindRecipient:
+ return String::stringWithUTF8Format("<%s:%p Recipient %s>", MCUTF8(className()), this,
+ MCUTF8(mValue->description()));
+ case IMAPSearchKindSubject:
+ return String::stringWithUTF8Format("<%s:%p Subject %s>", MCUTF8(className()), this,
+ MCUTF8(mValue->description()));
+ case IMAPSearchKindContent:
+ return String::stringWithUTF8Format("<%s:%p Content %s>", MCUTF8(className()), this,
+ MCUTF8(mValue->description()));
+ case IMAPSearchKindHeader:
+ return String::stringWithUTF8Format("<%s:%p Header %s %s>", MCUTF8(className()), this,
+ MCUTF8(mHeader->description()), MCUTF8(mValue->description()));
+ case IMAPSearchKindOr:
+ return String::stringWithUTF8Format("<%s:%p Or %s %s>", MCUTF8(className()), this,
+ MCUTF8(mLeftExpression->description()), MCUTF8(mRightExpression->description()));
+ case IMAPSearchKindAnd:
+ return String::stringWithUTF8Format("<%s:%p And %s %s>", MCUTF8(className()), this,
+ MCUTF8(mLeftExpression->description()), MCUTF8(mRightExpression->description()));
+ }
+}
+
+#if 0
+String * IMAPSearchExpression::className()
+{
+ return MCSTR("IMAPSearchExpression");
+}
+#endif
+
+Object * IMAPSearchExpression::copy()
+{
+ return new IMAPSearchExpression(this);
+}
+
+IMAPSearchExpression * IMAPSearchExpression::searchFrom(String * value)
+{
+ IMAPSearchExpression * expr = new IMAPSearchExpression();
+ expr->mKind = IMAPSearchKindFrom;
+ MC_SAFE_REPLACE_COPY(String, expr->mValue, value);
+ return (IMAPSearchExpression *) expr->autorelease();
+}
+
+IMAPSearchExpression * IMAPSearchExpression::searchRecipient(String * value)
+{
+ IMAPSearchExpression * expr = new IMAPSearchExpression();
+ expr->mKind = IMAPSearchKindRecipient;
+ MC_SAFE_REPLACE_COPY(String, expr->mValue, value);
+ return (IMAPSearchExpression *) expr->autorelease();
+}
+
+IMAPSearchExpression * IMAPSearchExpression::searchSubject(String * value)
+{
+ IMAPSearchExpression * expr = new IMAPSearchExpression();
+ expr->mKind = IMAPSearchKindSubject;
+ MC_SAFE_REPLACE_COPY(String, expr->mValue, value);
+ return (IMAPSearchExpression *) expr->autorelease();
+}
+
+IMAPSearchExpression * IMAPSearchExpression::searchContent(String * value)
+{
+ IMAPSearchExpression * expr = new IMAPSearchExpression();
+ expr->mKind = IMAPSearchKindContent;
+ MC_SAFE_REPLACE_COPY(String, expr->mValue, value);
+ return (IMAPSearchExpression *) expr->autorelease();
+}
+
+IMAPSearchExpression * IMAPSearchExpression::searchHeader(String * header, String * value)
+{
+ IMAPSearchExpression * expr = new IMAPSearchExpression();
+ expr->mKind = IMAPSearchKindHeader;
+ MC_SAFE_REPLACE_COPY(String, expr->mHeader, header);
+ MC_SAFE_REPLACE_COPY(String, expr->mValue, value);
+ return (IMAPSearchExpression *) expr->autorelease();
+}
+
+IMAPSearchExpression * IMAPSearchExpression::searchAnd(IMAPSearchExpression * left, IMAPSearchExpression * right)
+{
+ IMAPSearchExpression * expr = new IMAPSearchExpression();
+ expr->mKind = IMAPSearchKindAnd;
+ MC_SAFE_REPLACE_RETAIN(IMAPSearchExpression, expr->mLeftExpression, left);
+ MC_SAFE_REPLACE_RETAIN(IMAPSearchExpression, expr->mRightExpression, right);
+ return (IMAPSearchExpression *) expr->autorelease();
+}
+
+IMAPSearchExpression * IMAPSearchExpression::searchOr(IMAPSearchExpression * left, IMAPSearchExpression * right)
+{
+ IMAPSearchExpression * expr = new IMAPSearchExpression();
+ expr->mKind = IMAPSearchKindOr;
+ MC_SAFE_REPLACE_RETAIN(IMAPSearchExpression, expr->mLeftExpression, left);
+ MC_SAFE_REPLACE_RETAIN(IMAPSearchExpression, expr->mRightExpression, right);
+ return (IMAPSearchExpression *) expr->autorelease();
+}
+
+IMAPSearchKind IMAPSearchExpression::kind()
+{
+ return mKind;
+}
+
+String * IMAPSearchExpression::header()
+{
+ return mHeader;
+}
+
+String * IMAPSearchExpression::value()
+{
+ return mValue;
+}
+
+IMAPSearchExpression * IMAPSearchExpression::leftExpression()
+{
+ return mLeftExpression;
+}
+
+IMAPSearchExpression * IMAPSearchExpression::rightExpression()
+{
+ return mRightExpression;
+}
+
+
diff --git a/src/core/imap/MCIMAPSearchExpression.h b/src/core/imap/MCIMAPSearchExpression.h
new file mode 100644
index 00000000..53a373cd
--- /dev/null
+++ b/src/core/imap/MCIMAPSearchExpression.h
@@ -0,0 +1,45 @@
+#ifndef __MAILCORE_MCIMAPSEARCHEXPRESSION_H_
+
+#define __MAILCORE_MCIMAPSEARCHEXPRESSION_H_
+
+#include <mailcore/MCBaseTypes.h>
+#include <mailcore/MCMessageConstants.h>
+
+namespace mailcore {
+
+ class IMAPSearchExpression : Object {
+ private:
+ IMAPSearchKind mKind;
+ String * mHeader;
+ String * mValue;
+ IMAPSearchExpression * mLeftExpression;
+ IMAPSearchExpression * mRightExpression;
+ void init();
+
+ public:
+ IMAPSearchExpression();
+ IMAPSearchExpression(IMAPSearchExpression * other);
+ virtual ~IMAPSearchExpression();
+
+ virtual String * description();
+ //virtual String * className();
+ virtual Object * copy();
+
+ virtual IMAPSearchKind kind();
+ virtual String * header();
+ virtual String * value();
+ virtual IMAPSearchExpression * leftExpression();
+ virtual IMAPSearchExpression * rightExpression();
+
+ static IMAPSearchExpression * searchFrom(String * value);
+ static IMAPSearchExpression * searchRecipient(String * value);
+ static IMAPSearchExpression * searchSubject(String * value);
+ static IMAPSearchExpression * searchContent(String * value);
+ static IMAPSearchExpression * searchHeader(String * header, String * value);
+ static IMAPSearchExpression * searchAnd(IMAPSearchExpression * left, IMAPSearchExpression * right);
+ static IMAPSearchExpression * searchOr(IMAPSearchExpression * left, IMAPSearchExpression * right);
+ };
+
+}
+
+#endif
diff --git a/src/core/imap/MCIMAPSession.cc b/src/core/imap/MCIMAPSession.cc
new file mode 100644
index 00000000..317af507
--- /dev/null
+++ b/src/core/imap/MCIMAPSession.cc
@@ -0,0 +1,2559 @@
+#include "MCIMAPSession.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "MCIMAPSearchExpression.h"
+#include "MCIMAPFolder.h"
+#include "MCIMAPMessage.h"
+#include "MCIMAPPart.h"
+#include "MCMessageHeader.h"
+#include "MCAbstractPart.h"
+#include "MCIMAPProgressCallback.h"
+#include "MCIMAPNamespace.h"
+
+using namespace mailcore;
+
+enum {
+ STATE_DISCONNECTED,
+ STATE_CONNECTED,
+ STATE_LOGGEDIN,
+ STATE_SELECTED,
+};
+
+String * mailcore::IMAPNamespacePersonal = NULL;
+String * mailcore::IMAPNamespaceOther = NULL;
+String * mailcore::IMAPNamespaceShared = NULL;
+
+__attribute__((constructor))
+static void initialize() {
+ AutoreleasePool * pool = new AutoreleasePool();
+ IMAPNamespacePersonal = (String *) MCSTR("IMAPNamespacePersonal")->retain();
+ IMAPNamespaceOther = (String *) MCSTR("IMAPNamespaceOther")->retain();
+ IMAPNamespaceShared = (String *) MCSTR("IMAPNamespaceShared")->retain();
+ pool->release();
+}
+
+#define MAX_IDLE_DELAY (28 * 60)
+
+#define LOCK() pthread_mutex_lock(&mIdleLock)
+#define UNLOCK() pthread_mutex_unlock(&mIdleLock)
+
+static struct mailimap_flag_list * flags_to_lep(MessageFlag value)
+{
+ struct mailimap_flag_list * flag_list;
+
+ flag_list = mailimap_flag_list_new_empty();
+
+ if ((value & MessageFlagSeen) != 0) {
+ mailimap_flag_list_add(flag_list, mailimap_flag_new_seen());
+ }
+
+ if ((value & MessageFlagFlagged) != 0) {
+ mailimap_flag_list_add(flag_list, mailimap_flag_new_flagged());
+ }
+
+ if ((value & MessageFlagDeleted) != 0) {
+ mailimap_flag_list_add(flag_list, mailimap_flag_new_deleted());
+ }
+
+ if ((value & MessageFlagAnswered) != 0) {
+ mailimap_flag_list_add(flag_list, mailimap_flag_new_answered());
+ }
+
+ if ((value & MessageFlagDraft) != 0) {
+ mailimap_flag_list_add(flag_list, mailimap_flag_new_draft());
+ }
+
+ if ((value & MessageFlagForwarded) != 0) {
+ mailimap_flag_list_add(flag_list, mailimap_flag_new_flag_keyword(strdup("$Forwarded")));
+ }
+
+ if ((value & MessageFlagMDNSent) != 0) {
+ mailimap_flag_list_add(flag_list, mailimap_flag_new_flag_keyword(strdup("$MDNSent")));
+ }
+
+ if ((value & MessageFlagSubmitPending) != 0) {
+ mailimap_flag_list_add(flag_list, mailimap_flag_new_flag_keyword(strdup("$SubmitPending")));
+ }
+
+ if ((value & MessageFlagSubmitted) != 0) {
+ mailimap_flag_list_add(flag_list, mailimap_flag_new_flag_keyword(strdup("$Submitted")));
+ }
+
+ return flag_list;
+}
+
+static MessageFlag flag_from_lep(struct mailimap_flag * flag)
+{
+ switch (flag->fl_type) {
+ case MAILIMAP_FLAG_ANSWERED:
+ return MessageFlagAnswered;
+ case MAILIMAP_FLAG_FLAGGED:
+ return MessageFlagFlagged;
+ case MAILIMAP_FLAG_DELETED:
+ return MessageFlagDeleted;
+ case MAILIMAP_FLAG_SEEN:
+ return MessageFlagSeen;
+ case MAILIMAP_FLAG_DRAFT:
+ return MessageFlagDraft;
+ case MAILIMAP_FLAG_KEYWORD:
+ if (strcasecmp(flag->fl_data.fl_keyword, "$Forwarded") == 0) {
+ return MessageFlagForwarded;
+ }
+ else if (strcasecmp(flag->fl_data.fl_keyword, "$MDNSent") == 0) {
+ return MessageFlagMDNSent;
+ }
+ else if (strcasecmp(flag->fl_data.fl_keyword, "$SubmitPending") == 0) {
+ return MessageFlagSubmitPending;
+ }
+ else if (strcasecmp(flag->fl_data.fl_keyword, "$Submitted") == 0) {
+ return MessageFlagSubmitted;
+ }
+ }
+
+ return MessageFlagNone;
+}
+
+static MessageFlag flags_from_lep(struct mailimap_flag_list * flag_list)
+{
+ MessageFlag flags;
+ clistiter * iter;
+
+ flags = MessageFlagNone;
+ for(iter = clist_begin(flag_list->fl_list) ;iter != NULL ; iter = clist_next(iter)) {
+ struct mailimap_flag * flag;
+
+ flag = (struct mailimap_flag *) clist_content(iter);
+ flags = (MessageFlag) (flags | flag_from_lep(flag));
+ }
+
+ return flags;
+}
+
+static MessageFlag flags_from_lep_att_dynamic(struct mailimap_msg_att_dynamic * att_dynamic)
+{
+ MessageFlag flags;
+ clistiter * iter;
+
+ if (att_dynamic->att_list == NULL)
+ return MessageFlagNone;
+
+ flags = MessageFlagNone;
+ for(iter = clist_begin(att_dynamic->att_list) ;iter != NULL ; iter = clist_next(iter)) {
+ struct mailimap_flag_fetch * flag_fetch;
+ struct mailimap_flag * flag;
+
+ flag_fetch = (struct mailimap_flag_fetch *) clist_content(iter);
+ if (flag_fetch->fl_type != MAILIMAP_FLAG_FETCH_OTHER) {
+ continue;
+ }
+
+ flag = flag_fetch->fl_flag;
+ flags = (MessageFlag) (flags | flag_from_lep(flag));
+ }
+
+ return flags;
+}
+
+#pragma mark set conversion
+
+static Array * arrayFromSet(struct mailimap_set * imap_set)
+{
+ Array * result;
+ clistiter * iter;
+
+ result = Array::array();
+ for(iter = clist_begin(imap_set->set_list) ; iter != NULL ; iter = clist_next(iter)) {
+ struct mailimap_set_item * item;
+ unsigned long i;
+
+ item = (struct mailimap_set_item *) clist_content(iter);
+ for(i = item->set_first ; i <= item->set_last ; i ++) {
+ Value * nb;
+
+ nb = Value::valueWithUnsignedLongValue(i);
+ result->addObject(nb);
+ }
+ }
+
+ return result;
+}
+
+static int compareValuesUnsignedLong(void * value1, void * value2, void * context)
+{
+ Value * concreteValue1 = (Value *) value1;
+ Value * concreteValue2 = (Value *) value2;
+
+ if (concreteValue2->unsignedLongValue() > concreteValue1->unsignedLongValue()) {
+ return 1;
+ }
+ else if (concreteValue2->unsignedLongValue() < concreteValue1->unsignedLongValue()) {
+ return -1;
+ }
+ else {
+ return 0;
+ }
+}
+
+static struct mailimap_set * setFromArray(Array * array)
+{
+ unsigned int currentIndex;
+ unsigned int currentFirst;
+ unsigned int currentValue;
+ unsigned int lastValue;
+ struct mailimap_set * imap_set;
+
+ currentFirst = 0;
+ currentValue = 0;
+ lastValue = 0;
+ currentIndex = 0;
+
+ array = array->sortedArray(compareValuesUnsignedLong, NULL);
+ imap_set = mailimap_set_new_empty();
+
+ while (currentIndex < array->count()) {
+ currentValue = (unsigned int) ((Value *) array->objectAtIndex(currentIndex))->unsignedLongValue();
+ if (currentFirst == 0) {
+ currentFirst = currentValue;
+ }
+
+ if ((lastValue != 0) && (currentValue != lastValue + 1)) {
+ mailimap_set_add_interval(imap_set, currentFirst, lastValue);
+ currentFirst = 0;
+ lastValue = 0;
+ }
+ else {
+ lastValue = currentValue;
+ currentIndex ++;
+ }
+ }
+ if (currentFirst != 0) {
+ mailimap_set_add_interval(imap_set, currentFirst, lastValue);
+ }
+
+ return imap_set;
+}
+
+static clist * splitSet(struct mailimap_set * set, unsigned int splitCount)
+{
+ struct mailimap_set * current_set;
+ clist * result;
+ unsigned int count;
+
+ result = clist_new();
+
+ current_set = NULL;
+ count = 0;
+ for(clistiter * iter = clist_begin(set->set_list) ; iter != NULL ; iter = clist_next(iter)) {
+ struct mailimap_set_item * item;
+
+ if (current_set == NULL) {
+ current_set = mailimap_set_new_empty();
+ }
+
+ item = (struct mailimap_set_item *) clist_content(iter);
+ mailimap_set_add_interval(current_set, item->set_first, item->set_last);
+ count ++;
+
+ if (count >= splitCount) {
+ clist_append(result, current_set);
+ current_set = NULL;
+ count = 0;
+ }
+ }
+ if (current_set != NULL) {
+ clist_append(result, current_set);
+ }
+
+ return result;
+}
+
+void IMAPSession::init()
+{
+ mHostname = NULL;
+ mPort = 0;
+ mUsername = NULL;
+ mPassword = NULL;
+ mAuthType = AuthTypeSASLNone;
+ mConnectionType = ConnectionTypeClear;
+ mCheckCertificateEnabled = true;
+ mVoIPEnabled = true;
+ mDelimiter = 0;
+
+ mIdleEnabled = false;
+ mXListEnabled = false;
+ mWelcomeString = NULL;
+ mNeedsMboxMailWorkaround = false;
+ mDefaultNamespace = NULL;
+ mTimeout = 30;
+ mUIDValidity = 0;
+ mUIDNext = 0;
+ mFolderMsgCount = 0;
+ mLastFetchedSequenceNumber = 0;
+ mCurrentFolder = NULL;
+ pthread_mutex_init(&mIdleLock, NULL);
+ mState = STATE_DISCONNECTED;
+ mImap = NULL;
+ mProgressCallback = NULL;
+ mProgressItemsCount = 0;
+}
+
+IMAPSession::IMAPSession()
+{
+ init();
+}
+
+IMAPSession::~IMAPSession()
+{
+ MC_SAFE_RELEASE(mHostname);
+ MC_SAFE_RELEASE(mUsername);
+ MC_SAFE_RELEASE(mPassword);
+ MC_SAFE_RELEASE(mWelcomeString);
+ MC_SAFE_RELEASE(mDefaultNamespace);
+ MC_SAFE_RELEASE(mCurrentFolder);
+ pthread_mutex_destroy(&mIdleLock);
+}
+
+#if 0
+String * IMAPSession::className()
+{
+ return MCSTR("IMAPSession");
+}
+#endif
+
+void IMAPSession::setHostname(String * hostname)
+{
+ MC_SAFE_REPLACE_COPY(String, mHostname, hostname);
+}
+
+String * IMAPSession::hostname()
+{
+ return mHostname;
+}
+
+void IMAPSession::setPort(unsigned int port)
+{
+ mPort = port;
+}
+
+unsigned int IMAPSession::port()
+{
+ return mPort;
+}
+
+void IMAPSession::setUsername(String * username)
+{
+ MC_SAFE_REPLACE_COPY(String, mUsername, username);
+}
+
+String * IMAPSession::username()
+{
+ return mUsername;
+}
+
+void IMAPSession::setPassword(String * password)
+{
+ MC_SAFE_REPLACE_COPY(String, mPassword, password);
+}
+
+String * IMAPSession::password()
+{
+ return mPassword;
+}
+
+void IMAPSession::setAuthType(AuthType authType)
+{
+ mAuthType = authType;
+}
+
+AuthType IMAPSession::authType()
+{
+ return mAuthType;
+}
+
+void IMAPSession::setConnectionType(ConnectionType connectionType)
+{
+ mConnectionType = connectionType;
+}
+
+ConnectionType IMAPSession::connectionType()
+{
+ return mConnectionType;
+}
+
+void IMAPSession::setTimeout(time_t timeout)
+{
+ mTimeout = timeout;
+}
+
+time_t IMAPSession::timeout()
+{
+ return mTimeout;
+}
+
+void IMAPSession::setCheckCertificateEnabled(bool enabled)
+{
+ mCheckCertificateEnabled = enabled;
+}
+
+bool IMAPSession::isCheckCertificateEnabled()
+{
+ return mCheckCertificateEnabled;
+}
+
+void IMAPSession::setVoIPEnabled(bool enabled)
+{
+ mVoIPEnabled = enabled;
+}
+
+bool IMAPSession::isVoIPEnabled()
+{
+ return mVoIPEnabled;
+}
+
+
+void IMAPSession::setDelimiter(char delimiter)
+{
+ mDelimiter = delimiter;
+}
+
+char IMAPSession::delimiter()
+{
+ return mDelimiter;
+}
+
+static bool hasError(int errorCode)
+{
+ return ((errorCode != MAILIMAP_NO_ERROR) && (errorCode != MAILIMAP_NO_ERROR_AUTHENTICATED) &&
+ (errorCode != MAILIMAP_NO_ERROR_NON_AUTHENTICATED));
+}
+
+bool IMAPSession::checkCertificate()
+{
+ // XXX
+ return true;
+}
+
+void IMAPSession::body_progress(size_t current, size_t maximum, void * context)
+{
+ IMAPSession * session;
+
+ session = (IMAPSession *) context;
+ session->bodyProgress((unsigned int) current, (unsigned int) maximum);
+}
+
+void IMAPSession::items_progress(size_t current, size_t maximum, void * context)
+{
+ IMAPSession * session;
+
+ session = (IMAPSession *) context;
+ session->itemsProgress((unsigned int) current, (unsigned int) maximum);
+}
+
+void IMAPSession::setup()
+{
+ MCAssert(mImap == NULL);
+
+ mImap = mailimap_new(0, NULL);
+ mailimap_set_timeout(mImap, timeout());
+ mailimap_set_progress_callback(mImap, body_progress, IMAPSession::items_progress, this);
+}
+
+void IMAPSession::unsetup()
+{
+ mailimap * imap;
+
+ imap = mImap;
+ mImap = NULL;
+
+ if (imap != NULL) {
+ if (imap->imap_stream != NULL) {
+ mailstream_close(imap->imap_stream);
+ imap->imap_stream = NULL;
+ }
+ mailimap_free(imap);
+ imap = NULL;
+ }
+}
+
+void IMAPSession::connect(ErrorCode * pError)
+{
+ int r;
+
+ setup();
+
+ MCLog("connect %s", MCUTF8DESC(this));
+
+ MCAssert(mState == STATE_DISCONNECTED);
+
+ switch (mConnectionType) {
+ case ConnectionTypeStartTLS:
+ MCLog("STARTTLS connect");
+ r = mailimap_socket_connect_voip(mImap, MCUTF8(mHostname), mPort, isVoIPEnabled());
+ if (hasError(r)) {
+ * pError = ErrorConnection;
+ return;
+ }
+
+ r = mailimap_socket_starttls(mImap);
+ if (hasError(r)) {
+ MCLog("no TLS %i", r);
+ * pError = ErrorTLSNotAvailable;
+ return;
+ }
+ break;
+
+ case ConnectionTypeTLS:
+ r = mailimap_ssl_connect_voip(mImap, MCUTF8(mHostname), mPort, isVoIPEnabled());
+ MCLog("ssl connect %s %u %u", MCUTF8(mHostname), mPort, r);
+ if (hasError(r)) {
+ MCLog("connect error %i", r);
+ * pError = ErrorConnection;
+ return;
+ }
+ if (!checkCertificate()) {
+ MCLog("ssl connect certificate ERROR %d", r);
+ * pError = ErrorCertificate;
+ return;
+ }
+
+ break;
+
+ default:
+ MCLog("socket connect %s %u", MCUTF8(mHostname), mPort);
+ r = mailimap_socket_connect_voip(mImap, MCUTF8(mHostname), mPort, isVoIPEnabled());
+ MCLog("socket connect %i", r);
+ if (hasError(r)) {
+ MCLog("connect error %i", r);
+ * pError = ErrorConnection;
+ return;
+ }
+ break;
+ }
+
+ mailstream_low * low;
+ String * identifierString;
+ char * identifier;
+
+ low = mailstream_get_low(mImap->imap_stream);
+ identifierString = String::stringWithUTF8Format("%s@%s:%u", MCUTF8(mUsername), MCUTF8(mHostname), mPort);
+ identifier = strdup(identifierString->UTF8Characters());
+ mailstream_low_set_identifier(low, identifier);
+
+ if (mImap->imap_response != NULL) {
+ MC_SAFE_REPLACE_RETAIN(String, mWelcomeString, String::stringWithUTF8Characters(mImap->imap_response));
+ }
+
+ * pError = ErrorNone;
+ mState = STATE_CONNECTED;
+ MCLog("connect ok");
+}
+
+void IMAPSession::connectIfNeeded(ErrorCode * pError)
+{
+ if (mState == STATE_DISCONNECTED) {
+ connect(pError);
+ }
+ else {
+ * pError = ErrorNone;
+ }
+}
+
+void IMAPSession::loginIfNeeded(ErrorCode * pError)
+{
+ connectIfNeeded(pError);
+ if (* pError != ErrorNone)
+ return;
+
+ if (mState == STATE_CONNECTED) {
+ login(pError);
+ }
+ else {
+ * pError = ErrorNone;
+ }
+}
+
+void IMAPSession::login(ErrorCode * pError)
+{
+ int r;
+
+ MCLog("login");
+
+ MCAssert(mState == STATE_CONNECTED);
+
+ const char* utf8username;
+ const char* utf8password;
+ utf8username = MCUTF8(mUsername);
+ utf8password = MCUTF8(mPassword);
+ if (utf8username == NULL) {
+ utf8username = "";
+ }
+ if (utf8password == NULL) {
+ utf8password = "";
+ }
+
+ switch (mAuthType) {
+ case 0:
+ default:
+ r = mailimap_login(mImap, utf8username, utf8password);
+ break;
+
+ case AuthTypeSASLCRAMMD5:
+ r = mailimap_authenticate(mImap, "CRAM-MD5",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ utf8username, utf8username,
+ utf8password, NULL);
+ break;
+
+ case AuthTypeSASLPlain:
+ r = mailimap_authenticate(mImap, "PLAIN",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ utf8username, utf8username,
+ utf8password, NULL);
+ break;
+
+ case AuthTypeSASLGSSAPI:
+ // needs to be tested
+ r = mailimap_authenticate(mImap, "GSSAPI",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ utf8username, utf8username,
+ utf8password, NULL /* realm */);
+ break;
+
+ case AuthTypeSASLDIGESTMD5:
+ r = mailimap_authenticate(mImap, "DIGEST-MD5",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ utf8username, utf8username,
+ utf8password, NULL);
+ break;
+
+ case AuthTypeSASLLogin:
+ r = mailimap_authenticate(mImap, "LOGIN",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ utf8username, utf8username,
+ utf8password, NULL);
+ break;
+
+ case AuthTypeSASLSRP:
+ r = mailimap_authenticate(mImap, "SRP",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ utf8username, utf8username,
+ utf8password, NULL);
+ break;
+
+ case AuthTypeSASLNTLM:
+ r = mailimap_authenticate(mImap, "NTLM",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ utf8username, utf8username,
+ utf8password, NULL/* realm */);
+ break;
+
+ case AuthTypeSASLKerberosV4:
+ r = mailimap_authenticate(mImap, "KERBEROS_V4",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ utf8username, utf8username,
+ utf8password, NULL/* realm */);
+ break;
+ }
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return;
+ }
+ else if (hasError(r)) {
+ String * response;
+
+ response = MCSTR("");
+ if (mImap->imap_response != NULL) {
+ response = String::stringWithUTF8Characters(mImap->imap_response);
+ }
+ if (response->locationOfString(MCSTR("not enabled for IMAP use")) != -1) {
+ * pError = ErrorGmailIMAPNotEnabled;
+ }
+ else if (response->locationOfString(MCSTR("bandwidth limits")) != -1) {
+ * pError = ErrorGmailExceededBandwidthLimit;
+ }
+ else if (response->locationOfString(MCSTR("Too many simultaneous connections")) != -1) {
+ * pError = ErrorGmailTooManySimultaneousConnections;
+ }
+ else if (response->locationOfString(MCSTR("Maximum number of connections")) != -1) {
+ * pError = ErrorGmailTooManySimultaneousConnections;
+ }
+ else if (response->locationOfString(MCSTR("http://me.com/move")) != -1) {
+ * pError = ErrorMobileMeMoved;
+ }
+ else if (response->locationOfString(MCSTR("OCF12")) != -1) {
+ * pError = ErrorYahooUnavailable;
+ }
+ else {
+ * pError = ErrorAuthentication;
+ }
+ return;
+ }
+
+ * pError = ErrorNone;
+ mState = STATE_LOGGEDIN;
+ MCLog("login ok");
+}
+
+void IMAPSession::selectIfNeeded(String * folder, ErrorCode * pError)
+{
+ loginIfNeeded(pError);
+ if (* pError != ErrorNone)
+ return;
+
+ if (mState == STATE_LOGGEDIN) {
+ select(folder, pError);
+ }
+ else {
+ * pError = ErrorNone;
+ }
+}
+
+void IMAPSession::select(String * folder, ErrorCode * pError)
+{
+ int r;
+
+ MCLog("select");
+ MCAssert(mState == STATE_LOGGEDIN || mState == STATE_SELECTED);
+
+ r = mailimap_select(mImap, MCUTF8(folder));
+ MCLog("select error : %i", r);
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ MCLog("select error : %s %i", MCUTF8DESC(this), * pError);
+ return;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorNonExistantFolder;
+ MC_SAFE_RELEASE(mCurrentFolder);
+ return;
+ }
+
+ MC_SAFE_REPLACE_COPY(String, mCurrentFolder, folder);
+
+ if (mImap->imap_selection_info != NULL) {
+ mUIDValidity = mImap->imap_selection_info->sel_uidvalidity;
+ mUIDNext = mImap->imap_selection_info->sel_uidnext;
+ if (mImap->imap_selection_info->sel_has_exists) {
+ mFolderMsgCount = (unsigned int) (mImap->imap_selection_info->sel_exists);
+ } else {
+ mFolderMsgCount = -1;
+ }
+ }
+
+ mState = STATE_SELECTED;
+ * pError = ErrorNone;
+ MCLog("select ok");
+}
+
+#pragma mark mailbox flags conversion
+
+static struct {
+ const char * name;
+ int flag;
+} mb_keyword_flag[] = {
+ {"Inbox", IMAPFolderFlagInbox},
+ {"AllMail", IMAPFolderFlagAllMail},
+ {"Sent", IMAPFolderFlagSentMail},
+ {"Spam", IMAPFolderFlagSpam},
+ {"Starred", IMAPFolderFlagStarred},
+ {"Trash", IMAPFolderFlagTrash},
+ {"Important", IMAPFolderFlagImportant},
+ {"Drafts", IMAPFolderFlagDrafts},
+ {"Archive", IMAPFolderFlagArchive},
+};
+
+static int imap_mailbox_flags_to_flags(struct mailimap_mbx_list_flags * imap_flags)
+{
+ int flags;
+ clistiter * cur;
+
+ flags = 0;
+ if (imap_flags->mbf_type == MAILIMAP_MBX_LIST_FLAGS_SFLAG) {
+ switch (imap_flags->mbf_sflag) {
+ case MAILIMAP_MBX_LIST_SFLAG_MARKED:
+ flags |= IMAPFolderFlagMarked;
+ break;
+ case MAILIMAP_MBX_LIST_SFLAG_NOSELECT:
+ flags |= IMAPFolderFlagNoSelect;
+ break;
+ case MAILIMAP_MBX_LIST_SFLAG_UNMARKED:
+ flags |= IMAPFolderFlagUnmarked;
+ break;
+ }
+ }
+
+ for(cur = clist_begin(imap_flags->mbf_oflags) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimap_mbx_list_oflag * oflag;
+
+ oflag = (struct mailimap_mbx_list_oflag *) clist_content(cur);
+
+ switch (oflag->of_type) {
+ case MAILIMAP_MBX_LIST_OFLAG_NOINFERIORS:
+ flags |= IMAPFolderFlagNoInferiors;
+ break;
+
+ case MAILIMAP_MBX_LIST_OFLAG_FLAG_EXT:
+ for(unsigned int i = 0 ; i < sizeof(mb_keyword_flag) / sizeof(mb_keyword_flag[0]) ; i ++) {
+ if (strcasecmp(mb_keyword_flag[i].name, oflag->of_flag_ext) == 0) {
+ flags |= mb_keyword_flag[i].flag;
+ }
+ }
+ break;
+ }
+ }
+
+ return flags;
+}
+
+static Array * resultsWithError(int r, clist * list, ErrorCode * pError)
+{
+ clistiter * cur;
+ Array * result;
+
+ result = Array::array();
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return NULL;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return NULL;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorNonExistantFolder;
+ return NULL;
+ }
+
+ for(cur = clist_begin(list) ; cur != NULL ; cur = cur->next) {
+ struct mailimap_mailbox_list * mb_list;
+ IMAPFolderFlag flags;
+ IMAPFolder * folder;
+ String * path;
+
+ mb_list = (struct mailimap_mailbox_list *) cur->data;
+
+ flags = IMAPFolderFlagNone;
+ if (mb_list->mb_flag != NULL)
+ flags = (IMAPFolderFlag) imap_mailbox_flags_to_flags(mb_list->mb_flag);
+
+ folder = new IMAPFolder();
+ path = String::stringWithUTF8Characters(mb_list->mb_name);
+ if (path->uppercaseString()->isEqual(MCSTR("INBOX"))) {
+ folder->setPath(MCSTR("INBOX"));
+ }
+ else {
+ folder->setPath(path);
+ }
+ folder->setDelimiter(mb_list->mb_delimiter);
+ folder->setFlags(flags);
+
+ result->addObject(folder);
+
+ folder->release();
+ }
+
+ mailimap_list_result_free(list);
+
+ * pError = ErrorNone;
+ return result;
+}
+
+char IMAPSession::fetchDelimiterIfNeeded(char defaultDelimiter, ErrorCode * pError)
+{
+ int r;
+ clist * imap_folders;
+ IMAPFolder * folder;
+ Array * folders;
+
+ if (defaultDelimiter != 0)
+ return defaultDelimiter;
+
+ r = mailimap_list(mImap, "", "", &imap_folders);
+ folders = resultsWithError(r, imap_folders, pError);
+ if (* pError != ErrorNone)
+ return 0;
+
+ if (folders->count() > 0) {
+ folder = (IMAPFolder *) folders->objectAtIndex(0);
+ }
+ else {
+ folder = NULL;
+ }
+ if (folder == NULL)
+ return 0;
+
+ * pError = ErrorNone;
+ return folder->delimiter();
+}
+
+Array * /* IMAPFolder */ IMAPSession::fetchSubscribedFolders(ErrorCode * pError)
+{
+ int r;
+ clist * imap_folders;
+ char delimiter;
+
+ MCLog("fetch subscribed");
+ loginIfNeeded(pError);
+ if (* pError != ErrorNone)
+ return NULL;
+
+ delimiter = fetchDelimiterIfNeeded(mDelimiter, pError);
+ if (* pError != ErrorNone)
+ return NULL;
+
+ setDelimiter(delimiter);
+
+ String * prefix;
+ prefix = defaultNamespace()->mainPrefix();
+ if (prefix == NULL) {
+ prefix = MCSTR("");
+ }
+ if (prefix->length() > 0) {
+ if (!prefix->hasSuffix(String::stringWithUTF8Format("%c", delimiter))) {
+ prefix = prefix->stringByAppendingUTF8Format("%c", delimiter);
+ }
+ }
+
+ r = mailimap_lsub(mImap, MCUTF8(prefix), "*", &imap_folders);
+ MCLog("fetch subscribed %u", r);
+ return resultsWithError(r, imap_folders, pError);
+}
+
+Array * /* IMAPFolder */ IMAPSession::fetchAllFolders(ErrorCode * pError)
+{
+ int r;
+ clist * imap_folders;
+ char delimiter;
+
+ loginIfNeeded(pError);
+ if (* pError != ErrorNone)
+ return NULL;
+
+ delimiter = fetchDelimiterIfNeeded(mDelimiter, pError);
+ if (* pError != ErrorNone)
+ return NULL;
+
+ setDelimiter(delimiter);
+
+ String * prefix;
+ prefix = defaultNamespace()->mainPrefix();
+ if (prefix == NULL) {
+ prefix = MCSTR("");
+ }
+ if (prefix->length() > 0) {
+ if (!prefix->hasSuffix(String::stringWithUTF8Format("%c", delimiter))) {
+ prefix = prefix->stringByAppendingUTF8Format("%c", delimiter);
+ }
+ }
+
+ if (mXListEnabled) {
+ r = mailimap_xlist(mImap, MCUTF8(prefix), "*", &imap_folders);
+ }
+ else {
+ r = mailimap_list(mImap, MCUTF8(prefix), "*", &imap_folders);
+ }
+ return resultsWithError(r, imap_folders, pError);
+}
+
+void IMAPSession::renameFolder(String * folder, String * otherName, ErrorCode * pError)
+{
+ int r;
+
+ selectIfNeeded(MCSTR("INBOX"), pError);
+ if (* pError != ErrorNone)
+ return;
+
+ r = mailimap_rename(mImap, MCUTF8(folder), MCUTF8(otherName));
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorRename;
+ return;
+ }
+ * pError = ErrorNone;
+}
+
+void IMAPSession::deleteFolder(String * folder, ErrorCode * pError)
+{
+ int r;
+
+ selectIfNeeded(MCSTR("INBOX"), pError);
+ if (* pError != ErrorNone)
+ return;
+
+ r = mailimap_delete(mImap, MCUTF8(folder));
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorDelete;
+ return;
+ }
+ * pError = ErrorNone;
+}
+
+void IMAPSession::createFolder(String * folder, ErrorCode * pError)
+{
+ int r;
+
+ selectIfNeeded(MCSTR("INBOX"), pError);
+ if (* pError != ErrorNone)
+ return;
+
+ r = mailimap_create(mImap, MCUTF8(folder));
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorCreate;
+ return;
+ }
+
+ * pError = ErrorNone;
+ subscribeFolder(folder, pError);
+}
+
+void IMAPSession::subscribeFolder(String * folder, ErrorCode * pError)
+{
+ int r;
+
+ selectIfNeeded(MCSTR("INBOX"), pError);
+ if (* pError != ErrorNone)
+ return;
+
+ r = mailimap_subscribe(mImap, MCUTF8(folder));
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorSubscribe;
+ return;
+ }
+ * pError = ErrorNone;
+}
+
+void IMAPSession::unsubscribeFolder(String * folder, ErrorCode * pError)
+{
+ int r;
+
+ selectIfNeeded(MCSTR("INBOX"), pError);
+ if (* pError != ErrorNone)
+ return;
+
+ r = mailimap_unsubscribe(mImap, MCUTF8(folder));
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorSubscribe;
+ return;
+ }
+ * pError = ErrorNone;
+}
+
+void IMAPSession::appendMessage(String * folder, Data * messageData, MessageFlag flags,
+ IMAPProgressCallback * progressCallback, uint32_t * createdUID, ErrorCode * pError)
+{
+ int r;
+ struct mailimap_flag_list * flag_list;
+ uint32_t uidvalidity;
+ uint32_t uidresult;
+
+ selectIfNeeded(folder, pError);
+ if (* pError != ErrorNone)
+ return;
+
+ mProgressCallback = progressCallback;
+ bodyProgress(0, messageData->length());
+
+ flag_list = NULL;
+ flag_list = flags_to_lep(flags);
+ r = mailimap_uidplus_append(mImap, MCUTF8(folder), flag_list, NULL, messageData->bytes(), messageData->length(),
+ &uidvalidity, &uidresult);
+ mailimap_flag_list_free(flag_list);
+
+ bodyProgress(messageData->length(), messageData->length());
+ mProgressCallback = NULL;
+
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorAppend;
+ return;
+ }
+
+ * createdUID = uidresult;
+ * pError = ErrorNone;
+}
+
+void IMAPSession::copyMessages(String * folder, Array * uidSet, String * destFolder,
+ Array ** pDestUIDs, ErrorCode * pError)
+{
+ int r;
+ struct mailimap_set * set;
+ struct mailimap_set * src_uid;
+ struct mailimap_set * dest_uid;
+ uint32_t uidvalidity;
+ clist * setList;
+ Array * uidSetResult;
+
+ selectIfNeeded(folder, pError);
+ if (* pError != ErrorNone)
+ return;
+
+ set = setFromArray(uidSet);
+ if (clist_count(set->set_list) == 0) {
+ return;
+ }
+
+ setList = splitSet(set, 10);
+ uidSetResult = new Array();
+
+ for(clistiter * iter = clist_begin(setList) ; iter != NULL ; iter = clist_next(iter)) {
+ struct mailimap_set * current_set;
+
+ current_set = (struct mailimap_set *) clist_content(iter);
+
+ r = mailimap_uidplus_uid_copy(mImap, current_set, MCUTF8(destFolder),
+ &uidvalidity, &src_uid, &dest_uid);
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ goto release;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ goto release;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorCopy;
+ goto release;
+ }
+
+ if (src_uid != NULL) {
+ mailimap_set_free(src_uid);
+ }
+
+ if (dest_uid != NULL) {
+ uidSetResult->addObjectsFromArray(arrayFromSet(dest_uid));
+ mailimap_set_free(dest_uid);
+ }
+ }
+ * pDestUIDs = (Array *) uidSetResult->retain()->autorelease();
+ * pError = ErrorNone;
+
+ release:
+ MC_SAFE_RELEASE(uidSetResult);
+
+ for(clistiter * iter = clist_begin(setList) ; iter != NULL ; iter = clist_next(iter)) {
+ struct mailimap_set * current_set;
+
+ current_set = (struct mailimap_set *) clist_content(iter);
+ mailimap_set_free(current_set);
+ }
+ clist_free(setList);
+ mailimap_set_free(set);
+}
+
+void IMAPSession::expunge(String * folder, ErrorCode * pError)
+{
+ int r;
+
+ selectIfNeeded(folder, pError);
+ if (* pError != ErrorNone)
+ return;
+
+ r = mailimap_expunge(mImap);
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorExpunge;
+ return;
+ }
+ * pError = ErrorNone;
+}
+
+static int
+fetch_imap(mailimap * imap, uint32_t uid,
+ struct mailimap_fetch_type * fetch_type,
+ char ** result, size_t * result_len)
+{
+ int r;
+ struct mailimap_msg_att * msg_att;
+ struct mailimap_msg_att_item * msg_att_item;
+ clist * fetch_result;
+ struct mailimap_set * set;
+ char * text;
+ size_t text_length;
+ clistiter * cur;
+
+ set = mailimap_set_new_single(uid);
+ r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
+
+ mailimap_set_free(set);
+
+ switch (r) {
+ case MAILIMAP_NO_ERROR:
+ break;
+ default:
+ return r;
+ }
+
+ if (clist_begin(fetch_result) == NULL) {
+ mailimap_fetch_list_free(fetch_result);
+ return MAILIMAP_ERROR_FETCH;
+ }
+
+ msg_att = (struct mailimap_msg_att *) clist_begin(fetch_result)->data;
+
+ text = NULL;
+ text_length = 0;
+
+ for(cur = clist_begin(msg_att->att_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ msg_att_item = (struct mailimap_msg_att_item *) clist_content(cur);
+
+ if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
+
+ if (msg_att_item->att_data.att_static->att_type ==
+ MAILIMAP_MSG_ATT_BODY_SECTION) {
+ text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
+ msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
+ text_length =
+ msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
+ }
+ }
+ }
+
+ mailimap_fetch_list_free(fetch_result);
+
+ if (text == NULL)
+ return MAILIMAP_ERROR_FETCH;
+
+ * result = text;
+ * result_len = text_length;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+HashMap * IMAPSession::fetchMessageNumberUIDMapping(String * folder, uint32_t fromUID, uint32_t toUID,
+ ErrorCode * pError)
+{
+ struct mailimap_set * imap_set;
+ struct mailimap_fetch_type * fetch_type;
+ clist * fetch_result;
+ HashMap * result;
+ struct mailimap_fetch_att * fetch_att;
+ int r;
+ clistiter * iter;
+
+ selectIfNeeded(folder, pError);
+ if (* pError != ErrorNone)
+ return NULL;
+
+ result = HashMap::hashMap();
+
+ imap_set = mailimap_set_new_interval(fromUID, toUID);
+ fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
+ fetch_att = mailimap_fetch_att_new_uid();
+ mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
+
+ r = mailimap_uid_fetch(mImap, imap_set, fetch_type, &fetch_result);
+ mailimap_fetch_type_free(fetch_type);
+ mailimap_set_free(imap_set);
+
+ if (r == MAILIMAP_ERROR_STREAM) {
+ MCLog("error stream");
+ * pError = ErrorConnection;
+ return NULL;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ MCLog("error parse");
+ * pError = ErrorParse;
+ return NULL;
+ }
+ else if (hasError(r)) {
+ MCLog("error fetch");
+ * pError = ErrorFetch;
+ return NULL;
+ }
+
+ for(iter = clist_begin(fetch_result) ; iter != NULL ; iter = clist_next(iter)) {
+ struct mailimap_msg_att * msg_att;
+ clistiter * item_iter;
+ uint32_t uid;
+
+ msg_att = (struct mailimap_msg_att *) clist_content(iter);
+ uid = 0;
+ for(item_iter = clist_begin(msg_att->att_list) ; item_iter != NULL ; item_iter = clist_next(item_iter)) {
+ struct mailimap_msg_att_item * att_item;
+
+ att_item = (struct mailimap_msg_att_item *) clist_content(item_iter);
+ if (att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
+ struct mailimap_msg_att_static * att_static;
+
+ att_static = att_item->att_data.att_static;
+ if (att_static->att_type == MAILIMAP_MSG_ATT_UID) {
+ uid = att_static->att_data.att_uid;
+ }
+ }
+ }
+
+ if (uid < fromUID) {
+ uid = 0;
+ }
+
+ if (uid != 0) {
+ result->setObjectForKey(Value::valueWithUnsignedLongValue(msg_att->att_number),
+ Value::valueWithUnsignedLongValue(uid));
+ }
+ }
+
+ mailimap_fetch_list_free(fetch_result);
+ * pError = ErrorNone;
+
+ return result;
+}
+
+struct msg_att_handler_data {
+ IMAPSession * self;
+ bool fetchByUID;
+ Array * result;
+ String * folder;
+ IMAPMessagesRequestKind requestKind;
+ uint32_t mLastFetchedSequenceNumber;
+ HashMap * mapping;
+ bool needsHeader;
+ bool needsBody;
+ bool needsFlags;
+ bool needsGmailLabels;
+ uint32_t startUid;
+};
+
+static void msg_att_handler(struct mailimap_msg_att * msg_att, void * context)
+{
+ clistiter * item_iter;
+ uint32_t uid;
+ IMAPMessage * msg;
+ bool hasHeader;
+ bool hasBody;
+ bool hasFlags;
+ bool hasGmailLabels;
+ struct msg_att_handler_data * msg_att_context;
+ // struct
+ IMAPSession * self;
+ bool fetchByUID;
+ Array * result;
+ String * folder;
+ IMAPMessagesRequestKind requestKind;
+ uint32_t mLastFetchedSequenceNumber;
+ HashMap * mapping;
+ bool needsHeader;
+ bool needsBody;
+ bool needsFlags;
+ bool needsGmailLabels;
+ uint32_t startUid;
+
+ msg_att_context = (struct msg_att_handler_data *) context;
+ self = msg_att_context->self;
+ fetchByUID = msg_att_context->fetchByUID;
+ result = msg_att_context->result;
+ folder = msg_att_context->folder;
+ requestKind = msg_att_context->requestKind;
+ mLastFetchedSequenceNumber = msg_att_context->mLastFetchedSequenceNumber;
+ mapping = msg_att_context->mapping;
+ needsHeader = msg_att_context->needsHeader;
+ needsBody = msg_att_context->needsBody;
+ needsFlags = msg_att_context->needsFlags;
+ needsGmailLabels = msg_att_context->needsGmailLabels;
+ startUid = msg_att_context->startUid;
+
+ hasHeader = false;
+ hasBody = false;
+ hasFlags = false;
+ hasGmailLabels = false;
+
+ msg = new IMAPMessage();
+
+ uid = 0;
+ mLastFetchedSequenceNumber = msg_att->att_number;
+ if (mapping != NULL) {
+ uid = (uint32_t) ((Value *) mapping->objectForKey(Value::valueWithUnsignedLongValue(msg_att->att_number)))->longLongValue();
+ }
+ for(item_iter = clist_begin(msg_att->att_list) ; item_iter != NULL ; item_iter = clist_next(item_iter)) {
+ struct mailimap_msg_att_item * att_item;
+
+ att_item = (struct mailimap_msg_att_item *) clist_content(item_iter);
+ if (att_item->att_type == MAILIMAP_MSG_ATT_ITEM_DYNAMIC) {
+ MessageFlag flags;
+
+ flags = flags_from_lep_att_dynamic(att_item->att_data.att_dyn);
+ msg->setFlags(flags);
+ msg->setOriginalFlags(flags);
+ hasFlags = true;
+ }
+ else if (att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
+ struct mailimap_msg_att_static * att_static;
+
+ att_static = att_item->att_data.att_static;
+ if (att_static->att_type == MAILIMAP_MSG_ATT_UID) {
+ uid = att_static->att_data.att_uid;
+ }
+ else if (att_static->att_type == MAILIMAP_MSG_ATT_ENVELOPE) {
+ struct mailimap_envelope * env;
+
+ MCLog("parse envelope %lu", (unsigned long) uid);
+ env = att_static->att_data.att_env;
+ msg->header()->importIMAPEnvelope(env);
+ hasHeader = true;
+ }
+ else if (att_static->att_type == MAILIMAP_MSG_ATT_BODY_SECTION) {
+ if ((requestKind & IMAPMessagesRequestKindFullHeaders) != 0) {
+ char * bytes;
+ size_t length;
+
+ bytes = att_static->att_data.att_body_section->sec_body_part;
+ length = att_static->att_data.att_body_section->sec_length;
+
+ msg->header()->importHeadersData(Data::dataWithBytes(bytes, (unsigned int) length));
+ hasHeader = true;
+ }
+ else {
+ char * references;
+ size_t ref_size;
+
+ // references
+ references = att_static->att_data.att_body_section->sec_body_part;
+ ref_size = att_static->att_data.att_body_section->sec_length;
+
+ msg->header()->importIMAPReferences(Data::dataWithBytes(references, (unsigned int) ref_size));
+ }
+ }
+ else if (att_static->att_type == MAILIMAP_MSG_ATT_BODYSTRUCTURE) {
+ AbstractPart * mainPart;
+
+ // bodystructure
+ mainPart = IMAPPart::attachmentWithIMAPBody(att_static->att_data.att_body);
+ msg->setMainPart(mainPart);
+ hasBody = true;
+ }
+ }
+ else if (att_item->att_type == MAILIMAP_MSG_ATT_ITEM_EXTENSION) {
+ struct mailimap_extension_data * ext_data;
+
+ ext_data = att_item->att_data.att_extension_data;
+ if (ext_data->ext_extension == &mailimap_extension_xgmlabels) {
+ struct mailimap_msg_att_xgmlabels * cLabels;
+ Array * labels;
+ clistiter * cur;
+
+ labels = new Array();
+ hasGmailLabels = true;
+ cLabels = (struct mailimap_msg_att_xgmlabels *) ext_data->ext_data;
+ for(cur = clist_begin(cLabels->att_labels) ; cur != NULL ; cur = clist_next(cur)) {
+ char * cLabel;
+ String * label;
+
+ cLabel = (char *) clist_content(cur);
+ label = String::stringWithUTF8Characters(cLabel);
+ labels->addObject(label);
+ }
+ if (labels->count() > 0) {
+ msg->setGmailLabels(labels);
+ }
+ labels->release();
+ }
+ }
+ }
+ for(item_iter = clist_begin(msg_att->att_list) ; item_iter != NULL ; item_iter = clist_next(item_iter)) {
+ struct mailimap_msg_att_item * att_item;
+
+ att_item = (struct mailimap_msg_att_item *) clist_content(item_iter);
+ if (att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
+ struct mailimap_msg_att_static * att_static;
+
+ att_static = att_item->att_data.att_static;
+ if (att_static->att_type == MAILIMAP_MSG_ATT_INTERNALDATE) {
+ msg->header()->importIMAPInternalDate(att_static->att_data.att_internal_date);
+ }
+ }
+ }
+
+ if (fetchByUID) {
+ if (uid < startUid) {
+ uid = 0;
+ }
+ }
+
+ if (needsBody && !hasBody) {
+ msg->release();
+ return;
+ }
+ if (needsHeader && !hasHeader) {
+ msg->release();
+ return;
+ }
+ if (needsFlags && !hasFlags) {
+ msg->release();
+ return;
+ }
+
+ if (uid != 0) {
+ msg->setUid(uid);
+ }
+ else {
+ msg->release();
+ return;
+ }
+
+ result->addObject(msg);
+ msg->release();
+
+ msg_att_context->mLastFetchedSequenceNumber = mLastFetchedSequenceNumber;
+}
+
+Array * IMAPSession::fetchMessages(String * folder, IMAPMessagesRequestKind requestKind, bool fetchByUID,
+ struct mailimap_set * imapset, HashMap * mapping, uint32_t startUid,
+ IMAPProgressCallback * progressCallback, ErrorCode * pError)
+{
+ struct mailimap_fetch_type * fetch_type;
+ clist * fetch_result;
+ Array * result;
+ struct mailimap_fetch_att * fetch_att;
+ int r;
+ bool needsHeader;
+ bool needsBody;
+ bool needsFlags;
+ bool needsGmailLabels;
+
+ selectIfNeeded(folder, pError);
+ if (* pError != ErrorNone)
+ return NULL;
+
+ if (mNeedsMboxMailWorkaround) {
+ requestKind = (IMAPMessagesRequestKind) (requestKind & ~IMAPMessagesRequestKindHeaders);
+ requestKind = (IMAPMessagesRequestKind) (requestKind | IMAPMessagesRequestKindFullHeaders);
+ }
+
+ if ((requestKind & IMAPMessagesRequestKindHeaders) != 0) {
+ mProgressItemsCount = 0;
+ mProgressCallback = progressCallback;
+ }
+
+ result = Array::array();
+
+ needsHeader = false;
+ needsBody = false;
+ needsFlags = false;
+ needsGmailLabels = false;
+
+ fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
+ fetch_att = mailimap_fetch_att_new_uid();
+ mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
+ if ((requestKind & IMAPMessagesRequestKindFlags) != 0) {
+ MCLog("request flags");
+ fetch_att = mailimap_fetch_att_new_flags();
+ mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
+ needsFlags = true;
+ }
+ if ((requestKind & IMAPMessagesRequestKindGmailLabels) != 0) {
+ MCLog("request flags");
+ fetch_att = mailimap_fetch_att_new_xgmlabels();
+ mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
+ needsGmailLabels = true;
+ }
+ if ((requestKind & IMAPMessagesRequestKindFullHeaders) != 0) {
+ clist * hdrlist;
+ char * header;
+ struct mailimap_header_list * imap_hdrlist;
+ struct mailimap_section * section;
+
+ MCLog("request envelope");
+
+ // most important header
+ hdrlist = clist_new();
+ header = strdup("Date");
+ clist_append(hdrlist, header);
+ header = strdup("Subject");
+ clist_append(hdrlist, header);
+ header = strdup("From");
+ clist_append(hdrlist, header);
+ header = strdup("Sender");
+ clist_append(hdrlist, header);
+ header = strdup("Reply-To");
+ clist_append(hdrlist, header);
+ header = strdup("To");
+ clist_append(hdrlist, header);
+ header = strdup("Cc");
+ clist_append(hdrlist, header);
+ header = strdup("Message-ID");
+ clist_append(hdrlist, header);
+ header = strdup("References");
+ clist_append(hdrlist, header);
+ header = strdup("In-Reply-To");
+ clist_append(hdrlist, header);
+ imap_hdrlist = mailimap_header_list_new(hdrlist);
+ section = mailimap_section_new_header_fields(imap_hdrlist);
+ fetch_att = mailimap_fetch_att_new_body_peek_section(section);
+ mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
+ needsHeader = true;
+ }
+ if ((requestKind & IMAPMessagesRequestKindHeaders) != 0) {
+ clist * hdrlist;
+ char * header;
+ struct mailimap_header_list * imap_hdrlist;
+ struct mailimap_section * section;
+
+ MCLog("request envelope");
+ // envelope
+ fetch_att = mailimap_fetch_att_new_envelope();
+ mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
+
+ // references header
+ hdrlist = clist_new();
+ header = strdup("References");
+ clist_append(hdrlist, header);
+ if ((requestKind & IMAPMessagesRequestKindHeaderSubject) != 0) {
+ header = strdup("Subject");
+ clist_append(hdrlist, header);
+ }
+ imap_hdrlist = mailimap_header_list_new(hdrlist);
+ section = mailimap_section_new_header_fields(imap_hdrlist);
+ fetch_att = mailimap_fetch_att_new_body_peek_section(section);
+ mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
+ needsHeader = true;
+ }
+ if ((requestKind & IMAPMessagesRequestKindStructure) != 0) {
+ // message structure
+ MCLog("request bodystructure");
+ fetch_att = mailimap_fetch_att_new_bodystructure();
+ mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
+ needsBody = true;
+ }
+ if ((requestKind & IMAPMessagesRequestKindInternalDate) != 0) {
+ // internal date
+ fetch_att = mailimap_fetch_att_new_internaldate();
+ mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
+ }
+
+ struct msg_att_handler_data msg_att_data;
+
+ memset(&msg_att_data, 0, sizeof(msg_att_data));
+ msg_att_data.self = this;
+ msg_att_data.fetchByUID = fetchByUID;
+ msg_att_data.result = result;
+ msg_att_data.folder = folder;
+ msg_att_data.requestKind = requestKind;
+ msg_att_data.mLastFetchedSequenceNumber = mLastFetchedSequenceNumber;
+ msg_att_data.mapping = mapping;
+ msg_att_data.needsHeader = needsHeader;
+ msg_att_data.needsBody = needsBody;
+ msg_att_data.needsFlags = needsFlags;
+ msg_att_data.needsGmailLabels = needsGmailLabels;
+ msg_att_data.startUid = startUid;
+
+ mailimap_set_msg_att_handler(mImap, msg_att_handler, &msg_att_data);
+
+ if (fetchByUID) {
+ r = mailimap_uid_fetch(mImap, imapset, fetch_type, &fetch_result);
+ } else {
+ r = mailimap_fetch(mImap, imapset, fetch_type, &fetch_result);
+ }
+
+ mProgressCallback = NULL;
+
+ mLastFetchedSequenceNumber = msg_att_data.mLastFetchedSequenceNumber;
+
+ mailimap_fetch_type_free(fetch_type);
+
+ mailimap_set_msg_att_handler(mImap, NULL, NULL);
+
+ if (r == MAILIMAP_ERROR_STREAM) {
+ MCLog("error stream");
+ * pError = ErrorConnection;
+ return NULL;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ MCLog("error parse");
+ * pError = ErrorParse;
+ return NULL;
+ }
+ else if (hasError(r)) {
+ MCLog("error fetch");
+ * pError = ErrorFetch;
+ return NULL;
+ }
+
+ if ((requestKind & IMAPMessagesRequestKindHeaders) != 0) {
+ if (result->count() == 0) {
+ unsigned int count;
+
+ count = clist_count(fetch_result);
+ if (count > 0) {
+ requestKind = (IMAPMessagesRequestKind) (requestKind & ~IMAPMessagesRequestKindHeaders);
+ requestKind = (IMAPMessagesRequestKind) (requestKind | IMAPMessagesRequestKindFullHeaders);
+
+ result = fetchMessages(folder, requestKind, fetchByUID,
+ imapset, NULL, startUid, progressCallback, pError);
+ if (result->count() > 0) {
+ mNeedsMboxMailWorkaround = true;
+ }
+ }
+ }
+ }
+
+ mailimap_fetch_list_free(fetch_result);
+ * pError = ErrorNone;
+
+ return result;
+}
+
+Array * IMAPSession::fetchMessagesByUID(String * folder, IMAPMessagesRequestKind requestKind,
+ uint32_t firstUID, uint32_t lastUID, IMAPProgressCallback * progressCallback, ErrorCode * pError)
+{
+ struct mailimap_set * imapset = mailimap_set_new_interval(firstUID, lastUID);
+ Array * result = fetchMessages(folder, requestKind, true, imapset, NULL, firstUID,
+ progressCallback, pError);
+ mailimap_set_free(imapset);
+ return result;
+}
+
+Array * IMAPSession::fetchMessagesByUID(String * folder, IMAPMessagesRequestKind requestKind,
+ Array * uids, IMAPProgressCallback * progressCallback, ErrorCode * pError)
+{
+ struct mailimap_set * imapset = setFromArray(uids);
+ Array * result = fetchMessages(folder, requestKind, true, imapset, NULL,
+ (uint32_t) ((Value *) uids->objectAtIndex(0))->unsignedLongValue(),
+ progressCallback, pError);
+ mailimap_set_free(imapset);
+ return result;
+}
+
+Array * IMAPSession::fetchMessagesByNumber(String * folder, IMAPMessagesRequestKind requestKind,
+ uint32_t firstNumber, uint32_t lastNumber, IMAPProgressCallback * progressCallback, ErrorCode * pError)
+{
+ struct mailimap_set * imapset = mailimap_set_new_interval(firstNumber, lastNumber);
+ Array * result = fetchMessages(folder, requestKind, false, imapset, NULL, 0,
+ progressCallback, pError);
+ mailimap_set_free(imapset);
+ return result;
+}
+
+Array * IMAPSession::fetchMessagesByNumber(String * folder, IMAPMessagesRequestKind requestKind,
+ Array * numbers, IMAPProgressCallback * progressCallback, ErrorCode * pError)
+{
+ struct mailimap_set * imapset = setFromArray(numbers);
+ Array * result = fetchMessages(folder, requestKind, false, imapset, NULL, 0,
+ progressCallback, pError);
+ mailimap_set_free(imapset);
+ return result;
+}
+
+static int fetch_rfc822(mailimap * session,
+ uint32_t msgid, char ** result)
+{
+ int r;
+ clist * fetch_list;
+ struct mailimap_section * section;
+ struct mailimap_fetch_att * fetch_att;
+ struct mailimap_fetch_type * fetch_type;
+ struct mailimap_set * set;
+ struct mailimap_msg_att * msg_att;
+ struct mailimap_msg_att_item * item;
+ int res;
+ clistiter * cur;
+
+ section = mailimap_section_new(NULL);
+ fetch_att = mailimap_fetch_att_new_body_peek_section(section);
+ fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
+
+ set = mailimap_set_new_single(msgid);
+
+ r = mailimap_uid_fetch(session, set, fetch_type, &fetch_list);
+
+ mailimap_set_free(set);
+ mailimap_fetch_type_free(fetch_type);
+
+ if (r != MAILIMAP_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ if (clist_isempty(fetch_list)) {
+ res = MAILIMAP_ERROR_FETCH;
+ goto free;
+ }
+
+ msg_att = (struct mailimap_msg_att *) clist_begin(fetch_list)->data;
+
+ for(cur = clist_begin(msg_att->att_list) ; cur != NULL ; cur = clist_next(cur)) {
+ item = (struct mailimap_msg_att_item *) clist_content(cur);
+
+ if (item->att_type != MAILIMAP_MSG_ATT_ITEM_STATIC) {
+ continue;
+ }
+ if (item->att_data.att_static->att_type != MAILIMAP_MSG_ATT_BODY_SECTION) {
+ continue;
+ }
+
+ * result = item->att_data.att_static->att_data.att_body_section->sec_body_part;
+ item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
+ mailimap_fetch_list_free(fetch_list);
+
+ return MAILIMAP_NO_ERROR;
+ }
+
+ res = MAILIMAP_ERROR_FETCH;
+
+free:
+ mailimap_fetch_list_free(fetch_list);
+err:
+ return res;
+}
+
+Data * IMAPSession::fetchMessageByUID(String * folder, uint32_t uid,
+ IMAPProgressCallback * progressCallback, ErrorCode * pError)
+{
+ char * rfc822;
+ int r;
+ Data * data;
+
+ selectIfNeeded(folder, pError);
+ if (* pError != ErrorNone)
+ return NULL;
+
+ mProgressItemsCount = 0;
+ mProgressCallback = progressCallback;
+
+ rfc822 = NULL;
+ r = fetch_rfc822(mImap, uid, &rfc822);
+ if (r == MAILIMAP_NO_ERROR) {
+ size_t len;
+
+ len = 0;
+ if (rfc822 != NULL) {
+ len = strlen(rfc822);
+ }
+ bodyProgress((unsigned int) len, (unsigned int) len);
+ }
+ mProgressCallback = NULL;
+
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return NULL;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return NULL;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorFetch;
+ return NULL;
+ }
+
+ if (rfc822 == NULL) {
+ data = Data::data();
+ }
+ else {
+ data = Data::dataWithBytes(rfc822, (unsigned int) strlen(rfc822));
+ }
+
+ mailimap_nstring_free(rfc822);
+ * pError = ErrorNone;
+
+ return data;
+}
+
+Data * IMAPSession::fetchMessageAttachmentByUID(String * folder, uint32_t uid, String * partID,
+ Encoding encoding, unsigned int expectedSize,
+ IMAPProgressCallback * progressCallback, ErrorCode * pError)
+{
+ struct mailimap_fetch_type * fetch_type;
+ struct mailimap_fetch_att * fetch_att;
+ struct mailimap_section * section;
+ struct mailimap_section_part * section_part;
+ clist * sec_list;
+ Array * partIDArray;
+ int r;
+ char * text;
+ size_t text_length;
+ Data * data;
+
+ selectIfNeeded(folder, pError);
+ if (* pError != ErrorNone)
+ return NULL;
+
+ mProgressItemsCount = 0;
+ mProgressCallback = progressCallback;
+ bodyProgress(0, expectedSize);
+
+ 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();
+ clist_append(sec_list, value);
+ }
+ 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);
+ fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
+
+ r = fetch_imap(mImap, uid, fetch_type, &text, &text_length);
+ mailimap_fetch_type_free(fetch_type);
+
+ bodyProgress(expectedSize, expectedSize);
+ mProgressCallback = NULL;
+
+ MCLog("had error : %i", r);
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return NULL;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return NULL;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorFetch;
+ return NULL;
+ }
+
+ data = Data::dataWithBytes(text, (unsigned int) text_length);
+ data = data->decodedDataUsingEncoding(encoding);
+
+ mailimap_nstring_free(text);
+ * pError = ErrorNone;
+
+ return data;
+}
+
+Array * IMAPSession::search(String * folder, IMAPSearchKind kind, String * searchString, ErrorCode * pError)
+{
+ IMAPSearchExpression * expr;
+
+ expr = NULL;
+ switch (kind) {
+ case IMAPSearchKindFrom:
+ expr = IMAPSearchExpression::searchFrom(searchString);
+ break;
+ case IMAPSearchKindRecipient:
+ expr = IMAPSearchExpression::searchRecipient(searchString);
+ break;
+ case IMAPSearchKindSubject:
+ expr = IMAPSearchExpression::searchSubject(searchString);
+ break;
+ case IMAPSearchKindContent:
+ expr = IMAPSearchExpression::searchContent(searchString);
+ break;
+ default:
+ MCAssert(0);
+ break;
+ }
+ return search(folder, expr, pError);
+}
+
+static struct mailimap_search_key * searchKeyFromSearchExpression(IMAPSearchExpression * expression)
+{
+ switch (expression->kind()) {
+ case IMAPSearchKindFrom:
+ {
+ return mailimap_search_key_new_from(strdup(expression->value()->UTF8Characters()));
+ }
+ case IMAPSearchKindRecipient:
+ {
+ struct mailimap_search_key * to_search;
+ struct mailimap_search_key * cc_search;
+ struct mailimap_search_key * bcc_search;
+ struct mailimap_search_key * or_search1;
+ struct mailimap_search_key * or_search2;
+
+ to_search = mailimap_search_key_new_to(strdup(expression->value()->UTF8Characters()));
+ cc_search = mailimap_search_key_new_cc(strdup(expression->value()->UTF8Characters()));
+ bcc_search = mailimap_search_key_new_bcc(strdup(expression->value()->UTF8Characters()));
+
+ or_search1 = mailimap_search_key_new_or(to_search, cc_search);
+ or_search2 = mailimap_search_key_new_or(or_search1, bcc_search);
+
+ return or_search2;
+ }
+ case IMAPSearchKindSubject:
+ {
+ return mailimap_search_key_new_subject(strdup(expression->value()->UTF8Characters()));
+ }
+ case IMAPSearchKindContent:
+ {
+ return mailimap_search_key_new_text(strdup(expression->value()->UTF8Characters()));
+ }
+ case IMAPSearchKindHeader:
+ {
+ return mailimap_search_key_new_header(strdup(expression->header()->UTF8Characters()), strdup(expression->value()->UTF8Characters()));
+ }
+ case IMAPSearchKindOr:
+ {
+ return mailimap_search_key_new_or(searchKeyFromSearchExpression(expression->leftExpression()), searchKeyFromSearchExpression(expression->rightExpression()));
+ }
+ case IMAPSearchKindAnd:
+ {
+ clist * list;
+ list = clist_new();
+ clist_append(list, searchKeyFromSearchExpression(expression->leftExpression()));
+ clist_append(list, searchKeyFromSearchExpression(expression->rightExpression()));
+ return mailimap_search_key_new_multiple(list);
+ }
+ default:
+ MCAssert(0);
+ return NULL;
+ }
+}
+
+Array * IMAPSession::search(String * folder, IMAPSearchExpression * expression, ErrorCode * pError)
+{
+ struct mailimap_search_key * key;
+
+ key = searchKeyFromSearchExpression(expression);
+ selectIfNeeded(folder, pError);
+ if (* pError != ErrorNone)
+ return NULL;
+
+ clist * result_list = NULL;
+
+ int r = mailimap_uid_search(mImap, "utf-8", key, &result_list);
+ mailimap_search_key_free(key);
+ MCLog("had error : %i", r);
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return NULL;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return NULL;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorFetch;
+ return NULL;
+ }
+
+ Array * result = Array::array();
+ for(clistiter * cur = clist_begin(result_list) ; cur != NULL ; cur = clist_next(cur)) {
+ uint32_t * uid = (uint32_t *) clist_content(cur);
+ result->addObject(Value::valueWithUnsignedLongValue(* uid));
+ }
+ mailimap_search_result_free(result_list);
+ * pError = ErrorNone;
+ return result;
+}
+
+void IMAPSession::setupIdle()
+{
+ // main thread
+ LOCK();
+ mailstream_setup_idle(mImap->imap_stream);
+ UNLOCK();
+}
+
+void IMAPSession::idle(String * folder, uint32_t lastKnownUID, ErrorCode * pError)
+{
+ int r;
+
+ // connection thread
+ selectIfNeeded(folder, pError);
+ if (* pError != ErrorNone)
+ return;
+
+ if (lastKnownUID != 0) {
+ Array * msgs;
+
+ msgs = fetchMessagesByUID(folder, IMAPMessagesRequestKindUid, lastKnownUID, 0,
+ NULL, pError);
+ if (* pError != ErrorNone)
+ return;
+ if (msgs->count() > 0) {
+ IMAPMessage * msg;
+
+ msg = (IMAPMessage *) msgs->objectAtIndex(0);
+ if (msg->uid() > lastKnownUID) {
+ MCLog("found msg UID %u %u", (unsigned int) msg->uid(), (unsigned int) lastKnownUID);
+ return;
+ }
+ }
+ }
+
+ r = mailimap_idle(mImap);
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorIdle;
+ return;
+ }
+
+ if (!mImap->imap_selection_info->sel_has_exists && !mImap->imap_selection_info->sel_has_recent) {
+ int r;
+ r = mailstream_wait_idle(mImap->imap_stream, MAX_IDLE_DELAY);
+ switch (r) {
+ case MAILSTREAM_IDLE_ERROR:
+ case MAILSTREAM_IDLE_CANCELLED:
+ {
+ * pError = ErrorConnection;
+ MCLog("error or cancelled");
+ return;
+ }
+ case MAILSTREAM_IDLE_INTERRUPTED:
+ MCLog("interrupted by user");
+ break;
+ case MAILSTREAM_IDLE_HASDATA:
+ MCLog("something on the socket");
+ break;
+ case MAILSTREAM_IDLE_TIMEOUT:
+ MCLog("idle timeout");
+ break;
+ }
+ }
+ else {
+ MCLog("found info before idling");
+ }
+
+ r = mailimap_idle_done(mImap);
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorIdle;
+ return;
+ }
+ * pError = ErrorNone;
+}
+
+void IMAPSession::interruptIdle()
+{
+ // main thread
+ LOCK();
+ mailstream_interrupt_idle(mImap->imap_stream);
+ UNLOCK();
+}
+
+void IMAPSession::unsetupIdle()
+{
+ // main thread
+ LOCK();
+ mailstream_unsetup_idle(mImap->imap_stream);
+ UNLOCK();
+}
+
+void IMAPSession::disconnect()
+{
+ unsetup();
+}
+
+HashMap * IMAPSession::identity(String * vendor, String * name, String * version, ErrorCode * pError)
+{
+ connectIfNeeded(pError);
+ if (* pError != ErrorNone)
+ return NULL;
+
+ struct mailimap_id_params_list * client_identification;
+ char * dup_name;
+ char * dup_value;
+
+ client_identification = mailimap_id_params_list_new_empty();
+
+ if (name != NULL) {
+ dup_name = strdup("name");
+ dup_value = strdup(name->UTF8Characters());
+ mailimap_id_params_list_add_name_value(client_identification, dup_name, dup_value);
+ }
+ if (version != NULL) {
+ dup_name = strdup("version");
+ dup_value = strdup(version->UTF8Characters());
+ mailimap_id_params_list_add_name_value(client_identification, dup_name, dup_value);
+ }
+ if (vendor != NULL) {
+ dup_name = strdup("vendor");
+ dup_value = strdup(vendor->UTF8Characters());
+ mailimap_id_params_list_add_name_value(client_identification, dup_name, dup_value);
+ }
+
+ int r;
+ struct mailimap_id_params_list * server_identification;
+ r = mailimap_id(mImap, client_identification, &server_identification);
+ mailimap_id_params_list_free(client_identification);
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return NULL;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return NULL;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorIdentity;
+ return NULL;
+ }
+
+ HashMap * result = HashMap::hashMap();
+
+ clistiter * cur;
+ for(cur = clist_begin(server_identification->idpa_list) ; cur != NULL ; cur = clist_next(cur)) {
+ struct mailimap_id_param * param;
+
+ param = (struct mailimap_id_param *) clist_content(cur);
+
+ String * responseKey;
+ String * responseValue;
+ responseKey = String::stringWithUTF8Characters(param->idpa_name);
+ responseValue = String::stringWithUTF8Characters(param->idpa_value);
+ result->setObjectForKey(responseKey, responseValue);
+ }
+
+ mailimap_id_params_list_free(server_identification);
+ * pError = ErrorNone;
+
+ return result;
+}
+
+void IMAPSession::bodyProgress(unsigned int current, unsigned int maximum)
+{
+ if (mProgressCallback != NULL) {
+ mProgressCallback->bodyProgress(this, current, maximum);
+ }
+}
+
+void IMAPSession::itemsProgress(unsigned int current, unsigned int maximum)
+{
+ if (mProgressCallback != NULL) {
+ mProgressCallback->itemsProgress(this, current, maximum);
+ }
+}
+
+IMAPNamespace * IMAPSession::defaultNamespace()
+{
+ return mDefaultNamespace;
+}
+
+void IMAPSession::setDefaultNamespace(IMAPNamespace * ns)
+{
+ MC_SAFE_REPLACE_RETAIN(IMAPNamespace, mDefaultNamespace, ns);
+}
+
+HashMap * IMAPSession::fetchNamespace(ErrorCode * pError)
+{
+ HashMap * result;
+ struct mailimap_namespace_data * namespace_data;
+ int r;
+
+ loginIfNeeded(pError);
+ if (* pError != ErrorNone)
+ return NULL;
+
+ result = HashMap::hashMap();
+ r = mailimap_namespace(mImap, &namespace_data);
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return NULL;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return NULL;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorNamespace;
+ return NULL;
+ }
+
+ IMAPNamespace * ns;
+
+ if (namespace_data->ns_personal != NULL) {
+ ns = new IMAPNamespace();
+ ns->importIMAPNamespace(namespace_data->ns_personal);
+ result->setObjectForKey(IMAPNamespacePersonal, ns);
+ ns->release();
+ }
+
+ if (namespace_data->ns_other != NULL) {
+ ns = new IMAPNamespace();
+ ns->importIMAPNamespace(namespace_data->ns_other);
+ result->setObjectForKey(IMAPNamespaceOther, ns);
+ ns->release();
+ }
+
+ if (namespace_data->ns_shared != NULL) {
+ ns = new IMAPNamespace();
+ ns->importIMAPNamespace(namespace_data->ns_shared);
+ result->setObjectForKey(IMAPNamespaceOther, ns);
+ ns->release();
+ }
+
+ mailimap_namespace_data_free(namespace_data);
+ * pError = ErrorNone;
+
+ return result;
+}
+
+void IMAPSession::storeFlags(String * folder, Array * uids, IMAPStoreFlagsRequestKind kind, MessageFlag flags, ErrorCode * pError)
+{
+ struct mailimap_set * imap_set;
+ struct mailimap_store_att_flags * store_att_flags;
+ struct mailimap_flag_list * flag_list;
+ int r;
+ clist * setList;
+
+ selectIfNeeded(folder, pError);
+ if (* pError != ErrorNone)
+ return;
+
+ imap_set = setFromArray(uids);
+ if (clist_count(imap_set->set_list) == 0) {
+ return;
+ }
+
+ setList = splitSet(imap_set, 10);
+
+ flag_list = mailimap_flag_list_new_empty();
+ if ((flags & MessageFlagSeen) != 0) {
+ struct mailimap_flag * f;
+
+ f = mailimap_flag_new_seen();
+ mailimap_flag_list_add(flag_list, f);
+ }
+ if ((flags & MessageFlagAnswered) != 0) {
+ struct mailimap_flag * f;
+
+ f = mailimap_flag_new_answered();
+ mailimap_flag_list_add(flag_list, f);
+ }
+ if ((flags & MessageFlagFlagged) != 0) {
+ struct mailimap_flag * f;
+
+ f = mailimap_flag_new_flagged();
+ mailimap_flag_list_add(flag_list, f);
+ }
+ if ((flags & MessageFlagDeleted) != 0) {
+ struct mailimap_flag * f;
+
+ f = mailimap_flag_new_deleted();
+ mailimap_flag_list_add(flag_list, f);
+ }
+ if ((flags & MessageFlagDraft) != 0) {
+ struct mailimap_flag * f;
+
+ f = mailimap_flag_new_draft();
+ mailimap_flag_list_add(flag_list, f);
+ }
+ if ((flags & MessageFlagMDNSent) != 0) {
+ struct mailimap_flag * f;
+
+ f = mailimap_flag_new_flag_keyword(strdup("$MDNSent"));
+ mailimap_flag_list_add(flag_list, f);
+ }
+ if ((flags & MessageFlagForwarded) != 0) {
+ struct mailimap_flag * f;
+
+ f = mailimap_flag_new_flag_keyword(strdup("$Forwarded"));
+ mailimap_flag_list_add(flag_list, f);
+ }
+ if ((flags & MessageFlagSubmitPending) != 0) {
+ struct mailimap_flag * f;
+
+ f = mailimap_flag_new_flag_keyword(strdup("$SubmitPending"));
+ mailimap_flag_list_add(flag_list, f);
+ }
+ if ((flags & MessageFlagSubmitted) != 0) {
+ struct mailimap_flag * f;
+
+ f = mailimap_flag_new_flag_keyword(strdup("$Submitted"));
+ mailimap_flag_list_add(flag_list, f);
+ }
+
+ store_att_flags = NULL;
+ for(clistiter * iter = clist_begin(setList) ; iter != NULL ; iter = clist_next(iter)) {
+ struct mailimap_set * current_set;
+
+ current_set = (struct mailimap_set *) clist_content(iter);
+
+ switch (kind) {
+ case IMAPStoreFlagsRequestKindRemove:
+ store_att_flags = mailimap_store_att_flags_new_remove_flags_silent(flag_list);
+ break;
+ case IMAPStoreFlagsRequestKindAdd:
+ store_att_flags = mailimap_store_att_flags_new_add_flags_silent(flag_list);
+ break;
+ case IMAPStoreFlagsRequestKindSet:
+ store_att_flags = mailimap_store_att_flags_new_set_flags_silent(flag_list);
+ break;
+ }
+ r = mailimap_uid_store(mImap, current_set, store_att_flags);
+
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ goto release;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorStore;
+ return;
+ }
+ }
+
+ release:
+ for(clistiter * iter = clist_begin(setList) ; iter != NULL ; iter = clist_next(iter)) {
+ struct mailimap_set * current_set;
+
+ current_set = (struct mailimap_set *) clist_content(iter);
+ mailimap_set_free(current_set);
+ }
+ clist_free(setList);
+ mailimap_store_att_flags_free(store_att_flags);
+ mailimap_set_free(imap_set);
+ * pError = ErrorNone;
+}
+
+void IMAPSession::storeLabels(String * folder, Array * uids, IMAPStoreFlagsRequestKind kind, Array * labels, ErrorCode * pError)
+{
+ struct mailimap_set * imap_set;
+ struct mailimap_msg_att_xgmlabels * xgmlabels;
+ int r;
+ clist * setList;
+
+ selectIfNeeded(folder, pError);
+ if (* pError != ErrorNone)
+ return;
+
+ imap_set = setFromArray(uids);
+ if (clist_count(imap_set->set_list) == 0) {
+ return;
+ }
+
+ setList = splitSet(imap_set, 10);
+
+ xgmlabels = mailimap_msg_att_xgmlabels_new_empty();
+ for(unsigned int i = 0 ; i < labels->count() ; i ++) {
+ String * label = (String *) labels->objectAtIndex(i);
+ mailimap_msg_att_xgmlabels_add(xgmlabels, strdup(label->UTF8Characters()));
+ }
+
+ for(clistiter * iter = clist_begin(setList) ; iter != NULL ; iter = clist_next(iter)) {
+ struct mailimap_set * current_set;
+ int fl_sign;
+
+ current_set = (struct mailimap_set *) clist_content(iter);
+
+ switch (kind) {
+ case IMAPStoreFlagsRequestKindRemove:
+ fl_sign = -1;
+ break;
+ case IMAPStoreFlagsRequestKindAdd:
+ fl_sign = 1;
+ break;
+ case IMAPStoreFlagsRequestKindSet:
+ fl_sign = 0;
+ break;
+ }
+ r = mailimap_uid_store_xgmlabels(mImap, current_set, fl_sign, 1, xgmlabels);
+ if (r == MAILIMAP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ goto release;
+ }
+ else if (r == MAILIMAP_ERROR_PARSE) {
+ * pError = ErrorParse;
+ return;
+ }
+ else if (hasError(r)) {
+ * pError = ErrorStore;
+ return;
+ }
+ }
+
+ release:
+ for(clistiter * iter = clist_begin(setList) ; iter != NULL ; iter = clist_next(iter)) {
+ struct mailimap_set * current_set;
+
+ current_set = (struct mailimap_set *) clist_content(iter);
+ mailimap_set_free(current_set);
+ }
+ clist_free(setList);
+ mailimap_msg_att_xgmlabels_free(xgmlabels);
+ mailimap_set_free(imap_set);
+ * pError = ErrorNone;
+}
diff --git a/src/core/imap/MCIMAPSession.h b/src/core/imap/MCIMAPSession.h
new file mode 100644
index 00000000..93058c2b
--- /dev/null
+++ b/src/core/imap/MCIMAPSession.h
@@ -0,0 +1,162 @@
+#ifndef __MAILCORE_MCIMAPSESSION_H
+
+#define __MAILCORE_MCIMAPSESSION_H
+
+#include <mailcore/MCBaseTypes.h>
+#include <mailcore/MCMessageConstants.h>
+#include <libetpan/libetpan.h>
+
+namespace mailcore {
+
+ extern String * IMAPNamespacePersonal;
+ extern String * IMAPNamespaceOther;
+ extern String * IMAPNamespaceShared;
+
+ class IMAPNamespace;
+ class IMAPSearchExpression;
+ class IMAPFolder;
+ class IMAPProgressCallback;
+
+ class IMAPSession : public Object {
+ private:
+ String * mHostname;
+ unsigned int mPort;
+ String * mUsername;
+ String * mPassword;
+ AuthType mAuthType;
+ ConnectionType mConnectionType;
+ bool mCheckCertificateEnabled;
+ bool mVoIPEnabled;
+ char mDelimiter;
+ IMAPNamespace * mDefaultNamespace;
+
+ bool mIdleEnabled;
+ bool mXListEnabled;
+ String * mWelcomeString;
+ bool mNeedsMboxMailWorkaround;
+ time_t mTimeout;
+ uint32_t mUIDValidity;
+ uint32_t mUIDNext;
+ unsigned int mFolderMsgCount;
+ unsigned int mLastFetchedSequenceNumber;
+ String * mCurrentFolder;
+ pthread_mutex_t mIdleLock;
+ int mState;
+ mailimap * mImap;
+ IMAPProgressCallback * mProgressCallback;
+ unsigned int mProgressItemsCount;
+
+ void init();
+ void bodyProgress(unsigned int current, unsigned int maximum);
+ void itemsProgress(unsigned int current, unsigned int maximum);
+ bool checkCertificate();
+ static void body_progress(size_t current, size_t maximum, void * context);
+ static void items_progress(size_t current, size_t maximum, void * context);
+ void setup();
+ void unsetup();
+ void connectIfNeeded(ErrorCode * pError);
+ void loginIfNeeded(ErrorCode * pError);
+ void selectIfNeeded(String * folder, ErrorCode * pError);
+ char fetchDelimiterIfNeeded(char defaultDelimiter, ErrorCode * pError);
+ Array * fetchMessages(String * folder, IMAPMessagesRequestKind requestKind, bool fetchByUID,
+ struct mailimap_set * imapset, HashMap * mapping, uint32_t startUid,
+ IMAPProgressCallback * progressCallback, ErrorCode * pError);
+
+ public:
+ IMAPSession();
+ virtual ~IMAPSession();
+
+ //virtual String * className();
+
+ virtual void setHostname(String * hostname);
+ virtual String * hostname();
+
+ virtual void setPort(unsigned int port);
+ virtual unsigned int port();
+
+ virtual void setUsername(String * login);
+ virtual String * username();
+
+ virtual void setPassword(String * password);
+ virtual String * password();
+
+ virtual void setAuthType(AuthType authType);
+ virtual AuthType authType();
+
+ virtual void setConnectionType(ConnectionType connectionType);
+ virtual ConnectionType connectionType();
+
+ virtual void setTimeout(time_t timeout);
+ virtual time_t timeout();
+
+ virtual void setCheckCertificateEnabled(bool enabled);
+ virtual bool isCheckCertificateEnabled();
+
+ virtual void setVoIPEnabled(bool enabled);
+ virtual bool isVoIPEnabled();
+
+ virtual void setDelimiter(char delimiter);
+ virtual char delimiter();
+
+ virtual void setDefaultNamespace(IMAPNamespace * ns);
+ virtual IMAPNamespace * defaultNamespace();
+
+ virtual void select(String * folder, ErrorCode * pError);
+
+ virtual Array * /* IMAPFolder */ fetchSubscribedFolders(ErrorCode * pError);
+ virtual Array * /* IMAPFolder */ fetchAllFolders(ErrorCode * pError); // will use xlist if available
+
+ virtual void renameFolder(String * folder, String * otherName, ErrorCode * pError);
+ virtual void deleteFolder(String * folder, ErrorCode * pError);
+ virtual void createFolder(String * folder, ErrorCode * pError);
+
+ virtual void subscribeFolder(String * folder, ErrorCode * pError);
+ virtual void unsubscribeFolder(String * folder, ErrorCode * pError);
+
+ virtual void appendMessage(String * folder, Data * messageData, MessageFlag flags,
+ IMAPProgressCallback * progressCallback, uint32_t * createdUID, ErrorCode * pError);
+
+ virtual void copyMessages(String * folder, Array * uidSet, String * destFolder,
+ Array ** pDestUIDs, ErrorCode * pError);
+
+ virtual void expunge(String * folder, ErrorCode * pError);
+
+ virtual Array * fetchMessagesByUID(String * folder, IMAPMessagesRequestKind requestKind,
+ uint32_t firstUID, uint32_t lastUID, IMAPProgressCallback * progressCallback, ErrorCode * pError);
+ virtual Array * fetchMessagesByNumber(String * folder, IMAPMessagesRequestKind requestKind,
+ uint32_t firstNumber, uint32_t lastNumber, IMAPProgressCallback * progressCallback, ErrorCode * pError);
+ virtual Array * fetchMessagesByUID(String * folder, IMAPMessagesRequestKind requestKind,
+ Array * numbers, IMAPProgressCallback * progressCallback, ErrorCode * pError);
+ virtual Array * fetchMessagesByNumber(String * folder, IMAPMessagesRequestKind requestKind,
+ Array * numbers, IMAPProgressCallback * progressCallback, ErrorCode * pError);
+ virtual Data * fetchMessageByUID(String * folder, uint32_t uid,
+ IMAPProgressCallback * progressCallback, ErrorCode * pError);
+ virtual Data * fetchMessageAttachmentByUID(String * folder, uint32_t uid, String * partID,
+ Encoding encoding, unsigned int expectedSize,
+ IMAPProgressCallback * progressCallback, ErrorCode * pError);
+ virtual HashMap * fetchMessageNumberUIDMapping(String * folder, uint32_t fromUID, uint32_t toUID,
+ ErrorCode * pError);
+
+ virtual void storeFlags(String * folder, Array * uids, IMAPStoreFlagsRequestKind kind, MessageFlag flags, ErrorCode * pError);
+ virtual void storeLabels(String * folder, Array * uids, IMAPStoreFlagsRequestKind kind, Array * labels, ErrorCode * pError);
+
+ virtual Array * search(String * folder, IMAPSearchKind kind, String * searchString, ErrorCode * pError);
+ virtual Array * search(String * folder, IMAPSearchExpression * expression, ErrorCode * pError);
+
+ virtual void setupIdle();
+ virtual void idle(String * folder, uint32_t lastKnownUID, ErrorCode * pError);
+ virtual void interruptIdle();
+ virtual void unsetupIdle();
+
+ virtual void connect(ErrorCode * pError);
+ virtual void disconnect();
+
+ virtual HashMap * fetchNamespace(ErrorCode * pError);
+
+ virtual void login(ErrorCode * pError);
+
+ virtual HashMap * identity(String * vendor, String * name, String * version, ErrorCode * pError);
+ };
+}
+
+#endif
diff --git a/src/core/pop/.DS_Store b/src/core/pop/.DS_Store
new file mode 100644
index 00000000..5008ddfc
--- /dev/null
+++ b/src/core/pop/.DS_Store
Binary files differ
diff --git a/src/core/pop/MCPOP.h b/src/core/pop/MCPOP.h
new file mode 100644
index 00000000..7651f9e6
--- /dev/null
+++ b/src/core/pop/MCPOP.h
@@ -0,0 +1,9 @@
+#ifndef __MAILCORE_MCPOP_H
+
+#define __MAILCORE_MCPOP_H
+
+#include <mailcore/MCPOPMessageInfo.h>
+#include <mailcore/MCPOPProgressCallback.h>
+#include <mailcore/MCPOPSession.h>
+
+#endif
diff --git a/src/core/pop/MCPOPMessageInfo.cc b/src/core/pop/MCPOPMessageInfo.cc
new file mode 100644
index 00000000..eafbda9f
--- /dev/null
+++ b/src/core/pop/MCPOPMessageInfo.cc
@@ -0,0 +1,76 @@
+#include "MCPOPMessageInfo.h"
+
+using namespace mailcore;
+
+void POPMessageInfo::init()
+{
+ mIndex = 0;
+ mSize = 0;
+ mUid = NULL;
+}
+
+POPMessageInfo::POPMessageInfo()
+{
+ init();
+}
+
+POPMessageInfo::POPMessageInfo(POPMessageInfo * other)
+{
+ init();
+ mIndex = other->mIndex;
+ mSize = other->mSize;
+ MC_SAFE_REPLACE_COPY(String, mUid, other->mUid);
+}
+
+POPMessageInfo::~POPMessageInfo()
+{
+ MC_SAFE_RELEASE(mUid);
+}
+
+#if 0
+String * POPMessageInfo::className()
+{
+ return MCSTR("POPMessageInfo");
+}
+#endif
+
+String * POPMessageInfo::description()
+{
+ return String::stringWithUTF8Format("<%s:%p %u %s %u>",
+ MCUTF8(className()), this, mIndex, MCUTF8(mUid), mSize);
+}
+
+Object * POPMessageInfo::copy()
+{
+ return new POPMessageInfo(this);
+}
+
+void POPMessageInfo::setIndex(unsigned int index)
+{
+ mIndex = index;
+}
+
+unsigned int POPMessageInfo::index()
+{
+ return mIndex;
+}
+
+void POPMessageInfo::setSize(unsigned int size)
+{
+ mSize = size;
+}
+
+unsigned int POPMessageInfo::size()
+{
+ return mSize;
+}
+
+void POPMessageInfo::setUid(String * uid)
+{
+ MC_SAFE_REPLACE_COPY(String, mUid, uid);
+}
+
+String * POPMessageInfo::uid()
+{
+ return mUid;
+}
diff --git a/src/core/pop/MCPOPMessageInfo.h b/src/core/pop/MCPOPMessageInfo.h
new file mode 100644
index 00000000..1e52b695
--- /dev/null
+++ b/src/core/pop/MCPOPMessageInfo.h
@@ -0,0 +1,38 @@
+#ifndef __MAILCORE_MCPOPMESSAGEINFO_H_
+
+#define __MAILCORE_MCPOPMESSAGEINFO_H_
+
+#include <mailcore/MCBaseTypes.h>
+
+namespace mailcore {
+
+ class POPMessageInfo : public Object {
+ private:
+ unsigned int mIndex;
+ unsigned int mSize;
+ String * mUid;
+
+ void init();
+
+ public:
+ POPMessageInfo();
+ POPMessageInfo(POPMessageInfo * other);
+ virtual ~POPMessageInfo();
+
+ //virtual String * className();
+ virtual String * description();
+ virtual Object * copy();
+
+ virtual void setIndex(unsigned int index);
+ virtual unsigned int index();
+
+ virtual void setSize(unsigned int size);
+ virtual unsigned int size();
+
+ virtual void setUid(String * uid);
+ virtual String * uid();
+ };
+
+}
+
+#endif
diff --git a/src/core/pop/MCPOPProgressCallback.h b/src/core/pop/MCPOPProgressCallback.h
new file mode 100644
index 00000000..2fc1b66b
--- /dev/null
+++ b/src/core/pop/MCPOPProgressCallback.h
@@ -0,0 +1,15 @@
+#ifndef __MAILCORE_MCPOPPROGRESSCALLBACK_H_
+
+#define __MAILCORE_MCPOPPROGRESSCALLBACK_H_
+
+namespace mailcore {
+
+ class POPSession;
+
+ class POPProgressCallback {
+ public:
+ virtual void bodyProgress(POPSession * session, unsigned int current, unsigned int maximum) {};
+ };
+}
+
+#endif
diff --git a/src/core/pop/MCPOPSession.cc b/src/core/pop/MCPOPSession.cc
new file mode 100644
index 00000000..eea5af90
--- /dev/null
+++ b/src/core/pop/MCPOPSession.cc
@@ -0,0 +1,545 @@
+#include "MCPOPSession.h"
+
+#include <string.h>
+
+#include "MCPOPMessageInfo.h"
+#include "MCPOPProgressCallback.h"
+#include "MCMessageHeader.h"
+
+using namespace mailcore;
+
+enum {
+ STATE_DISCONNECTED,
+ STATE_CONNECTED,
+ STATE_LOGGEDIN,
+ STATE_LISTED,
+};
+
+void POPSession::init()
+{
+ mHostname = NULL;
+ mPort = 0;
+ mUsername = NULL;
+ mPassword = NULL;
+ mAuthType = AuthTypeSASLNone;
+ mConnectionType = ConnectionTypeClear;
+ mCheckCertificateEnabled = true;
+ mTimeout = 30;
+
+ mPop = NULL;
+ mCapabilities = POPCapabilityNone;
+ mProgressCallback = NULL;
+ mState = STATE_DISCONNECTED;
+}
+
+POPSession::POPSession()
+{
+ init();
+}
+
+POPSession::~POPSession()
+{
+ MC_SAFE_RELEASE(mHostname);
+ MC_SAFE_RELEASE(mUsername);
+ MC_SAFE_RELEASE(mPassword);
+}
+
+#if 0
+String * POPSession::className()
+{
+ return MCSTR("POPSession");
+}
+#endif
+
+void POPSession::setHostname(String * hostname)
+{
+ MC_SAFE_REPLACE_COPY(String, mHostname, hostname);
+}
+
+String * POPSession::hostname()
+{
+ return mHostname;
+}
+
+void POPSession::setPort(unsigned int port)
+{
+ mPort = port;
+}
+
+unsigned int POPSession::port()
+{
+ return mPort;
+}
+
+void POPSession::setUsername(String * username)
+{
+ MC_SAFE_REPLACE_COPY(String, mUsername, username);
+}
+
+String * POPSession::username()
+{
+ return mUsername;
+}
+
+void POPSession::setPassword(String * password)
+{
+ MC_SAFE_REPLACE_COPY(String, mPassword, password);
+}
+
+String * POPSession::password()
+{
+ return mPassword;
+}
+
+void POPSession::setAuthType(AuthType authType)
+{
+ mAuthType = authType;
+}
+
+AuthType POPSession::authType()
+{
+ return mAuthType;
+}
+
+void POPSession::setConnectionType(ConnectionType connectionType)
+{
+ mConnectionType = connectionType;
+}
+
+ConnectionType POPSession::connectionType()
+{
+ return mConnectionType;
+}
+
+void POPSession::setTimeout(time_t timeout)
+{
+ mTimeout = timeout;
+}
+
+time_t POPSession::timeout()
+{
+ return mTimeout;
+}
+
+void POPSession::setCheckCertificateEnabled(bool enabled)
+{
+ mCheckCertificateEnabled = enabled;
+}
+
+bool POPSession::isCheckCertificateEnabled()
+{
+ return mCheckCertificateEnabled;
+}
+
+bool POPSession::checkCertificate()
+{
+ // XXX
+ return true;
+}
+
+void POPSession::bodyProgress(unsigned int current, unsigned int maximum)
+{
+ if (mProgressCallback != NULL) {
+ mProgressCallback->bodyProgress(this, current, maximum);
+ }
+}
+
+void POPSession::body_progress(size_t current, size_t maximum, void * context)
+{
+ POPSession * session;
+
+ session = (POPSession *) context;
+ session->bodyProgress((unsigned int) current, (unsigned int) maximum);
+}
+
+void POPSession::setup()
+{
+ mPop = mailpop3_new(0, NULL);
+}
+
+void POPSession::unsetup()
+{
+ if (mPop != NULL) {
+ if (mPop->pop3_stream != NULL) {
+ mailstream_close(mPop->pop3_stream);
+ mPop->pop3_stream = NULL;
+ }
+ mailpop3_free(mPop);
+ mPop = NULL;
+ }
+}
+
+void POPSession::connectIfNeeded(ErrorCode * pError)
+{
+ if (mState == STATE_DISCONNECTED) {
+ connect(pError);
+ }
+ else {
+ * pError = ErrorNone;
+ }
+}
+
+void POPSession::connect(ErrorCode * pError)
+{
+ int r;
+
+ setup();
+
+ switch (mConnectionType) {
+ case ConnectionTypeStartTLS:
+ MCLog("connect %s %u", MCUTF8(hostname()), (unsigned int) port());
+ r = mailpop3_socket_connect(mPop, MCUTF8(hostname()), port());
+ if (r != MAILPOP3_NO_ERROR) {
+ * pError = ErrorConnection;
+ return;
+ }
+
+ MCLog("start TLS");
+ r = mailpop3_socket_starttls(mPop);
+ if (r != MAILPOP3_NO_ERROR) {
+ * pError = ErrorStartTLSNotAvailable;
+ return;
+ }
+ MCLog("done");
+ if (!checkCertificate()) {
+ * pError = ErrorCertificate;
+ return;
+ }
+ break;
+
+ case ConnectionTypeTLS:
+ MCLog("connect %s %u", MCUTF8(hostname()), (unsigned int) port());
+ r = mailpop3_ssl_connect(mPop, MCUTF8(hostname()), port());
+ if (r != MAILPOP3_NO_ERROR) {
+ * pError = ErrorConnection;
+ return;
+ }
+ if (!checkCertificate()) {
+ * pError = ErrorCertificate;
+ return;
+ }
+ break;
+
+ default:
+ r = mailpop3_socket_connect(mPop, MCUTF8(hostname()), port());
+ if (r != MAILIMAP_NO_ERROR) {
+ * pError = ErrorConnection;
+ return;
+ }
+ break;
+ }
+
+ mailstream_low * low;
+ String * identifierString;
+ char * identifier;
+
+ low = mailstream_get_low(mPop->pop3_stream);
+ if (mUsername != NULL) {
+ identifierString = String::stringWithUTF8Format("%s@%s:%u", MCUTF8(mUsername), MCUTF8(mHostname), mPort);
+ }
+ else {
+ identifierString = String::stringWithUTF8Format("%s:%u", MCUTF8(mUsername), mPort);
+ }
+ identifier = strdup(identifierString->UTF8Characters());
+ mailstream_low_set_identifier(low, identifier);
+ mState = STATE_CONNECTED;
+ * pError = ErrorNone;
+}
+
+void POPSession::disconnect()
+{
+ if (mPop == NULL)
+ return;
+
+ mailpop3_quit(mPop);
+ mState = STATE_DISCONNECTED;
+ unsetup();
+}
+
+void POPSession::loginIfNeeded(ErrorCode * pError)
+{
+ connectIfNeeded(pError);
+ if (* pError != ErrorNone)
+ return;
+
+ if (mState == STATE_CONNECTED) {
+ login(pError);
+ }
+ else {
+ * pError = ErrorNone;
+ }
+}
+
+void POPSession::login(ErrorCode * pError)
+{
+ int r;
+ const char * utf8username;
+ const char * utf8password;
+
+ utf8username = MCUTF8(username());
+ utf8password = MCUTF8(password());
+ if (utf8username == NULL) {
+ utf8username = "";
+ }
+ if (utf8password == NULL) {
+ utf8password = "";
+ }
+
+ switch (authType()) {
+ case 0:
+ default:
+ r = mailpop3_user(mPop, utf8username);
+ if (r == MAILPOP3_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r != MAILPOP3_NO_ERROR) {
+ * pError = ErrorAuthentication;
+ return;
+ }
+
+ r = mailpop3_pass(mPop, utf8password);
+ break;
+
+ case AuthTypeSASLCRAMMD5:
+ r = mailpop3_auth(mPop, "CRAM-MD5",
+ MCUTF8(hostname()),
+ NULL,
+ NULL,
+ utf8username, utf8username,
+ utf8password, NULL);
+ break;
+
+ case AuthTypeSASLPlain:
+ r = mailpop3_auth(mPop, "PLAIN",
+ MCUTF8(hostname()),
+ NULL,
+ NULL,
+ utf8username, utf8username,
+ utf8password, NULL);
+ break;
+
+ case AuthTypeSASLGSSAPI:
+ // needs to be tested
+ r = mailpop3_auth(mPop, "GSSAPI",
+ MCUTF8(hostname()),
+ NULL,
+ NULL,
+ utf8username, utf8username,
+ utf8password, NULL /* realm */);
+ break;
+
+ case AuthTypeSASLDIGESTMD5:
+ r = mailpop3_auth(mPop, "DIGEST-MD5",
+ MCUTF8(hostname()),
+ NULL,
+ NULL,
+ utf8username, utf8username,
+ utf8password, NULL);
+ break;
+
+ case AuthTypeSASLLogin:
+ r = mailpop3_auth(mPop, "LOGIN",
+ MCUTF8(hostname()),
+ NULL,
+ NULL,
+ utf8username, utf8username,
+ utf8password, NULL);
+ break;
+
+ case AuthTypeSASLSRP:
+ r = mailpop3_auth(mPop, "SRP",
+ MCUTF8(hostname()),
+ NULL,
+ NULL,
+ utf8username, utf8username,
+ utf8password, NULL);
+ break;
+
+ case AuthTypeSASLNTLM:
+ r = mailpop3_auth(mPop, "NTLM",
+ MCUTF8(hostname()),
+ NULL,
+ NULL,
+ utf8username, utf8username,
+ utf8password, NULL /* realm */);
+ break;
+
+ case AuthTypeSASLKerberosV4:
+ r = mailpop3_auth(mPop, "KERBEROS_V4",
+ MCUTF8(hostname()),
+ NULL,
+ NULL,
+ utf8username, utf8username,
+ utf8password, NULL /* realm */);
+ break;
+ }
+ if (r == MAILPOP3_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r != MAILPOP3_NO_ERROR) {
+ * pError = ErrorAuthentication;
+ return;
+ }
+
+ mState = STATE_LOGGEDIN;
+ * pError = ErrorNone;
+}
+
+Array * POPSession::fetchMessages(ErrorCode * pError)
+{
+ int r;
+ carray * msg_list;
+
+ loginIfNeeded(pError);
+ if (* pError != ErrorNone) {
+ return NULL;
+ }
+
+ r = mailpop3_list(mPop, &msg_list);
+ if (r == MAILPOP3_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return NULL;
+ }
+ else if (r != MAILPOP3_NO_ERROR) {
+ * pError = ErrorFetchMessageList;
+ return NULL;
+ }
+
+ Array * result = Array::array();
+ for(unsigned int i = 0 ; i < carray_count(msg_list) ; i ++) {
+ struct mailpop3_msg_info * msg_info;
+ String * uid;
+
+ msg_info = (struct mailpop3_msg_info *) carray_get(msg_list, i);
+ if (msg_info->msg_uidl == NULL)
+ continue;
+
+ uid = String::stringWithUTF8Characters(msg_info->msg_uidl);
+
+ POPMessageInfo * info = new POPMessageInfo();
+ info->setUid(uid);
+ info->setIndex(msg_info->msg_index);
+ result->addObject(info);
+ info->release();
+ }
+
+ * pError = ErrorNone;
+ mState = STATE_LISTED;
+
+ return result;
+}
+
+void POPSession::listIfNeeded(ErrorCode * pError)
+{
+ if (mState == STATE_LISTED) {
+ * pError = ErrorNone;
+ return;
+ }
+
+ fetchMessages(pError);
+}
+
+MessageHeader * POPSession::fetchHeader(unsigned int index, ErrorCode * pError)
+{
+ int r;
+ char * content;
+ size_t content_len;
+
+ listIfNeeded(pError);
+ if (* pError != ErrorNone) {
+ return NULL;
+ }
+
+ r = mailpop3_top(mPop, index, 0, &content, &content_len);
+ if (r == MAILPOP3_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return NULL;
+ }
+ else if (r != MAILPOP3_NO_ERROR) {
+ * pError = ErrorFetch;
+ return NULL;
+ }
+
+ Data * data;
+ data = new Data(content, (unsigned int) content_len);
+ MessageHeader * result = new MessageHeader();
+ result->importHeadersData(data);
+ result->autorelease();
+ data->release();
+
+ mailpop3_top_free(content);
+ * pError = ErrorNone;
+
+ return result;
+}
+
+MessageHeader * POPSession::fetchHeader(POPMessageInfo * msg, ErrorCode * pError)
+{
+ return fetchHeader(msg->index(), pError);
+}
+
+Data * POPSession::fetchMessage(unsigned int index, POPProgressCallback * callback, ErrorCode * pError)
+{
+ int r;
+ char * content;
+ size_t content_len;
+
+ listIfNeeded(pError);
+ if (* pError != ErrorNone) {
+ return NULL;
+ }
+
+ mProgressCallback = callback;
+
+ r = mailpop3_retr(mPop, index, &content, &content_len);
+ mProgressCallback = NULL;
+ if (r == MAILPOP3_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return NULL;
+ }
+ else if (r != MAILPOP3_NO_ERROR) {
+ * pError = ErrorFetch;
+ return NULL;
+ }
+
+ Data * result;
+ result = Data::dataWithBytes(content, (unsigned int) content_len);
+ mailpop3_retr_free(content);
+ * pError = ErrorNone;
+
+ return result;
+}
+
+Data * POPSession::fetchMessage(POPMessageInfo * msg, POPProgressCallback * callback, ErrorCode * pError)
+{
+ return fetchMessage(msg->index(), callback, pError);
+}
+
+void POPSession::deleteMessage(unsigned int index, ErrorCode * pError)
+{
+ int r;
+
+ listIfNeeded(pError);
+ if (* pError != ErrorNone) {
+ return;
+ }
+
+ r = mailpop3_dele(mPop, index);
+ if (r == MAILPOP3_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r != MAILPOP3_NO_ERROR) {
+ * pError = ErrorDeleteMessage;
+ return;
+ }
+
+ * pError = ErrorNone;
+}
+
+void POPSession::deleteMessage(POPMessageInfo * msg, ErrorCode * pError)
+{
+ deleteMessage(msg->index(), pError);
+}
diff --git a/src/core/pop/MCPOPSession.h b/src/core/pop/MCPOPSession.h
new file mode 100644
index 00000000..ef6c132b
--- /dev/null
+++ b/src/core/pop/MCPOPSession.h
@@ -0,0 +1,90 @@
+#ifndef __MAILCORE_MCPOPSESSION_H_
+
+#define __MAILCORE_MCPOPSESSION_H_
+
+#include <mailcore/MCBaseTypes.h>
+#include <mailcore/MCMessageConstants.h>
+#include <libetpan/libetpan.h>
+
+namespace mailcore {
+
+ class POPMessageInfo;
+ class POPProgressCallback;
+ class MessageHeader;
+
+ class POPSession : public Object {
+ private:
+ String * mHostname;
+ unsigned int mPort;
+ String * mUsername;
+ String * mPassword;
+ AuthType mAuthType;
+ ConnectionType mConnectionType;
+ bool mCheckCertificateEnabled;
+ time_t mTimeout;
+
+ mailpop3 * mPop;
+ POPCapability mCapabilities;
+ POPProgressCallback * mProgressCallback;
+ int mState;
+
+ void init();
+ void bodyProgress(unsigned int current, unsigned int maximum);
+ bool checkCertificate();
+ static void body_progress(size_t current, size_t maximum, void * context);
+ void setup();
+ void unsetup();
+ void connectIfNeeded(ErrorCode * pError);
+ void loginIfNeeded(ErrorCode * pError);
+ void listIfNeeded(ErrorCode * pError);
+
+ public:
+ POPSession();
+ virtual ~POPSession();
+
+ //virtual String * className();
+
+ virtual void setHostname(String * hostname);
+ virtual String * hostname();
+
+ virtual void setPort(unsigned int port);
+ virtual unsigned int port();
+
+ virtual void setUsername(String * login);
+ virtual String * username();
+
+ virtual void setPassword(String * password);
+ virtual String * password();
+
+ virtual void setAuthType(AuthType authType);
+ virtual AuthType authType();
+
+ virtual void setConnectionType(ConnectionType connectionType);
+ virtual ConnectionType connectionType();
+
+ virtual void setTimeout(time_t timeout);
+ virtual time_t timeout();
+
+ virtual void setCheckCertificateEnabled(bool enabled);
+ virtual bool isCheckCertificateEnabled();
+
+ virtual void connect(ErrorCode * pError);
+ virtual void disconnect();
+
+ virtual void login(ErrorCode * pError);
+
+ Array * fetchMessages(ErrorCode * pError);
+
+ MessageHeader * fetchHeader(unsigned int index, ErrorCode * pError);
+ MessageHeader * fetchHeader(POPMessageInfo * msg, ErrorCode * pError);
+
+ Data * fetchMessage(unsigned int index, POPProgressCallback * callback, ErrorCode * pError);
+ Data * fetchMessage(POPMessageInfo * msg, POPProgressCallback * callback, ErrorCode * pError);
+
+ void deleteMessage(unsigned int index, ErrorCode * pError);
+ void deleteMessage(POPMessageInfo * msg, ErrorCode * pError);
+ };
+
+}
+
+#endif
diff --git a/src/core/rfc822/.DS_Store b/src/core/rfc822/.DS_Store
new file mode 100644
index 00000000..5008ddfc
--- /dev/null
+++ b/src/core/rfc822/.DS_Store
Binary files differ
diff --git a/src/core/rfc822/MCAttachment.cc b/src/core/rfc822/MCAttachment.cc
new file mode 100644
index 00000000..856a756f
--- /dev/null
+++ b/src/core/rfc822/MCAttachment.cc
@@ -0,0 +1,444 @@
+#include "MCAttachment.h"
+
+#include "MCMultipart.h"
+#include "MCMessagePart.h"
+#include "MCMessageHeader.h"
+#include "MCMessageConstants.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+using namespace mailcore;
+
+String * Attachment::mimeTypeForFilename(String * filename)
+{
+ // TODO: read from a file
+ String * ext;
+
+ ext = filename->pathExtension()->lowercaseString();
+ if (ext->isEqual(MCSTR("jpg"))) {
+ return MCSTR("image/jpeg");
+ }
+ else if (ext->isEqual(MCSTR("jpeg"))) {
+ return MCSTR("image/jpeg");
+ }
+ else if (ext->isEqual(MCSTR("png"))) {
+ return MCSTR("image/png");
+ }
+ else if (ext->isEqual(MCSTR("gif"))) {
+ return MCSTR("image/gif");
+ }
+ else if (ext->isEqual(MCSTR("html"))) {
+ return MCSTR("text/html");
+ }
+ else if (ext->isEqual(MCSTR("txt"))) {
+ return MCSTR("text/plain");
+ }
+ return NULL;
+}
+
+Attachment * Attachment::attachmentWithContentOfFile(String * filename)
+{
+ Attachment * attachment;
+ String * mimeType;
+ Data * data;
+
+ attachment = new Attachment();
+ data = Data::dataWithContentsOfFile(filename);
+ mimeType = Attachment::mimeTypeForFilename(filename);
+ if (mimeType != NULL) {
+ attachment->setMimeType(mimeType);
+ }
+ attachment->setFilename(filename->lastPathComponent());
+ attachment->setData(data);
+
+ return (Attachment *) attachment->autorelease();
+}
+
+Attachment * Attachment::attachmentWithHTMLString(String * htmlString)
+{
+ Data * data;
+ Attachment * attachment;
+
+ attachment = new Attachment();
+ attachment->setInlineAttachment(true);
+ attachment->setMimeType(MCSTR("text/html"));
+ data = htmlString->dataUsingEncoding("utf-8");
+ attachment->setData(data);
+
+ return (Attachment *) attachment->autorelease();
+}
+
+Attachment * Attachment::attachmentWithRFC822Message(Data * messageData)
+{
+ Attachment * attachment;
+
+ attachment = new Attachment();
+ attachment->setMimeType(MCSTR("message/rfc822"));
+ attachment->setData(messageData);
+
+ return (Attachment *) attachment->autorelease();
+}
+
+Attachment * Attachment::attachmentWithText(String * text)
+{
+ Data * data;
+ Attachment * attachment;
+
+ attachment = new Attachment();
+ attachment->setInlineAttachment(true);
+ attachment->setMimeType(MCSTR("text/plain"));
+ data = text->dataUsingEncoding("utf-8");
+ attachment->setData(data);
+
+ return (Attachment *) attachment->autorelease();
+}
+
+void Attachment::init()
+{
+ mData = NULL;
+ setMimeType(MCSTR("application/octet-stream"));
+}
+
+Attachment::Attachment()
+{
+ init();
+}
+
+Attachment::Attachment(Attachment * other) : AbstractPart(other)
+{
+ init();
+ MC_SAFE_REPLACE_RETAIN(Data, mData, other->mData);
+}
+
+Attachment::~Attachment()
+{
+ MC_SAFE_RELEASE(mData);
+}
+
+String * Attachment::description()
+{
+ String * result = String::string();
+ result->appendUTF8Format("<%s:%p\n", className()->UTF8Characters(), this);
+ if (filename() != NULL) {
+ result->appendUTF8Format("filename: %s\n", filename()->UTF8Characters());
+ }
+ if (mimeType() != NULL) {
+ result->appendUTF8Format("mime type: %s\n", mimeType()->UTF8Characters());
+ }
+ if (charset() != NULL) {
+ result->appendUTF8Format("charset: %s\n", charset()->UTF8Characters());
+ }
+ if (contentID() != NULL) {
+ result->appendUTF8Format("content-ID: %s\n", contentID()->UTF8Characters());
+ }
+ if (contentLocation() != NULL) {
+ result->appendUTF8Format("content-location: %s\n", contentLocation()->UTF8Characters());
+ }
+ result->appendUTF8Format("inline: %i\n", isInlineAttachment());
+ if (mData != NULL) {
+ result->appendUTF8Format("data: %i bytes\n", mData->length());
+ }
+ else {
+ result->appendUTF8Format("no data\n");
+ }
+ result->appendUTF8Format(">");
+
+ return result;
+}
+
+#if 0
+String * Attachment::className()
+{
+ return MCSTR("Attachment");
+}
+#endif
+
+Object * Attachment::copy()
+{
+ return new Attachment(this);
+}
+
+void Attachment::setData(Data * data)
+{
+ MC_SAFE_REPLACE_RETAIN(Data, mData, data);
+}
+
+Data * Attachment::data()
+{
+ return mData;
+}
+
+AbstractPart * Attachment::attachmentsWithMIME(struct mailmime * mime)
+{
+ return attachmentsWithMIMEWithMain(mime, true);
+}
+
+void Attachment::fillMultipartSubAttachments(AbstractMultipart * multipart, struct mailmime * mime)
+{
+ switch (mime->mm_type) {
+ case MAILMIME_MULTIPLE:
+ {
+ clistiter * cur;
+ Array * subAttachments = Array::array();
+ for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ; cur != NULL ; cur = clist_next(cur)) {
+ struct mailmime * submime;
+ AbstractPart * subAttachment;
+
+ submime = (struct mailmime *) clist_content(cur);
+ subAttachment = attachmentsWithMIMEWithMain(submime, false);
+ subAttachments->addObject(subAttachment);
+ }
+
+ multipart->setParts(subAttachments);
+ break;
+ }
+ }
+}
+
+AbstractPart * Attachment::attachmentsWithMIMEWithMain(struct mailmime * mime, bool isMain)
+{
+ switch (mime->mm_type) {
+ case MAILMIME_SINGLE:
+ {
+ Attachment * attachment;
+ attachment = attachmentWithSingleMIME(mime);
+ return attachment;
+ }
+ case MAILMIME_MULTIPLE:
+ {
+ if ((mime->mm_content_type != NULL) && (mime->mm_content_type->ct_subtype != NULL) &&
+ (strcasecmp(mime->mm_content_type->ct_subtype, "alternative") == 0)) {
+ Multipart * attachment;
+ attachment = new Multipart();
+ attachment->setPartType(PartTypeMultipartAlternative);
+ fillMultipartSubAttachments(attachment, mime);
+ return (Multipart *) attachment->autorelease();
+ }
+ else if ((mime->mm_content_type != NULL) && (mime->mm_content_type->ct_subtype != NULL) &&
+ (strcasecmp(mime->mm_content_type->ct_subtype, "related") == 0)) {
+ Multipart * attachment;
+ attachment = new Multipart();
+ attachment->setPartType(PartTypeMultipartRelated);
+ fillMultipartSubAttachments(attachment, mime);
+ return (Multipart *) attachment->autorelease();
+ }
+ else {
+ Multipart * attachment;
+ attachment = new Multipart();
+ fillMultipartSubAttachments(attachment, mime);
+ return (Multipart *) attachment->autorelease();
+ }
+ }
+ case MAILMIME_MESSAGE:
+ {
+ if (isMain) {
+ AbstractPart * attachment;
+ attachment = attachmentsWithMIMEWithMain(mime->mm_data.mm_message.mm_msg_mime, false);
+ return attachment;
+ }
+ else {
+ MessagePart * messagePart;
+ messagePart = attachmentWithMessageMIME(mime);
+ return messagePart;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+Encoding Attachment::encodingForMIMEEncoding(struct mailmime_mechanism * mechanism, int defaultMimeEncoding)
+{
+ Encoding mimeEncoding = (Encoding) defaultMimeEncoding;
+
+ if (mechanism != NULL) {
+ mimeEncoding = (Encoding) mechanism->enc_type;
+ }
+
+ switch ((int) mimeEncoding) {
+ default:
+ case MAILMIME_MECHANISM_ERROR:
+ return EncodingOther;
+ case MAILMIME_MECHANISM_7BIT:
+ return Encoding7Bit;
+ case MAILMIME_MECHANISM_8BIT:
+ return Encoding8Bit;
+ case MAILMIME_MECHANISM_BINARY:
+ return EncodingBinary;
+ case MAILMIME_MECHANISM_QUOTED_PRINTABLE:
+ return EncodingQuotedPrintable;
+ case MAILMIME_MECHANISM_BASE64:
+ return EncodingBase64;
+ case MAILMIME_MECHANISM_TOKEN:
+ if (mechanism == NULL)
+ return Encoding8Bit;
+ if (mechanism->enc_token == NULL)
+ return Encoding8Bit;
+
+ if (strcasecmp(mechanism->enc_token, "x-uuencode") == 0) {
+ return EncodingUUEncode;
+ }
+ else {
+ return EncodingOther;
+ }
+ }
+}
+
+static const char * get_discrete_type(struct mailmime_discrete_type * discrete_type)
+{
+ switch (discrete_type->dt_type) {
+ case MAILMIME_DISCRETE_TYPE_TEXT:
+ return "text";
+
+ case MAILMIME_DISCRETE_TYPE_IMAGE:
+ return "image";
+
+ case MAILMIME_DISCRETE_TYPE_AUDIO:
+ return "audio";
+
+ case MAILMIME_DISCRETE_TYPE_VIDEO:
+ return "video";
+
+ case MAILMIME_DISCRETE_TYPE_APPLICATION:
+ return "application";
+
+ case MAILMIME_DISCRETE_TYPE_EXTENSION:
+ return discrete_type->dt_extension;
+ }
+
+ return NULL;
+}
+
+static const char *
+get_composite_type(struct mailmime_composite_type * composite_type)
+{
+ switch (composite_type->ct_type) {
+ case MAILMIME_COMPOSITE_TYPE_MESSAGE:
+ return "message";
+
+ case MAILMIME_COMPOSITE_TYPE_MULTIPART:
+ return "multipart";
+
+ case MAILMIME_COMPOSITE_TYPE_EXTENSION:
+ return composite_type->ct_token;
+ }
+
+ return NULL;
+}
+
+static char * get_content_type_str(struct mailmime_content * content)
+{
+ const char * str;
+ char * result;
+ const char * subtype;
+
+ if (content == NULL) {
+ return strdup("unknown/unknown");
+ }
+
+ str = "unknown";
+
+ switch (content->ct_type->tp_type) {
+ case MAILMIME_TYPE_DISCRETE_TYPE:
+ str = get_discrete_type(content->ct_type->tp_data.tp_discrete_type);
+ break;
+
+ case MAILMIME_TYPE_COMPOSITE_TYPE:
+ str = get_composite_type(content->ct_type->tp_data.tp_composite_type);
+ break;
+ }
+
+ if (str == NULL)
+ str = "unknown";
+ subtype = content->ct_subtype;
+ if (subtype == NULL)
+ subtype = "unknown";
+
+ result = (char *) malloc(strlen(str) + strlen(subtype) + 2);
+ strcpy(result, str);
+ strcat(result, "/");
+ strcat(result, subtype);
+
+ return result;
+}
+
+Attachment * Attachment::attachmentWithSingleMIME(struct mailmime * mime)
+{
+ struct mailmime_data * data;
+ const char * bytes;
+ size_t length;
+ Attachment * result;
+ struct mailmime_single_fields single_fields;
+ char * str;
+ char * name;
+ char * filename;
+ char * content_id;
+ char * loc;
+ Encoding encoding;
+
+ MCAssert(mime->mm_type == MAILMIME_SINGLE);
+
+ result = new Attachment();
+ data = mime->mm_data.mm_single;
+ bytes = data->dt_data.dt_text.dt_data;
+ length = data->dt_data.dt_text.dt_length;
+
+ 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);
+
+ name = single_fields.fld_content_name;
+ filename = single_fields.fld_disposition_filename;
+ content_id = single_fields.fld_id;
+ loc = single_fields.fld_location;
+
+ MCLog("filename %s", filename);
+ if (filename != NULL) {
+ result->setFilename(String::stringByDecodingMIMEHeaderValue(filename));
+ }
+ else if (name != NULL) {
+ result->setFilename(String::stringByDecodingMIMEHeaderValue(name));
+ }
+ if (content_id != NULL) {
+ result->setContentID(String::stringWithUTF8Characters(content_id));
+ }
+ if (single_fields.fld_content_charset != NULL) {
+ result->setCharset(String::stringByDecodingMIMEHeaderValue(single_fields.fld_content_charset));
+ }
+ if (loc != NULL) {
+ result->setContentLocation(String::stringWithUTF8Characters(loc));
+ }
+
+ if (single_fields.fld_disposition != NULL) {
+ if (single_fields.fld_disposition->dsp_type != NULL) {
+ if (single_fields.fld_disposition->dsp_type->dsp_type == MAILMIME_DISPOSITION_TYPE_INLINE) {
+ result->setInlineAttachment(true);
+ }
+ }
+ }
+
+ return (Attachment *) result->autorelease();
+}
+
+MessagePart * Attachment::attachmentWithMessageMIME(struct mailmime * mime)
+{
+ MessagePart * attachment;
+ AbstractPart * mainPart;
+
+ attachment = new MessagePart();
+ attachment->header()->importIMFFields(mime->mm_data.mm_message.mm_fields);
+ mainPart = attachmentsWithMIMEWithMain(mime->mm_data.mm_message.mm_msg_mime, false);
+ attachment->setMainPart(mainPart);
+
+ return (MessagePart *) attachment->autorelease();
+}
diff --git a/src/core/rfc822/MCAttachment.h b/src/core/rfc822/MCAttachment.h
new file mode 100644
index 00000000..0fc4fc98
--- /dev/null
+++ b/src/core/rfc822/MCAttachment.h
@@ -0,0 +1,47 @@
+#ifndef __MAILCORE_MCATTACHMENT_H_
+
+#define __MAILCORE_MCATTACHMENT_H_
+
+#include <mailcore/MCBaseTypes.h>
+#include <mailcore/MCAbstractPart.h>
+#include <mailcore/MCAbstractMultipart.h>
+#include <mailcore/MCMessageConstants.h>
+
+namespace mailcore {
+
+ class MessagePart;
+
+ class Attachment : public AbstractPart {
+ private:
+ Data * mData;
+ void init();
+ static void fillMultipartSubAttachments(AbstractMultipart * multipart, struct mailmime * mime);
+ static AbstractPart * attachmentsWithMIMEWithMain(struct mailmime * mime, bool isMain);
+ static Attachment * attachmentWithSingleMIME(struct mailmime * mime);
+ static MessagePart * attachmentWithMessageMIME(struct mailmime * mime);
+ static Encoding encodingForMIMEEncoding(struct mailmime_mechanism * mechanism, int defaultMimeEncoding);
+
+ public:
+ static String * mimeTypeForFilename(String * filename);
+ static Attachment * attachmentWithContentOfFile(String * filename);
+ static Attachment * attachmentWithHTMLString(String * htmlString);
+ static Attachment * attachmentWithRFC822Message(Data * messageData);
+ static Attachment * attachmentWithText(String * text);
+
+ Attachment();
+ Attachment(Attachment * other);
+ virtual ~Attachment();
+
+ virtual String * description();
+ //virtual String * className();
+ virtual Object * copy();
+
+ virtual void setData(Data * data);
+ virtual Data * data();
+
+ static AbstractPart * attachmentsWithMIME(struct mailmime * mime);
+ };
+
+}
+
+#endif
diff --git a/src/core/rfc822/MCMessageBuilder.cc b/src/core/rfc822/MCMessageBuilder.cc
new file mode 100644
index 00000000..62482564
--- /dev/null
+++ b/src/core/rfc822/MCMessageBuilder.cc
@@ -0,0 +1,706 @@
+#include "MCMessageBuilder.h"
+
+#include "MCMessageHeader.h"
+#include "MCAttachment.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+using namespace mailcore;
+
+static char * generate_boundary(const char * boundary_prefix);
+struct mailmime * part_multiple_new(const char * type, const char * boundary_prefix);
+static struct mailmime *
+part_new_empty(struct mailmime_content * content,
+ struct mailmime_fields * mime_fields,
+ const char * boundary_prefix,
+ int force_single);
+
+static struct mailmime * get_multipart_alternative(const char * boundary_prefix)
+{
+ struct mailmime * mime;
+
+ mime = part_multiple_new("multipart/alternative", boundary_prefix);
+
+ return mime;
+}
+
+static struct mailmime * get_multipart_related(const char * boundary_prefix)
+{
+ struct mailmime * mime;
+
+ mime = part_multiple_new("multipart/related", boundary_prefix);
+
+ return mime;
+}
+
+static int add_attachment(struct mailmime * mime,
+ struct mailmime * mime_sub,
+ const char * boundary_prefix)
+{
+ struct mailmime * saved_sub;
+ struct mailmime * mp;
+ int res;
+ int r;
+
+ switch (mime->mm_type) {
+ case MAILMIME_SINGLE:
+ res = MAILIMF_ERROR_INVAL;
+ goto err;
+
+ case MAILMIME_MULTIPLE:
+ r = mailmime_add_part(mime, mime_sub);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ return MAILIMF_NO_ERROR;
+ }
+
+ /* MAILMIME_MESSAGE */
+
+ if (mime->mm_data.mm_message.mm_msg_mime == NULL) {
+ /* there is no subpart, we can simply attach it */
+
+ r = mailmime_add_part(mime, mime_sub);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ return MAILIMF_NO_ERROR;
+ }
+
+ if (mime->mm_data.mm_message.mm_msg_mime->mm_type == MAILMIME_MULTIPLE &&
+ strcasecmp(mime->mm_data.mm_message.mm_msg_mime->mm_content_type->ct_subtype, "alternative") != 0) {
+ /* in case the subpart is multipart, simply attach it to the subpart */
+
+ return mailmime_add_part(mime->mm_data.mm_message.mm_msg_mime, mime_sub);
+ }
+
+ /* we save the current subpart, ... */
+
+ saved_sub = mime->mm_data.mm_message.mm_msg_mime;
+
+ /* create a multipart */
+
+ mp = part_multiple_new("multipart/mixed", boundary_prefix);
+ if (mp == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ /* detach the saved subpart from the parent */
+
+ mailmime_remove_part(saved_sub);
+
+ /* the created multipart is the new child of the parent */
+
+ r = mailmime_add_part(mime, mp);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_mp;
+ }
+
+ /* then, attach the saved subpart and ... */
+
+ r = mailmime_add_part(mp, saved_sub);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_saved_sub;
+ }
+
+ /* the given part to the parent */
+
+ r = mailmime_add_part(mp, mime_sub);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_saved_sub;
+ }
+
+ return MAILIMF_NO_ERROR;
+
+free_mp:
+ mailmime_free(mp);
+free_saved_sub:
+ mailmime_free(saved_sub);
+err:
+ return res;
+}
+
+static struct mailmime * get_text_part(const char * mime_type, const char * charset, const char * content_id,
+ const char * text, size_t length, int encoding_type)
+{
+ struct mailmime_fields * mime_fields;
+ struct mailmime * mime;
+ struct mailmime_content * content;
+ struct mailmime_parameter * param;
+ struct mailmime_disposition * disposition;
+ struct mailmime_mechanism * encoding;
+ char * dup_content_id;
+
+ encoding = mailmime_mechanism_new(encoding_type, NULL);
+ disposition = mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
+ NULL, NULL, NULL, NULL, (size_t) -1);
+ dup_content_id = NULL;
+ if (content_id != NULL)
+ dup_content_id = strdup(content_id);
+ mime_fields = mailmime_fields_new_with_data(encoding,
+ dup_content_id, NULL, disposition, NULL);
+
+ content = mailmime_content_new_with_str(mime_type);
+ if (charset == NULL) {
+ param = mailmime_param_new_with_data((char *) "charset", (char *) "utf-8");
+ }
+ else {
+ param = mailmime_param_new_with_data((char *) "charset", (char *) charset);
+ }
+ clist_append(content->ct_parameters, param);
+ mime = part_new_empty(content, mime_fields, NULL, 1);
+ mailmime_set_body_text(mime, (char *) text, length);
+
+ return mime;
+}
+
+static struct mailmime * get_plain_text_part(const char * mime_type, const char * charset, const char * content_id,
+ const char * text, size_t length)
+{
+ bool needsQuotedPrintable;
+ int mechanism;
+
+ needsQuotedPrintable = false;
+ for(size_t i = 0 ; i < length ; i ++) {
+ if ((text[i] & (1 << 7)) != 0) {
+ needsQuotedPrintable = true;
+ }
+ }
+
+ mechanism = MAILMIME_MECHANISM_7BIT;
+ if (needsQuotedPrintable) {
+ mechanism = MAILMIME_MECHANISM_QUOTED_PRINTABLE;
+ }
+ return get_text_part(mime_type, charset, content_id, text, length, mechanism);
+}
+
+static struct mailmime * get_other_text_part(const char * mime_type, const char * charset, const char * content_id,
+ const char * text, size_t length)
+{
+ return get_text_part(mime_type, charset, content_id, text, length, MAILMIME_MECHANISM_QUOTED_PRINTABLE);
+}
+
+static struct mailmime * get_file_part(const char * filename, const char * mime_type, int is_inline,
+ const char * content_id,
+ const char * text, size_t length)
+{
+ char * disposition_name;
+ int encoding_type;
+ struct mailmime_disposition * disposition;
+ struct mailmime_mechanism * encoding;
+ struct mailmime_content * content;
+ struct mailmime * mime;
+ struct mailmime_fields * mime_fields;
+ char * dup_content_id;
+
+ disposition_name = NULL;
+ if (filename != NULL) {
+ disposition_name = strdup(filename);
+ }
+ if (is_inline) {
+ disposition = mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
+ disposition_name, NULL, NULL, NULL, (size_t) -1);
+ }
+ else {
+ disposition = mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
+ disposition_name, NULL, NULL, NULL, (size_t) -1);
+ }
+ content = mailmime_content_new_with_str(mime_type);
+
+ encoding_type = MAILMIME_MECHANISM_BASE64;
+ encoding = mailmime_mechanism_new(encoding_type, NULL);
+ dup_content_id = NULL;
+ if (content_id != NULL)
+ dup_content_id = strdup(content_id);
+ mime_fields = mailmime_fields_new_with_data(encoding,
+ dup_content_id, NULL, disposition, NULL);
+ mime = part_new_empty(content, mime_fields, NULL, 1);
+ mailmime_set_body_text(mime, (char *) text, length);
+
+ return mime;
+}
+
+static struct mailmime * mime_from_attachment(Attachment * att)
+{
+ struct mailmime * mime;
+ Data * data;
+ int r;
+
+ data = att->data();
+ if (data == NULL) {
+ data = Data::data();
+ }
+ if (att->mimeType()->lowercaseString()->isEqual(MCSTR("message/rfc822"))) {
+ size_t indx = 0;
+ r = mailmime_parse(data->bytes(), data->length(), &indx, &mime);
+ if (r != MAILIMF_NO_ERROR)
+ return NULL;
+ }
+ else if (att->isInlineAttachment() && att->mimeType()->lowercaseString()->isEqual(MCSTR("text/plain"))) {
+ mime = get_plain_text_part(MMCUTF8(att->mimeType()), MMCUTF8(att->charset()),
+ MMCUTF8(att->contentID()),
+ data->bytes(), data->length());
+ }
+ else if (att->isInlineAttachment() && att->mimeType()->lowercaseString()->hasPrefix(MCSTR("text/"))) {
+ mime = get_other_text_part(MMCUTF8(att->mimeType()), MMCUTF8(att->charset()),
+ MMCUTF8(att->contentID()),
+ data->bytes(), data->length());
+ }
+ else {
+ mime = get_file_part(att->filename()->encodedMIMEHeaderValue()->bytes(),
+ MMCUTF8(att->mimeType()), att->isInlineAttachment(),
+ MMCUTF8(att->contentID()),
+ data->bytes(), data->length());
+ }
+ return mime;
+}
+
+static struct mailmime * multipart_related_from_attachments(Attachment * htmlAttachment,
+ Array * attachments, const char * boundary_prefix)
+{
+ if ((attachments != NULL) && (attachments->count() > 0)) {
+ struct mailmime * submime;
+ struct mailmime * mime;
+
+ mime = get_multipart_related(boundary_prefix);
+
+ submime = mime_from_attachment(htmlAttachment);
+ add_attachment(mime, submime, boundary_prefix);
+
+ for(unsigned int i = 0 ; i < attachments->count() ; i ++) {
+ Attachment * attachment;
+
+ attachment = (Attachment *) attachments->objectAtIndex(i);
+ submime = mime_from_attachment(attachment);
+ add_attachment(mime, submime, boundary_prefix);
+ }
+
+ return mime;
+ }
+ else {
+ struct mailmime * mime;
+
+ mime = mime_from_attachment(htmlAttachment);
+
+ return mime;
+ }
+}
+
+static struct mailmime *
+part_new_empty(struct mailmime_content * content,
+ struct mailmime_fields * mime_fields,
+ const char * boundary_prefix,
+ int force_single)
+{
+ struct mailmime * build_info;
+ clist * list;
+ int r;
+ int mime_type;
+
+ list = NULL;
+
+ if (force_single) {
+ mime_type = MAILMIME_SINGLE;
+ }
+ else {
+ switch (content->ct_type->tp_type) {
+ case MAILMIME_TYPE_DISCRETE_TYPE:
+ mime_type = MAILMIME_SINGLE;
+ break;
+
+ case MAILMIME_TYPE_COMPOSITE_TYPE:
+ switch (content->ct_type->tp_data.tp_composite_type->ct_type) {
+ case MAILMIME_COMPOSITE_TYPE_MULTIPART:
+ mime_type = MAILMIME_MULTIPLE;
+ break;
+
+ case MAILMIME_COMPOSITE_TYPE_MESSAGE:
+ if (strcasecmp(content->ct_subtype, "rfc822") == 0)
+ mime_type = MAILMIME_MESSAGE;
+ else
+ mime_type = MAILMIME_SINGLE;
+ break;
+
+ default:
+ goto err;
+ }
+ break;
+
+ default:
+ goto err;
+ }
+ }
+
+ if (mime_type == MAILMIME_MULTIPLE) {
+ char * attr_name;
+ char * attr_value;
+ struct mailmime_parameter * param;
+ clist * parameters;
+ char * boundary;
+
+ list = clist_new();
+ if (list == NULL)
+ goto err;
+
+ attr_name = strdup("boundary");
+ if (attr_name == NULL)
+ goto free_list;
+
+ boundary = generate_boundary(boundary_prefix);
+ attr_value = boundary;
+ if (attr_name == NULL) {
+ free(attr_name);
+ goto free_list;
+ }
+
+ param = mailmime_parameter_new(attr_name, attr_value);
+ if (param == NULL) {
+ free(attr_value);
+ free(attr_name);
+ goto free_list;
+ }
+
+ if (content->ct_parameters == NULL) {
+ parameters = clist_new();
+ if (parameters == NULL) {
+ mailmime_parameter_free(param);
+ goto free_list;
+ }
+ }
+ else
+ parameters = content->ct_parameters;
+
+ r = clist_append(parameters, param);
+ if (r != 0) {
+ clist_free(parameters);
+ mailmime_parameter_free(param);
+ goto free_list;
+ }
+
+ if (content->ct_parameters == NULL)
+ content->ct_parameters = parameters;
+ }
+
+ build_info = mailmime_new(mime_type,
+ NULL, 0, mime_fields, content,
+ NULL, NULL, NULL, list,
+ NULL, NULL);
+ if (build_info == NULL) {
+ clist_free(list);
+ return NULL;
+ }
+
+ return build_info;
+
+free_list:
+ clist_free(list);
+err:
+ return NULL;
+}
+
+struct mailmime * part_multiple_new(const char * type, const char * boundary_prefix)
+{
+ struct mailmime_fields * mime_fields;
+ struct mailmime_content * content;
+ struct mailmime * mp;
+
+ mime_fields = mailmime_fields_new_empty();
+ if (mime_fields == NULL)
+ goto err;
+
+ content = mailmime_content_new_with_str(type);
+ if (content == NULL)
+ goto free_fields;
+
+ mp = part_new_empty(content, mime_fields, boundary_prefix, 0);
+ if (mp == NULL)
+ goto free_content;
+
+ return mp;
+
+free_content:
+ mailmime_content_free(content);
+free_fields:
+ mailmime_fields_free(mime_fields);
+err:
+ return NULL;
+}
+
+#define MAX_MESSAGE_ID 512
+
+static char * generate_boundary(const char * boundary_prefix)
+{
+ char id[MAX_MESSAGE_ID];
+ time_t now;
+ char name[MAX_MESSAGE_ID];
+ long value;
+
+ now = time(NULL);
+ value = random();
+
+ gethostname(name, MAX_MESSAGE_ID);
+
+ if (boundary_prefix == NULL)
+ boundary_prefix = "";
+
+ snprintf(id, MAX_MESSAGE_ID, "%s%lx_%lx_%x", boundary_prefix, now, value, getpid());
+
+ return strdup(id);
+}
+
+void MessageBuilder::init()
+{
+ mHTMLBody = NULL;
+ mTextBody = NULL;
+ mAttachments = NULL;
+ mRelatedAttachments = NULL;
+ mBoundaryPrefix = NULL;
+}
+
+MessageBuilder::MessageBuilder()
+{
+ init();
+}
+
+MessageBuilder::MessageBuilder(MessageBuilder * other)
+{
+ init();
+ setHTMLBody(other->mHTMLBody);
+ setHTMLBody(other->mTextBody);
+ setAttachments(other->mAttachments);
+ setRelatedAttachments(other->mRelatedAttachments);
+ MC_SAFE_REPLACE_COPY(String, mBoundaryPrefix, other->mBoundaryPrefix);
+}
+
+MessageBuilder::~MessageBuilder()
+{
+ MC_SAFE_RELEASE(mHTMLBody);
+ MC_SAFE_RELEASE(mTextBody);
+ MC_SAFE_RELEASE(mAttachments);
+ MC_SAFE_RELEASE(mRelatedAttachments);
+ MC_SAFE_RELEASE(mBoundaryPrefix);
+}
+
+String * MessageBuilder::description()
+{
+ String * result = String::string();
+ result->appendUTF8Format("<%s:%p\n", className()->UTF8Characters(), this);
+ if (header() != NULL) {
+ result->appendString(header()->description());
+ result->appendUTF8Characters("\n");
+ }
+ if (mHTMLBody != NULL) {
+ result->appendUTF8Characters("-- html body --\n");
+ result->appendString(mHTMLBody);
+ result->appendUTF8Characters("\n");
+ }
+ if (mTextBody != NULL) {
+ result->appendUTF8Characters("-- text body --\n");
+ result->appendString(mTextBody);
+ result->appendUTF8Characters("\n");
+ }
+ if (mAttachments != NULL) {
+ result->appendUTF8Characters("-- attachments --\n");
+ result->appendString(mAttachments->description());
+ result->appendUTF8Characters("\n");
+ }
+ if (mRelatedAttachments != NULL) {
+ result->appendUTF8Characters("-- related attachments --\n");
+ result->appendString(mRelatedAttachments->description());
+ result->appendUTF8Characters("\n");
+ }
+ result->appendUTF8Characters(">");
+
+ return result;
+}
+
+#if 0
+String * MessageBuilder::className()
+{
+ return MCSTR("MessageBuilder");
+}
+#endif
+
+Object * MessageBuilder::copy()
+{
+ return new MessageBuilder(this);
+}
+
+void MessageBuilder::setHTMLBody(String * htmlBody)
+{
+ MC_SAFE_REPLACE_COPY(String, mHTMLBody, htmlBody);
+}
+
+String * MessageBuilder::htmlBody()
+{
+ return mHTMLBody;
+}
+
+void MessageBuilder::setTextBody(String * textBody)
+{
+ MC_SAFE_REPLACE_COPY(String, mTextBody, textBody);
+}
+
+String * MessageBuilder::textBody()
+{
+ return mTextBody;
+}
+
+void MessageBuilder::setAttachments(Array * attachments)
+{
+ if (attachments != NULL) {
+ for(unsigned int i = 0 ; i < attachments->count() ; i ++) {
+ Attachment * attachment = (Attachment *) attachments->objectAtIndex(i);
+ attachment->setMessage(this);
+ }
+ }
+ MC_SAFE_REPLACE_COPY(Array, mAttachments, attachments);
+}
+
+Array * MessageBuilder::attachments()
+{
+ return mAttachments;
+}
+
+void MessageBuilder::addAttachment(Attachment * attachment)
+{
+ if (mAttachments == NULL) {
+ mAttachments = new Array();
+ }
+ attachment->setMessage(this);
+ mAttachments->addObject(attachment);
+}
+
+void MessageBuilder::setRelatedAttachments(Array * attachments)
+{
+ if (attachments != NULL) {
+ for(unsigned int i = 0 ; i < attachments->count() ; i ++) {
+ Attachment * attachment = (Attachment *) attachments->objectAtIndex(i);
+ attachment->setMessage(this);
+ }
+ }
+ MC_SAFE_REPLACE_COPY(Array, mRelatedAttachments, attachments);
+}
+
+Array * MessageBuilder::relatedAttachments()
+{
+ return mRelatedAttachments;
+}
+
+void MessageBuilder::addRelatedAttachment(Attachment * attachment)
+{
+ if (mRelatedAttachments == NULL) {
+ mRelatedAttachments = new Array();
+ }
+ attachment->setMessage(this);
+ mRelatedAttachments->addObject(attachment);
+}
+
+void MessageBuilder::setBoundaryPrefix(String * boundaryPrefix)
+{
+ MC_SAFE_REPLACE_COPY(String, mBoundaryPrefix, boundaryPrefix);
+}
+
+String * MessageBuilder::boundaryPrefix()
+{
+ return mBoundaryPrefix;
+}
+
+Data * MessageBuilder::dataAndFilterBcc(bool filterBcc)
+{
+ Data * data;
+ MMAPString * str;
+ int col;
+
+ struct mailmime * htmlPart;
+ struct mailmime * textPart;
+ struct mailmime * altPart;
+ struct mailmime * mainPart;
+
+ htmlPart = NULL;
+ textPart = NULL;
+ altPart = NULL;
+ mainPart = NULL;
+
+ if (htmlBody() != NULL) {
+ Attachment * htmlAttachment;
+
+ htmlAttachment = Attachment::attachmentWithHTMLString(htmlBody());
+ htmlPart = multipart_related_from_attachments(htmlAttachment, mRelatedAttachments,
+ MMCUTF8(mBoundaryPrefix));
+ }
+
+ if (textBody() != NULL) {
+ Attachment * textAttachment;
+
+ textAttachment = Attachment::attachmentWithText(textBody());
+ textPart = mime_from_attachment(textAttachment);
+ }
+ else if (htmlBody() != NULL) {
+ Attachment * textAttachment;
+
+ textAttachment = Attachment::attachmentWithText(htmlBody()->flattenHTML());
+ textPart = mime_from_attachment(textAttachment);
+ }
+
+ if ((textPart != NULL) && (htmlPart != NULL)) {
+ altPart = get_multipart_alternative(MMCUTF8(mBoundaryPrefix));
+ mailmime_smart_add_part(altPart, textPart);
+ mailmime_smart_add_part(altPart, htmlPart);
+ mainPart = altPart;
+ }
+ else if (textPart != NULL) {
+ mainPart = textPart;
+ }
+ else if (htmlPart != NULL) {
+ mainPart = htmlPart;
+ }
+
+ struct mailimf_fields * fields;
+ unsigned int i;
+ struct mailmime * mime;
+
+ fields = header()->createIMFFieldsAndFilterBcc(filterBcc);
+
+ mime = mailmime_new_message_data(NULL);
+ mailmime_set_imf_fields(mime, fields);
+
+ if (mainPart != NULL) {
+ add_attachment(mime, mainPart, MMCUTF8(mBoundaryPrefix));
+ }
+
+ if (attachments() != NULL) {
+ for(i = 0 ; i < attachments()->count() ; i ++) {
+ Attachment * attachment;
+ struct mailmime * submime;
+
+ attachment = (Attachment *) attachments()->objectAtIndex(i);
+ submime = mime_from_attachment(attachment);
+ add_attachment(mime, submime, MMCUTF8(mBoundaryPrefix));
+ }
+ }
+
+ str = mmap_string_new("");
+ col = 0;
+ mailmime_write_mem(str, &col, mime);
+ data = Data::dataWithBytes(str->str, (unsigned int) str->len);
+ mmap_string_free(str);
+ mailmime_free(mime);
+
+ return data;
+}
+
+Data * MessageBuilder::data()
+{
+ return dataAndFilterBcc(false);
+}
diff --git a/src/core/rfc822/MCMessageBuilder.h b/src/core/rfc822/MCMessageBuilder.h
new file mode 100644
index 00000000..fd05f3dc
--- /dev/null
+++ b/src/core/rfc822/MCMessageBuilder.h
@@ -0,0 +1,55 @@
+#ifndef __MAILCORE_MCMESSAGEBUILDER_H_
+
+#define __MAILCORE_MCMESSAGEBUILDER_H_
+
+#include <mailcore/MCBaseTypes.h>
+#include <mailcore/MCAbstractMessage.h>
+
+namespace mailcore {
+
+ class Attachment;
+
+ class MessageBuilder : public AbstractMessage {
+ private:
+ String * mHTMLBody;
+ String * mTextBody;
+ Array * mAttachments;
+ Array * mRelatedAttachments;
+ String * mBoundaryPrefix;
+ void init();
+ Data * dataAndFilterBcc(bool filterBcc);
+
+ public:
+ MessageBuilder();
+ MessageBuilder(MessageBuilder * other);
+ virtual ~MessageBuilder();
+
+ virtual String * description();
+ //virtual String * className();
+ virtual Object * copy();
+
+ virtual void setHTMLBody(String * htmlBody);
+ virtual String * htmlBody();
+
+ virtual void setTextBody(String * textBody);
+ virtual String * textBody();
+
+ virtual void setAttachments(Array * /* Attachment */ attachments);
+ virtual Array * /* Attachment */ attachments();
+ virtual void addAttachment(Attachment * attachment);
+
+ // attachments (usually images) that are included in HTML.
+ virtual void setRelatedAttachments(Array * /* Attachment */ attachments);
+ virtual Array * /* Attachment */ relatedAttachments();
+ virtual void addRelatedAttachment(Attachment * attachment);
+
+ // When boundary needs to be prefixed (to go through spam filters).
+ virtual void setBoundaryPrefix(String * boundaryPrefix);
+ virtual String * boundaryPrefix();
+
+ virtual Data * data();
+ };
+
+};
+
+#endif
diff --git a/src/core/rfc822/MCMessageParser.cc b/src/core/rfc822/MCMessageParser.cc
new file mode 100644
index 00000000..f301ce3e
--- /dev/null
+++ b/src/core/rfc822/MCMessageParser.cc
@@ -0,0 +1,82 @@
+#include "MCMessageParser.h"
+
+#include "MCAttachment.h"
+#include "MCMessageHeader.h"
+
+using namespace mailcore;
+
+MessageParser * MessageParser::messageParserWithData(Data * data)
+{
+ MessageParser * parser = new MessageParser(data);
+ return (MessageParser *) parser->autorelease();
+}
+
+void MessageParser::init()
+{
+ mData = NULL;
+ mMainPart = NULL;
+}
+
+MessageParser::MessageParser(Data * data)
+{
+ init();
+ mData = (Data *) data->retain();
+
+ mailmessage * msg;
+ struct mailmime * mime;
+
+ msg = data_message_init(data->bytes(), data->length());
+ mailmessage_get_bodystructure(msg, &mime);
+ mMainPart = (AbstractPart *) Attachment::attachmentsWithMIME(msg->msg_mime)->retain();
+ MCLog("%s:%p ", MCUTF8(mMainPart->className()), mMainPart);
+ MCLog("%s:%p ", MCUTF8(mMainPart->description()), mMainPart);
+ mMainPart->setMessage(this);
+ header()->importIMFFields(msg->msg_fields);
+ mailmessage_free(msg);
+}
+
+MessageParser::MessageParser(MessageParser * other)
+{
+ init();
+ MC_SAFE_REPLACE_RETAIN(Data, mData, other->mData);
+ MC_SAFE_REPLACE_RETAIN(AbstractPart, mMainPart, other->mMainPart);
+}
+
+MessageParser::~MessageParser()
+{
+ MC_SAFE_RELEASE(mMainPart);
+ MC_SAFE_RELEASE(mData);
+}
+
+AbstractPart * MessageParser::mainPart()
+{
+ return mMainPart;
+}
+
+Data * MessageParser::data()
+{
+ return mData;
+}
+
+String * MessageParser::description()
+{
+ String * result = String::string();
+ result->appendUTF8Format("<%s:%p ", MCUTF8(className()), this);
+ result->appendUTF8Format("<%p>", mMainPart);
+ result->appendString(mMainPart->description());
+ result->appendUTF8Characters(">");
+
+ return result;
+}
+
+#if 0
+String * MessageParser::className()
+{
+ return MCSTR("MessageParser");
+}
+#endif
+
+Object * MessageParser::copy()
+{
+ return new MessageParser(this);
+}
diff --git a/src/core/rfc822/MCMessageParser.h b/src/core/rfc822/MCMessageParser.h
new file mode 100644
index 00000000..a3ece61c
--- /dev/null
+++ b/src/core/rfc822/MCMessageParser.h
@@ -0,0 +1,34 @@
+#ifndef __MAILCORE_MCPARSEDMESSAGE_H_
+
+#define __MAILCORE_MCPARSEDMESSAGE_H_
+
+#include <mailcore/MCBaseTypes.h>
+#include <mailcore/MCAbstractMessage.h>
+#include <mailcore/MCAbstractPart.h>
+
+namespace mailcore {
+
+ class MessageParser : public AbstractMessage {
+ private:
+ Data * mData;
+ AbstractPart * mMainPart;
+ void init();
+
+ public:
+ static MessageParser * messageParserWithData(Data * data);
+
+ MessageParser(Data * data);
+ MessageParser(MessageParser * other);
+ virtual ~MessageParser();
+
+ virtual String * description();
+ //virtual String * className();
+ virtual Object * copy();
+
+ virtual AbstractPart * mainPart();
+ virtual Data * data();
+ };
+
+};
+
+#endif
diff --git a/src/core/rfc822/MCMessagePart.cc b/src/core/rfc822/MCMessagePart.cc
new file mode 100644
index 00000000..8a2122c3
--- /dev/null
+++ b/src/core/rfc822/MCMessagePart.cc
@@ -0,0 +1,27 @@
+#include "MCMessagePart.h"
+
+using namespace mailcore;
+
+MessagePart::MessagePart()
+{
+}
+
+MessagePart::MessagePart(MessagePart * other) : AbstractMessagePart(other)
+{
+}
+
+MessagePart::~MessagePart()
+{
+}
+
+#if 0
+String * MessagePart::className()
+{
+ return MCSTR("MessagePart");
+}
+#endif
+
+Object * MessagePart::copy()
+{
+ return new MessagePart(this);
+}
diff --git a/src/core/rfc822/MCMessagePart.h b/src/core/rfc822/MCMessagePart.h
new file mode 100644
index 00000000..3f20b3a8
--- /dev/null
+++ b/src/core/rfc822/MCMessagePart.h
@@ -0,0 +1,22 @@
+#ifndef __MAILCORE_MCMESSAGEPART_H_
+
+#define __MAILCORE_MCMESSAGEPART_H_
+
+#include <mailcore/MCBaseTypes.h>
+#include <mailcore/MCAbstractMessagePart.h>
+
+namespace mailcore {
+
+ class MessagePart : public AbstractMessagePart {
+ public:
+ MessagePart();
+ MessagePart(MessagePart * other);
+ virtual ~MessagePart();
+
+ //virtual String * className();
+ virtual Object * copy();
+ };
+}
+
+
+#endif
diff --git a/src/core/rfc822/MCMultipart.cc b/src/core/rfc822/MCMultipart.cc
new file mode 100644
index 00000000..6ab1f0db
--- /dev/null
+++ b/src/core/rfc822/MCMultipart.cc
@@ -0,0 +1,28 @@
+#include "MCMultipart.h"
+
+using namespace mailcore;
+
+Multipart::Multipart()
+{
+}
+
+Multipart::Multipart(Multipart * other) : AbstractMultipart(other)
+{
+}
+
+Multipart::~Multipart()
+{
+}
+
+#if 0
+String * Multipart::className()
+{
+ return MCSTR("Multipart");
+}
+#endif
+
+Object * Multipart::copy()
+{
+ return new Multipart(this);
+}
+
diff --git a/src/core/rfc822/MCMultipart.h b/src/core/rfc822/MCMultipart.h
new file mode 100644
index 00000000..bdd71c48
--- /dev/null
+++ b/src/core/rfc822/MCMultipart.h
@@ -0,0 +1,21 @@
+#ifndef __MAILCORE_MCMULTIPART_H
+
+#define __MAILCORE_MCMULTIPART_H
+
+#include <mailcore/MCBaseTypes.h>
+#include <mailcore/MCAbstractMultipart.h>
+
+namespace mailcore {
+
+ class Multipart : public AbstractMultipart {
+ public:
+ Multipart();
+ Multipart(Multipart * other);
+ virtual ~Multipart();
+
+ //virtual String * className();
+ virtual Object * copy();
+ };
+}
+
+#endif
diff --git a/src/core/rfc822/MCRFC822.h b/src/core/rfc822/MCRFC822.h
new file mode 100644
index 00000000..9eb381b8
--- /dev/null
+++ b/src/core/rfc822/MCRFC822.h
@@ -0,0 +1,11 @@
+#ifndef __MAILCORE_MCRFC822_H
+
+#define __MAILCORE_MCRFC822_H
+
+#include <mailcore/MCAttachment.h>
+#include <mailcore/MCMessageBuilder.h>
+#include <mailcore/MCMessageParser.h>
+#include <mailcore/MCMessagePart.h>
+#include <mailcore/MCMultipart.h>
+
+#endif
diff --git a/src/core/smtp/.DS_Store b/src/core/smtp/.DS_Store
new file mode 100644
index 00000000..5008ddfc
--- /dev/null
+++ b/src/core/smtp/.DS_Store
Binary files differ
diff --git a/src/core/smtp/MCSMTP.h b/src/core/smtp/MCSMTP.h
new file mode 100644
index 00000000..1f7d17d7
--- /dev/null
+++ b/src/core/smtp/MCSMTP.h
@@ -0,0 +1,8 @@
+#ifndef __MAILCORE_MCSMTP_H
+
+#define __MAILCORE_MCSMTP_H
+
+#include <mailcore/MCSMTPProgressCallback.h>
+#include <mailcore/MCSMTPSession.h>
+
+#endif
diff --git a/src/core/smtp/MCSMTPProgressCallback.h b/src/core/smtp/MCSMTPProgressCallback.h
new file mode 100644
index 00000000..2537c2c3
--- /dev/null
+++ b/src/core/smtp/MCSMTPProgressCallback.h
@@ -0,0 +1,15 @@
+#ifndef __MAILCORE_MCSMTPPROGRESSCALLBACK_H_
+
+#define __MAILCORE_MCSMTPPROGRESSCALLBACK_H_
+
+namespace mailcore {
+
+ class SMTPSession;
+
+ class SMTPProgressCallback {
+ public:
+ virtual void bodyProgress(SMTPSession * session, unsigned int current, unsigned int maximum) {};
+ };
+}
+
+#endif
diff --git a/src/core/smtp/MCSMTPSession.cc b/src/core/smtp/MCSMTPSession.cc
new file mode 100644
index 00000000..52851a08
--- /dev/null
+++ b/src/core/smtp/MCSMTPSession.cc
@@ -0,0 +1,656 @@
+#include "MCSMTPSession.h"
+
+#include <string.h>
+
+#include "MCAddress.h"
+#include "MCMessageBuilder.h"
+#include "MCMessageParser.h"
+#include "MCMessageHeader.h"
+#include "MCSMTPProgressCallback.h"
+
+using namespace mailcore;
+
+enum {
+ STATE_DISCONNECTED,
+ STATE_CONNECTED,
+ STATE_LOGGEDIN,
+};
+
+void SMTPSession::init()
+{
+ mHostname = NULL;
+ mPort = 0;
+ mUsername = NULL;
+ mPassword = NULL;
+ mAuthType = AuthTypeSASLNone;
+ mConnectionType = ConnectionTypeClear;
+ mTimeout = 30;
+ mCheckCertificateEnabled = true;
+ mUseHeloIPEnabled = false;
+
+ mSmtp = NULL;
+ mProgressCallback = NULL;
+ mState = STATE_DISCONNECTED;
+ mLastSMTPResponse = NULL;
+ mLastLibetpanError = 0;
+ mLastSMTPResponseCode = 0;
+}
+
+SMTPSession::SMTPSession()
+{
+ init();
+}
+
+SMTPSession::~SMTPSession()
+{
+ MCLog("dealloc");
+ MC_SAFE_RELEASE(mLastSMTPResponse);
+ MC_SAFE_RELEASE(mHostname);
+ MC_SAFE_RELEASE(mUsername);
+ MC_SAFE_RELEASE(mPassword);
+ MCLog("dealloc4");
+}
+
+#if 0
+String * SMTPSession::className()
+{
+ return MCSTR("SMTPSession");
+}
+#endif
+
+void SMTPSession::setHostname(String * hostname)
+{
+ MC_SAFE_REPLACE_COPY(String, mHostname, hostname);
+}
+
+String * SMTPSession::hostname()
+{
+ return mHostname;
+}
+
+void SMTPSession::setPort(unsigned int port)
+{
+ mPort = port;
+}
+
+unsigned int SMTPSession::port()
+{
+ return mPort;
+}
+
+void SMTPSession::setUsername(String * username)
+{
+ MC_SAFE_REPLACE_COPY(String, mUsername, username);
+}
+
+String * SMTPSession::username()
+{
+ return mUsername;
+}
+
+void SMTPSession::setPassword(String * password)
+{
+ MC_SAFE_REPLACE_COPY(String, mPassword, password);
+}
+
+String * SMTPSession::password()
+{
+ return mPassword;
+}
+
+void SMTPSession::setAuthType(AuthType authType)
+{
+ mAuthType = authType;
+}
+
+AuthType SMTPSession::authType()
+{
+ return mAuthType;
+}
+
+void SMTPSession::setConnectionType(ConnectionType connectionType)
+{
+ mConnectionType = connectionType;
+}
+
+ConnectionType SMTPSession::connectionType()
+{
+ return mConnectionType;
+}
+
+void SMTPSession::setTimeout(time_t timeout)
+{
+ mTimeout = timeout;
+}
+
+time_t SMTPSession::timeout()
+{
+ return mTimeout;
+}
+
+void SMTPSession::setCheckCertificateEnabled(bool enabled)
+{
+ mCheckCertificateEnabled = enabled;
+}
+
+bool SMTPSession::isCheckCertificateEnabled()
+{
+ return mCheckCertificateEnabled;
+}
+
+bool SMTPSession::checkCertificate()
+{
+ // XXX
+ return true;
+}
+
+void SMTPSession::setUseHeloIPEnabled(bool enabled)
+{
+ mUseHeloIPEnabled = enabled;
+}
+
+bool SMTPSession::useHeloIPEnabled()
+{
+ return mUseHeloIPEnabled;
+}
+
+void SMTPSession::body_progress(size_t current, size_t maximum, void * context)
+{
+ SMTPSession * session;
+
+ session = (SMTPSession *) context;
+ session->bodyProgress((unsigned int) current, (unsigned int) maximum);
+}
+
+void SMTPSession::bodyProgress(unsigned int current, unsigned int maximum)
+{
+ if (mProgressCallback != NULL) {
+ mProgressCallback->bodyProgress(this, current, maximum);
+ }
+}
+
+void SMTPSession::setup()
+{
+ mSmtp = mailsmtp_new(0, NULL);
+ mailsmtp_set_timeout(mSmtp, timeout());
+ mailsmtp_set_progress_callback(mSmtp, body_progress, this);
+}
+
+void SMTPSession::unsetup()
+{
+ mailsmtp_free(mSmtp);
+ mSmtp = NULL;
+}
+
+void SMTPSession::connectIfNeeded(ErrorCode * pError)
+{
+ if (mState == STATE_DISCONNECTED) {
+ connect(pError);
+ }
+ else {
+ * pError = ErrorNone;
+ }
+}
+
+void SMTPSession::connect(ErrorCode * pError)
+{
+ int r;
+
+ setup();
+
+ switch (mConnectionType) {
+ case ConnectionTypeStartTLS:
+ MCLog("connect %s %u", MCUTF8(hostname()), (unsigned int) port());
+ r = mailsmtp_socket_connect(mSmtp, MCUTF8(hostname()), port());
+ if (r != MAILSMTP_NO_ERROR) {
+ * pError = ErrorConnection;
+ return;
+ }
+
+ MCLog("init");
+ if (useHeloIPEnabled()) {
+ r = mailsmtp_init_with_ip(mSmtp, 1);
+ } else {
+ r = mailsmtp_init(mSmtp);
+ }
+ if (r == MAILSMTP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r != MAILSMTP_NO_ERROR) {
+ * pError = ErrorConnection;
+ return;
+ }
+
+ MCLog("start TLS");
+ r = mailsmtp_socket_starttls(mSmtp);
+ if (r != MAILSMTP_NO_ERROR) {
+ * pError = ErrorStartTLSNotAvailable;
+ return;
+ }
+ MCLog("done");
+ if (!checkCertificate()) {
+ * pError = ErrorCertificate;
+ return;
+ }
+
+ MCLog("init after starttls");
+ if (useHeloIPEnabled()) {
+ r = mailsmtp_init_with_ip(mSmtp, 1);
+ } else {
+ r = mailsmtp_init(mSmtp);
+ }
+ if (r == MAILSMTP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r != MAILSMTP_NO_ERROR) {
+ * pError = ErrorConnection;
+ return;
+ }
+
+ break;
+
+ case ConnectionTypeTLS:
+ r = mailsmtp_ssl_connect(mSmtp, MCUTF8(mHostname), port());
+ if (r != MAILSMTP_NO_ERROR) {
+ * pError = ErrorConnection;
+ return;
+ }
+ if (!checkCertificate()) {
+ * pError = ErrorCertificate;
+ return;
+ }
+
+ MCLog("init");
+ if (useHeloIPEnabled()) {
+ r = mailsmtp_init_with_ip(mSmtp, 1);
+ } else {
+ r = mailsmtp_init(mSmtp);
+ }
+ if (r == MAILSMTP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r != MAILSMTP_NO_ERROR) {
+ * pError = ErrorConnection;
+ return;
+ }
+
+ break;
+
+ default:
+ r = mailsmtp_socket_connect(mSmtp, MCUTF8(hostname()), port());
+ if (r != MAILIMAP_NO_ERROR) {
+ * pError = ErrorConnection;
+ return;
+ }
+
+ MCLog("init");
+ if (useHeloIPEnabled()) {
+ r = mailsmtp_init_with_ip(mSmtp, 1);
+ } else {
+ r = mailsmtp_init(mSmtp);
+ }
+ if (r == MAILSMTP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r != MAILSMTP_NO_ERROR) {
+ * pError = ErrorConnection;
+ return;
+ }
+
+ break;
+ }
+
+ mailstream_low * low;
+ String * identifierString;
+ char * identifier;
+
+ low = mailstream_get_low(mSmtp->stream);
+ if (mUsername != NULL) {
+ identifierString = String::stringWithUTF8Format("%s@%s:%u", MCUTF8(mUsername), MCUTF8(mHostname), port());
+ }
+ else {
+ identifierString = String::stringWithUTF8Format("%s:%u", MCUTF8(mHostname), port());
+ }
+ identifier = strdup(identifierString->UTF8Characters());
+ mailstream_low_set_identifier(low, identifier);
+
+ mState = STATE_CONNECTED;
+ * pError = ErrorNone;
+}
+
+void SMTPSession::disconnect()
+{
+ if (mSmtp == NULL)
+ return;
+
+ mailsmtp_quit(mSmtp);
+
+ unsetup();
+
+ mState = STATE_DISCONNECTED;
+}
+
+void SMTPSession::loginIfNeeded(ErrorCode * pError)
+{
+ connectIfNeeded(pError);
+ if (* pError != ErrorNone)
+ return;
+
+ if (mState == STATE_CONNECTED) {
+ login(pError);
+ }
+ else {
+ * pError = ErrorNone;
+ }
+}
+
+void SMTPSession::login(ErrorCode * pError)
+{
+ int r;
+
+ if ((username() == NULL) || (password() == NULL)) {
+ mState = STATE_LOGGEDIN;
+ * pError = ErrorNone;
+ return;
+ }
+
+ if (authType() == 0) {
+ if (mSmtp->auth & MAILSMTP_AUTH_DIGEST_MD5) {
+ setAuthType((AuthType) (authType() | AuthTypeSASLDIGESTMD5));
+ }
+ else if (mSmtp->auth & MAILSMTP_AUTH_CRAM_MD5) {
+ setAuthType((AuthType) (authType() | AuthTypeSASLCRAMMD5));
+ }
+ else if (mSmtp->auth & MAILSMTP_AUTH_GSSAPI) {
+ setAuthType((AuthType) (authType() | AuthTypeSASLGSSAPI));
+ }
+ else if (mSmtp->auth & MAILSMTP_AUTH_SRP) {
+ setAuthType((AuthType) (authType() | AuthTypeSASLSRP));
+ }
+ else if (mSmtp->auth & MAILSMTP_AUTH_NTLM) {
+ setAuthType((AuthType) (authType() | AuthTypeSASLNTLM));
+ }
+ else if (mSmtp->auth & MAILSMTP_AUTH_KERBEROS_V4) {
+ setAuthType((AuthType) (authType() | AuthTypeSASLKerberosV4));
+ }
+ else if (mSmtp->auth & MAILSMTP_AUTH_PLAIN) {
+ setAuthType((AuthType) (authType() | AuthTypeSASLPlain));
+ }
+ else if (mSmtp->auth & MAILSMTP_AUTH_LOGIN) {
+ setAuthType((AuthType) (authType() | AuthTypeSASLLogin));
+ }
+ }
+
+ switch (authType()) {
+ case 0:
+ default:
+ r = mailesmtp_auth_sasl(mSmtp, "PLAIN",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ MCUTF8(mUsername), MCUTF8(mUsername),
+ MCUTF8(mPassword), NULL);
+ break;
+
+ case AuthTypeSASLCRAMMD5:
+ r = mailesmtp_auth_sasl(mSmtp, "CRAM-MD5",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ MCUTF8(mUsername), MCUTF8(mUsername),
+ MCUTF8(mPassword), NULL);
+ break;
+
+ case AuthTypeSASLPlain:
+ r = mailesmtp_auth_sasl(mSmtp, "PLAIN",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ MCUTF8(mUsername), MCUTF8(mUsername),
+ MCUTF8(mPassword), NULL);
+ break;
+
+ case AuthTypeSASLGSSAPI:
+ // needs to be tested
+ r = mailesmtp_auth_sasl(mSmtp, "GSSAPI",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ MCUTF8(mUsername), MCUTF8(mUsername),
+ MCUTF8(mPassword), NULL);
+ break;
+
+ case AuthTypeSASLDIGESTMD5:
+ r = mailesmtp_auth_sasl(mSmtp, "DIGEST-MD5",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ MCUTF8(mUsername), MCUTF8(mUsername),
+ MCUTF8(mPassword), NULL);
+ break;
+
+ case AuthTypeSASLLogin:
+ r = mailesmtp_auth_sasl(mSmtp, "LOGIN",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ MCUTF8(mUsername), MCUTF8(mUsername),
+ MCUTF8(mPassword), NULL);
+ break;
+
+ case AuthTypeSASLSRP:
+ r = mailesmtp_auth_sasl(mSmtp, "SRP",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ MCUTF8(mUsername), MCUTF8(mUsername),
+ MCUTF8(mPassword), NULL);
+ break;
+
+ case AuthTypeSASLNTLM:
+ r = mailesmtp_auth_sasl(mSmtp, "NTLM",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ MCUTF8(mUsername), MCUTF8(mUsername),
+ MCUTF8(mPassword), NULL /* realm */);
+ break;
+
+ case AuthTypeSASLKerberosV4:
+ r = mailesmtp_auth_sasl(mSmtp, "KERBEROS_V4",
+ MCUTF8(mHostname),
+ NULL,
+ NULL,
+ MCUTF8(mUsername), MCUTF8(mUsername),
+ MCUTF8(mPassword), NULL /* realm */);
+ break;
+ }
+ if (r == MAILSMTP_ERROR_STREAM) {
+ * pError = ErrorConnection;
+ return;
+ }
+ else if (r != MAILSMTP_NO_ERROR) {
+ * pError = ErrorAuthentication;
+ return;
+ }
+
+ mState = STATE_LOGGEDIN;
+ * pError = ErrorNone;
+}
+
+void SMTPSession::sendMessage(Address * from, Array * recipients, Data * messageData,
+ SMTPProgressCallback * callback, ErrorCode * pError)
+{
+ clist * address_list;
+ int r;
+
+ messageData = dataWithFilteredBcc(messageData);
+
+ mProgressCallback = callback;
+ bodyProgress(0, messageData->length());
+
+ MCLog("setup");
+
+ MCLog("connect");
+ loginIfNeeded(pError);
+ if (* pError != ErrorNone) {
+ goto err;
+ }
+
+ // disable DSN feature for more compatibility
+ mSmtp->esmtp &= ~MAILSMTP_ESMTP_DSN;
+
+ address_list = esmtp_address_list_new();
+ for(unsigned int i = 0 ; i < recipients->count() ; i ++) {
+ Address * addr = (Address *) recipients->objectAtIndex(i);
+ esmtp_address_list_add(address_list, (char *) MCUTF8(addr->mailbox()), 0, NULL);
+ }
+ MCLog("send");
+ if ((mSmtp->esmtp & MAILSMTP_ESMTP_PIPELINING) != 0) {
+ r = mailesmtp_send_quit(mSmtp, MCUTF8(from->mailbox()), 0, NULL,
+ address_list,
+ messageData->bytes(), messageData->length());
+ }
+ else {
+ r = mailesmtp_send(mSmtp, MCUTF8(from->mailbox()), 0, NULL,
+ address_list,
+ messageData->bytes(), messageData->length());
+ }
+ esmtp_address_list_free(address_list);
+
+ String * response;
+ int responseCode;
+
+ response = NULL;
+ if (mSmtp->response != NULL) {
+ response = String::stringWithUTF8Characters(mSmtp->response);
+ }
+ responseCode = mSmtp->response_code;
+
+ if ((r == MAILSMTP_ERROR_STREAM) || (r == MAILSMTP_ERROR_CONNECTION_REFUSED)) {
+ * pError = ErrorConnection;
+ goto err;
+ }
+ else if (r == MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION) {
+ if (response->locationOfString(MCSTR("5.7.0")) != -1) {
+ * pError = ErrorSendMessageIllegalAttachment;
+ }
+ else {
+ * pError = ErrorStorageLimit;
+ }
+ goto err;
+ }
+ else if (r == MAILSMTP_ERROR_MAILBOX_UNAVAILABLE) {
+ * pError = ErrorSendMessageNotAllowed;
+ goto err;
+ }
+ else if (r == MAILSMTP_ERROR_AUTH_REQUIRED) {
+ * pError = ErrorAuthenticationRequired;
+ goto err;
+ }
+ else if (r != MAILSMTP_NO_ERROR) {
+ if ((responseCode == 550) && (response->hasPrefix(MCSTR("5.3.4")))) {
+ * pError = ErrorNeedsConnectToWebmail;
+ goto err;
+ }
+ else {
+ * pError = ErrorSendMessage;
+ MC_SAFE_REPLACE_COPY(String, mLastSMTPResponse, response);
+ mLastLibetpanError = r;
+ mLastSMTPResponseCode = responseCode;
+ goto err;
+ }
+ }
+
+ bodyProgress(messageData->length(), messageData->length());
+ * pError = ErrorNone;
+
+ err:
+ mProgressCallback = NULL;
+}
+
+Data * SMTPSession::dataWithFilteredBcc(Data * data)
+{
+ int r;
+ size_t idx;
+ struct mailimf_message * msg;
+ MMAPString * str;
+
+ idx = 0;
+ r = mailimf_message_parse(data->bytes(), data->length(), &idx, &msg);
+ if (r != MAILIMF_NO_ERROR) {
+ return Data::data();
+ }
+
+ struct mailimf_fields * fields = msg->msg_fields;
+ int col = 0;
+
+ str = mmap_string_new("");
+ for(clistiter * cur = clist_begin(fields->fld_list) ; cur != NULL ; cur = clist_next(cur)) {
+ struct mailimf_field * field = (struct mailimf_field *) clist_content(cur);
+ if (field->fld_type == MAILIMF_FIELD_BCC) {
+ mailimf_field_free(field);
+ clist_delete(fields->fld_list, cur);
+ break;
+ }
+ }
+ mailimf_fields_write_mem(str, &col, fields);
+ mmap_string_append(str, "\n");
+ mmap_string_append_len(str, msg->msg_body->bd_text, msg->msg_body->bd_size);
+
+ Data * result = Data::dataWithBytes(str->str, (unsigned int) str->len);
+
+ mmap_string_free(str);
+ mailimf_message_free(msg);
+
+ return result;
+}
+
+void SMTPSession::sendMessage(Data * messageData, SMTPProgressCallback * callback, ErrorCode * pError)
+{
+ AutoreleasePool * pool = new AutoreleasePool();
+ MessageParser * parser = new MessageParser(messageData);
+ Array * recipients = new Array();
+
+ if (parser->header()->to() != NULL) {
+ recipients->addObjectsFromArray(parser->header()->to());
+ }
+ if (parser->header()->cc() != NULL) {
+ recipients->addObjectsFromArray(parser->header()->cc());
+ }
+ if (parser->header()->bcc() != NULL) {
+ recipients->addObjectsFromArray(parser->header()->bcc());
+ }
+ Address * from = parser->header()->from();
+
+ sendMessage(from, recipients, messageData, callback, pError);
+
+ recipients->release();
+ parser->release();
+ pool->release();
+}
+
+void SMTPSession::sendMessage(MessageBuilder * msg, SMTPProgressCallback * callback, ErrorCode * pError)
+{
+ Array * recipients = new Array();
+ if (msg->header()->to() != NULL) {
+ recipients->addObjectsFromArray(msg->header()->to());
+ }
+ if (msg->header()->cc() != NULL) {
+ recipients->addObjectsFromArray(msg->header()->cc());
+ }
+ if (msg->header()->bcc() != NULL) {
+ recipients->addObjectsFromArray(msg->header()->bcc());
+ }
+ Address * from = msg->header()->from();
+ Data * data = msg->data();
+ MCAssert(from != NULL);
+ MCAssert(recipients->count() > 0);
+ sendMessage(from, recipients, data, callback, pError);
+ recipients->release();
+}
+
diff --git a/src/core/smtp/MCSMTPSession.h b/src/core/smtp/MCSMTPSession.h
new file mode 100644
index 00000000..45a7c54b
--- /dev/null
+++ b/src/core/smtp/MCSMTPSession.h
@@ -0,0 +1,90 @@
+#ifndef __MAILCORE_MCSMTPSESSION_H
+
+#define __MAILCORE_MCSMTPSESSION_H
+
+#include <mailcore/MCBaseTypes.h>
+#include <mailcore/MCMessageConstants.h>
+#include <libetpan/libetpan.h>
+
+namespace mailcore {
+
+ class Address;
+ class SMTPProgressCallback;
+ class MessageBuilder;
+
+ class SMTPSession : public Object {
+ private:
+ String * mHostname;
+ unsigned int mPort;
+ String * mUsername;
+ String * mPassword;
+ AuthType mAuthType;
+ ConnectionType mConnectionType;
+ time_t mTimeout;
+ bool mCheckCertificateEnabled;
+ bool mUseHeloIPEnabled;
+
+ mailsmtp * mSmtp;
+ SMTPProgressCallback * mProgressCallback;
+ int mState;
+ String * mLastSMTPResponse;
+ int mLastLibetpanError;
+ int mLastSMTPResponseCode;
+
+ void init();
+ Data * dataWithFilteredBcc(Data * data);
+ static void body_progress(size_t current, size_t maximum, void * context);
+ void bodyProgress(unsigned int current, unsigned int maximum);
+ void setup();
+ void unsetup();
+ void connectIfNeeded(ErrorCode * pError);
+ void loginIfNeeded(ErrorCode * pError);
+ bool checkCertificate();
+
+ public:
+ SMTPSession();
+ virtual ~SMTPSession();
+
+ //virtual String * className();
+
+ virtual void setHostname(String * hostname);
+ virtual String * hostname();
+
+ virtual void setPort(unsigned int port);
+ virtual unsigned int port();
+
+ virtual void setUsername(String * username);
+ virtual String * username();
+
+ virtual void setPassword(String * password);
+ virtual String * password();
+
+ virtual void setAuthType(AuthType authType);
+ virtual AuthType authType();
+
+ virtual void setConnectionType(ConnectionType connectionType);
+ virtual ConnectionType connectionType();
+
+ virtual void setTimeout(time_t timeout);
+ virtual time_t timeout();
+
+ virtual void setCheckCertificateEnabled(bool enabled);
+ virtual bool isCheckCertificateEnabled();
+
+ virtual void setUseHeloIPEnabled(bool enabled);
+ virtual bool useHeloIPEnabled();
+
+ virtual void connect(ErrorCode * pError);
+ virtual void disconnect();
+
+ virtual void login(ErrorCode * pError);
+
+ virtual void sendMessage(Address * from, Array * recipients, Data * messageData,
+ SMTPProgressCallback * callback, ErrorCode * pError);
+ virtual void sendMessage(Data * messageData, SMTPProgressCallback * callback, ErrorCode * pError);
+ virtual void sendMessage(MessageBuilder * msg, SMTPProgressCallback * callback, ErrorCode * pError);
+ };
+
+}
+
+#endif
diff --git a/src/mailcore.h b/src/mailcore.h
new file mode 100644
index 00000000..f4198e6d
--- /dev/null
+++ b/src/mailcore.h
@@ -0,0 +1,14 @@
+//
+// mailcore.h
+// mailcore2
+//
+// Created by DINH Viêt Hoà on 1/10/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#ifndef mailcore2_mailcore_h
+#define mailcore2_mailcore_h
+
+#include <mailcore/MCCore.h>
+
+#endif
diff --git a/tests/main.mm b/tests/main.mm
new file mode 100644
index 00000000..db73c89b
--- /dev/null
+++ b/tests/main.mm
@@ -0,0 +1,187 @@
+//
+// main.m
+// tests
+//
+// Created by DINH Viêt Hoà on 1/10/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#include <unicode/putil.h>
+#include <unicode/uclean.h>
+#include <unicode/ucnv.h>
+#include <mailcore/mailcore.h>
+
+extern "C" {
+ extern int mailstream_debug;
+}
+
+static mailcore::String * password = NULL;
+static mailcore::String * displayName = NULL;
+static mailcore::String * email = NULL;
+
+class TestOperation : public mailcore::Operation {
+ void main()
+ {
+ MCLog("coin %p", this);
+ }
+};
+
+class TestCallback : public mailcore::Object, public mailcore::OperationCallback {
+ virtual void operationFinished(mailcore::Operation * op)
+ {
+ MCLog("callback coin %p %p %s", this, op, MCUTF8DESC(this));
+ }
+};
+
+static mailcore::Data * testMessageBuilder()
+{
+ mailcore::Address * address = new mailcore::Address();
+ address->setDisplayName(displayName);
+ address->setMailbox(email);
+
+ address->release();
+
+ mailcore::MessageBuilder * msg = new mailcore::MessageBuilder();
+
+ msg->header()->setFrom(mailcore::Address::addressWithDisplayName(displayName, email));
+ mailcore::Array * to = new mailcore::Array();
+ mailcore::Array * bcc = new mailcore::Array();
+ to->addObject(mailcore::Address::addressWithDisplayName(MCSTR("Foo Bar"), MCSTR("foobar@to-recipient.org")));
+ to->addObject(mailcore::Address::addressWithDisplayName(MCSTR("Other Recipient"), MCSTR("another-foobar@to-recipient.org")));
+ bcc->addObject(mailcore::Address::addressWithDisplayName(MCSTR("Hidden Recipient"), MCSTR("foobar@bcc-recipient.org")));
+ msg->header()->setTo(to);
+ msg->header()->setBcc(bcc);
+ to->release();
+ bcc->release();
+ msg->header()->setSubject(MCSTR("Mon projet d'été"));
+ msg->setHTMLBody(MCSTR("<div>Hello <img src=\"cid:1234\"></div>"));
+ msg->addAttachment(mailcore::Attachment::attachmentWithContentOfFile(MCSTR("first-filename")));
+ msg->addAttachment(mailcore::Attachment::attachmentWithContentOfFile(MCSTR("second-filename")));
+ mailcore::Attachment * attachment = mailcore::Attachment::attachmentWithContentOfFile(MCSTR("third-image-attachment"));
+ attachment->setContentID(MCSTR("1234"));
+ msg->addRelatedAttachment(attachment);
+
+ mailcore::Data * data = msg->data();
+
+ MCLog("%s", data->bytes());
+
+ msg->release();
+
+ return data;
+}
+
+static void testMessageParser(mailcore::Data * data)
+{
+ mailcore::MessageParser * parser = mailcore::MessageParser::messageParserWithData(data);
+ MCLog("%s", MCUTF8(parser->description()));
+}
+
+static void testIMAP()
+{
+ mailcore::IMAPSession * session;
+ mailcore::ErrorCode error;
+
+ session = new mailcore::IMAPSession();
+ session->setHostname(MCSTR("imap.gmail.com"));
+ session->setPort(993);
+ session->setUsername(email);
+ session->setPassword(password);
+ session->setConnectionType(mailcore::ConnectionTypeTLS);
+
+ mailcore::IMAPMessagesRequestKind requestKind = (mailcore::IMAPMessagesRequestKind)
+ (mailcore::IMAPMessagesRequestKindHeaders | mailcore::IMAPMessagesRequestKindStructure |
+ mailcore::IMAPMessagesRequestKindInternalDate | mailcore::IMAPMessagesRequestKindHeaderSubject |
+ mailcore::IMAPMessagesRequestKindFlags);
+ mailcore::Array * messages = session->fetchMessagesByUID(MCSTR("INBOX"),
+ requestKind, 1, 0, NULL, &error);
+ MCLog("%s", MCUTF8DESC(messages));
+
+ session->release();
+}
+
+static void testSMTP(mailcore::Data * data)
+{
+ mailcore::SMTPSession * smtp;
+ mailcore::ErrorCode error;
+
+ smtp = new mailcore::SMTPSession();
+
+ smtp->setHostname(MCSTR("smtp.gmail.com"));
+ smtp->setPort(25);
+ smtp->setUsername(email);
+ smtp->setPassword(password);
+ smtp->setConnectionType(mailcore::ConnectionTypeStartTLS);
+
+ smtp->sendMessage(data, NULL, &error);
+
+ smtp->release();
+}
+
+static void testPOP()
+{
+ mailcore::POPSession * session;
+ mailcore::ErrorCode error;
+
+ session = new mailcore::POPSession();
+ session->setHostname(MCSTR("pop.gmail.com"));
+ session->setPort(995);
+ session->setUsername(email);
+ session->setPassword(password);
+ session->setConnectionType(mailcore::ConnectionTypeTLS);
+
+ mailcore::Array * messages = session->fetchMessages(&error);
+ MCLog("%s", MCUTF8DESC(messages));
+
+ session->release();
+}
+
+void testAll()
+{
+ u_setDataDirectory("/usr/local/share/icu");
+
+ mailcore::AutoreleasePool * pool = new mailcore::AutoreleasePool();
+
+ mailstream_debug = 1;
+
+ mailcore::Data * data = testMessageBuilder();
+ testMessageParser(data);
+ testSMTP(data);
+ testIMAP();
+ testPOP();
+
+ mailcore::OperationQueue * queue = new mailcore::OperationQueue();
+
+ TestCallback * callback = new TestCallback();
+
+ for(unsigned int i = 0 ; i < 1 ; i ++) {
+ mailcore::Operation * op = new TestOperation();
+ op->setCallback(callback);
+ queue->addOperation(op);
+ op->release();
+ }
+
+ [[NSRunLoop currentRunLoop] run];
+
+ queue->release();
+
+ MCLog("pool release");
+ pool->release();
+}
+
+int main(int argc, const char * argv[])
+{
+
+ @autoreleasepool {
+
+ email = MCSTR("email@gmail.com");
+ password = MCSTR("MyP4ssw0rd");
+ displayName = MCSTR("My Email");
+
+ testAll();
+
+ }
+ return 0;
+}
+