aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/ui
diff options
context:
space:
mode:
authorGravatar Hoa V. DINH <dinh.viet.hoa@gmail.com>2013-03-27 08:46:25 -0700
committerGravatar Hoa V. DINH <dinh.viet.hoa@gmail.com>2013-03-27 08:46:25 -0700
commitf890e0daa7ca701b8c0db6c34177132c2bf6e8e9 (patch)
tree9028837686e353c23572276fd32145f464575e3e /src/ui
parent35cf435e289ae5de353a7b67b28a5d982c124d5d (diff)
Fixed cancellation of IMAP operations
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/mac/MCOCIDURLProtocol.h31
-rw-r--r--src/ui/mac/MCOCIDURLProtocol.mm148
-rw-r--r--src/ui/mac/MCOMessageView.h49
-rw-r--r--src/ui/mac/MCOMessageView.mm335
4 files changed, 563 insertions, 0 deletions
diff --git a/src/ui/mac/MCOCIDURLProtocol.h b/src/ui/mac/MCOCIDURLProtocol.h
new file mode 100644
index 00000000..cf0b5335
--- /dev/null
+++ b/src/ui/mac/MCOCIDURLProtocol.h
@@ -0,0 +1,31 @@
+//
+// MCTCIDURLProtocol.h
+// testUI
+//
+// Created by DINH Viêt Hoà on 1/22/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#include <mailcore/mailcore.h>
+
+@interface MCOCIDURLProtocol : NSURLProtocol
+
++ (void) registerProtocol;
+
++ (BOOL) isCID:(NSURL *)url;
++ (BOOL) isXMailcoreImage:(NSURL *)url;
+
+#ifdef __cplusplus
++ (void) startLoadingWithMessage:(MCOAbstractMessage *)message
+ partUniqueID:(NSString *)partUniqueID
+ data:(NSData *)data
+ request:(NSMutableURLRequest *)request;
+
++ (void) partDownloadedMessage:(MCOAbstractMessage *)message
+ partUniqueID:(NSString *)partUniqueID
+ data:(NSData *)data;
+#endif
+
+@end
diff --git a/src/ui/mac/MCOCIDURLProtocol.mm b/src/ui/mac/MCOCIDURLProtocol.mm
new file mode 100644
index 00000000..83730c9d
--- /dev/null
+++ b/src/ui/mac/MCOCIDURLProtocol.mm
@@ -0,0 +1,148 @@
+//
+// MCTCIDURLProtocol.m
+// testUI
+//
+// Created by DINH Viêt Hoà on 1/22/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#import "MCOCIDURLProtocol.h"
+
+#import "MCOMessageView.h"
+
+#define MCOCIDURLProtocolDownloadedNotification @"MCOCIDURLProtocolDownloadedNotification"
+
+@implementation MCOCIDURLProtocol
+
++ (void) registerProtocol
+{
+ static dispatch_once_t onceToken = 0;
+ dispatch_once(&onceToken, ^{
+ [NSURLProtocol registerClass:[MCOCIDURLProtocol class]];
+ });
+}
+
++ (BOOL) canInitWithRequest:(NSURLRequest *)theRequest
+{
+ if ([self isCID:[theRequest URL]])
+ return YES;
+ if ([self isXMailcoreImage:[theRequest URL]])
+ return YES;
+ return NO;
+}
+
++ (BOOL) isCID:(NSURL *)url
+{
+ NSString *theScheme = [url scheme];
+ if ([theScheme caseInsensitiveCompare:@"cid"] == NSOrderedSame)
+ return YES;
+ return NO;
+}
+
++ (BOOL) isXMailcoreImage:(NSURL *)url
+{
+ NSString *theScheme = [url scheme];
+ if ([theScheme caseInsensitiveCompare:@"x-mailcore-image"] == NSOrderedSame)
+ return YES;
+ return NO;
+}
+
++ (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request
+{
+ return request;
+}
+
+- (id) initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id < NSURLProtocolClient >)client
+{
+ self = [super initWithRequest:request cachedResponse:cachedResponse client:client];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_downloaded:) name:MCOCIDURLProtocolDownloadedNotification object:nil];
+ return self;
+}
+
+- (void) dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (NSString *) _partUniqueID
+{
+ return [NSURLProtocol propertyForKey:@"PartUniqueID" inRequest:[self request]];
+}
+
+- (NSData *) _data
+{
+ return [NSURLProtocol propertyForKey:@"Data" inRequest:[self request]];
+}
+
+- (MCOAbstractMessage *) _message
+{
+ return (MCOAbstractMessage *) [NSURLProtocol propertyForKey:@"Message" inRequest:[self request]];
+}
+
+- (void) startLoading
+{
+ //NSLog(@"waiting for %p %@", self, [self _partUniqueID]);
+ if ([self _data] != NULL) {
+ [[self class] partDownloadedMessage:[self _message] partUniqueID:[self _partUniqueID] data:[self _data]];
+ }
+}
+
+- (void) _downloaded:(NSNotification *)notification
+{
+ NSDictionary * userInfo = [notification userInfo];
+
+ //NSLog(@"downloaded?");
+ NSString * notifPartID = [userInfo objectForKey:@"PartUniqueID"];
+ MCOAbstractMessage * notifMessage = [userInfo objectForKey:@"Message"];
+ if (notifMessage != [self _message]) {
+ return;
+ }
+ if (![[self _partUniqueID] isEqualToString:notifPartID]) {
+ return;
+ }
+
+ //NSLog(@"downloaded2 %p %@", self, notifPartID);
+
+ NSData * data = [userInfo objectForKey:@"Data"];
+ NSURLResponse * response = [[NSURLResponse alloc] initWithURL:[[self request] URL] MIMEType:@"application/data"
+ expectedContentLength:[data length] textEncodingName:nil];
+ [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
+ [[self client] URLProtocol:self didLoadData:data];
+ [[self client] URLProtocolDidFinishLoading:self];
+ [response release];
+}
+
+- (void) stopLoading
+{
+}
+
++ (void) startLoadingWithMessage:(MCOAbstractMessage *)message
+ partUniqueID:(NSString *)partUniqueID
+ data:(NSData *)data
+ request:(NSMutableURLRequest *)request
+{
+ [NSURLProtocol setProperty:message
+ forKey:@"Message" inRequest:request];
+ if (data != NULL) {
+ [NSURLProtocol setProperty:data forKey:@"Data" inRequest:request];
+ }
+ [NSURLProtocol setProperty:partUniqueID forKey:@"PartUniqueID" inRequest:request];
+}
+
++ (void) partDownloadedMessage:(MCOAbstractMessage *)message
+ partUniqueID:(NSString *)partUniqueID
+ data:(NSData *)data
+{
+ NSMutableDictionary * userInfo = [[NSMutableDictionary alloc] init];
+ [userInfo setObject:message forKey:@"Message"];
+ [userInfo setObject:partUniqueID forKey:@"PartUniqueID"];
+ if (data != NULL) {
+ [userInfo setObject:data forKey:@"Data"];
+ }
+ [[NSNotificationCenter defaultCenter] postNotificationName:MCOCIDURLProtocolDownloadedNotification object:nil userInfo:userInfo];
+ [userInfo release];
+ //NSLog(@"downloaded %p %@", self, partUniqueID);
+}
+
+@end
diff --git a/src/ui/mac/MCOMessageView.h b/src/ui/mac/MCOMessageView.h
new file mode 100644
index 00000000..c8ffe241
--- /dev/null
+++ b/src/ui/mac/MCOMessageView.h
@@ -0,0 +1,49 @@
+//
+// MCOMessageView.h
+// testUI
+//
+// Created by DINH Viêt Hoà on 1/19/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+#include <mailcore/mailcore.h>
+
+@protocol MCOMessageViewDelegate;
+
+@interface MCOMessageView : NSView
+
+@property (nonatomic, copy) NSString * folder;
+@property (nonatomic, strong) MCOAbstractMessage * message;
+
+@property (nonatomic, assign) id <MCOMessageViewDelegate> delegate;
+
+@property (nonatomic, assign) BOOL prefetchIMAPImagesEnabled;
+@property (nonatomic, assign) BOOL prefetchIMAPAttachmentsEnabled;
+
+@end
+
+@protocol MCOMessageViewDelegate <NSObject>
+
+@optional
+- (NSData *) MCOMessageView:(MCOMessageView *)view dataForPartWithUniqueID:(NSString *)partUniqueID;
+- (void) MCOMessageView:(MCOMessageView *)view fetchDataForPartWithUniqueID:(NSString *)partUniqueID
+ downloadedFinished:(void (^)(NSError * error))downloadFinished;
+
+- (NSString *) MCOMessageView_templateForMainHeader:(MCOMessageView *)view;
+- (NSString *) MCOMessageView_templateForImage:(MCOMessageView *)view;
+- (NSString *) MCOMessageView_templateForAttachment:(MCOMessageView *)view;
+- (NSString *) MCOMessageView_templateForMessage:(MCOMessageView *)view;
+- (NSString *) MCOMessageView_templateForEmbeddedMessage:(MCOMessageView *)view;
+- (NSString *) MCOMessageView_templateForEmbeddedMessageHeader:(MCOMessageView *)view;
+- (NSString *) MCOMessageView_templateForAttachmentSeparator:(MCOMessageView *)view;
+
+- (NSDictionary *) MCOMessageView:(MCOMessageView *)view templateValuesForPartWithUniqueID:(NSString *)uniqueID;
+- (NSDictionary *) MCOMessageView:(MCOMessageView *)view templateValuesForHeader:(MCOMessageHeader *)header;
+- (BOOL) MCOMessageView:(MCOMessageView *)view canPreviewPart:(MCOAbstractPart *)part;
+
+- (NSString *) MCOMessageView:(MCOMessageView *)view filteredHTMLForPart:(NSString *)html;
+- (NSString *) MCOMessageView:(MCOMessageView *)view filteredHTMLForMessage:(NSString *)html;
+- (NSData *) MCOMessageView:(MCOMessageView *)view previewForData:(NSData *)data isHTMLInlineImage:(BOOL)isHTMLInlineImage;
+
+@end
diff --git a/src/ui/mac/MCOMessageView.mm b/src/ui/mac/MCOMessageView.mm
new file mode 100644
index 00000000..4e3b908c
--- /dev/null
+++ b/src/ui/mac/MCOMessageView.mm
@@ -0,0 +1,335 @@
+//
+// MCOMessageView.m
+// testUI
+//
+// Created by DINH Viêt Hoà on 1/19/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#import "MCOMessageView.h"
+
+#import <WebKit/WebKit.h>
+
+#import "MCOCIDURLProtocol.h"
+
+@interface MCOMessageView () <MCOHTMLRendererIMAPDelegate>
+
+@end
+
+@implementation MCOMessageView {
+ WebView * _webView;
+ NSString * _folder;
+ MCOAbstractMessage * _message;
+ id <MCOMessageViewDelegate> _delegate;
+ BOOL _prefetchIMAPImagesEnabled;
+ BOOL _prefetchIMAPAttachmentsEnabled;
+}
+
+@synthesize folder = _folder;
+@synthesize delegate = _delegate;
+@synthesize prefetchIMAPImagesEnabled = _prefetchIMAPImagesEnabled;
+@synthesize prefetchIMAPAttachmentsEnabled = _prefetchIMAPAttachmentsEnabled;
+
++ (void) initialize
+{
+ [MCOCIDURLProtocol registerProtocol];
+}
+
+- (id)initWithFrame:(NSRect)frame
+{
+ self = [super initWithFrame:frame];
+
+ _webView = [[WebView alloc] initWithFrame:[self bounds]];
+ [_webView setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
+ [_webView setResourceLoadDelegate:self];
+ [self addSubview:_webView];
+
+ return self;
+}
+
+- (void) dealloc
+{
+ [_message release];
+ [_folder release];
+ [_webView release];
+
+ [super dealloc];
+}
+
+- (void) setMessage:(MCOAbstractMessage *)message
+{
+ [_message release];
+ _message = [message retain];
+
+ [_webView stopLoading:nil];
+ [self _refresh];
+}
+
+- (MCOAbstractMessage *) message
+{
+ return _message;
+}
+
+- (void) _refresh
+{
+ NSString * content;
+
+ if (_message == nil) {
+ content = nil;
+ }
+ else {
+ if ([_message isKindOfClass:[MCOIMAPMessage class]]) {
+ content = [(MCOIMAPMessage *) _message htmlRenderingWithFolder:_folder delegate:self];
+ }
+ else if ([_message isKindOfClass:[MCOMessageBuilder class]]) {
+ content = [(MCOMessageBuilder *) _message htmlRenderingWithDelegate:self];
+ }
+ else if ([_message isKindOfClass:[MCOMessageParser class]]) {
+ content = [(MCOMessageParser *) _message htmlRenderingWithDelegate:self];
+ }
+ else {
+ content = nil;
+ MCAssert(0);
+ }
+ }
+ [[_webView mainFrame] loadHTMLString:content baseURL:nil];
+}
+
+- (MCOAbstractPart *) _partForCIDURL:(NSURL *)url
+{
+ return [_message partForContentID:[url resourceSpecifier]];
+}
+
+- (MCOAbstractPart *) _partForUniqueID:(NSString *)partUniqueID
+{
+ return [_message partForUniqueID:partUniqueID];
+}
+
+- (NSData *) _dataForIMAPPart:(MCOIMAPPart *)part folder:(NSString *)folder
+{
+ NSData * data;
+ NSString * partUniqueID = [part uniqueID];
+ data = [[self delegate] MCOMessageView:self dataForPartWithUniqueID:partUniqueID];
+ if (data == NULL) {
+ [[self delegate] MCOMessageView:self fetchDataForPartWithUniqueID:partUniqueID downloadedFinished:^(NSError * error) {
+ [self _refresh];
+ }];
+ }
+ return data;
+}
+
+- (NSURLRequest *)webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(id)dataSource
+{
+ MCOAbstractPart * part = NULL;
+
+ if ([MCOCIDURLProtocol isCID:[request URL]]) {
+ part = [self _partForCIDURL:[request URL]];
+ }
+ else if ([MCOCIDURLProtocol isXMailcoreImage:[ request URL]]) {
+ NSString * specifier = [[request URL] resourceSpecifier];
+ NSString * partUniqueID = specifier;
+ part = [self _partForUniqueID:partUniqueID];
+ }
+
+ if (part != NULL) {
+ if ([_message isKindOfClass:[MCOIMAPMessage class]]) {
+ NSMutableURLRequest * mutableRequest = [request mutableCopy];
+ NSString * partUniqueID = [part uniqueID];
+ NSData * data = [[self delegate] MCOMessageView:self dataForPartWithUniqueID:partUniqueID];
+ if (data == NULL) {
+ [[self delegate] MCOMessageView:self fetchDataForPartWithUniqueID:partUniqueID downloadedFinished:^(NSError * error) {
+ NSData * downloadedData = [[self delegate] MCOMessageView:self dataForPartWithUniqueID:partUniqueID];
+ NSData * previewData = [[self delegate] MCOMessageView:self previewForData:downloadedData isHTMLInlineImage:[MCOCIDURLProtocol isCID:[request URL]]];
+ [MCOCIDURLProtocol partDownloadedMessage:_message partUniqueID:partUniqueID data:previewData];
+ }];
+ }
+ [MCOCIDURLProtocol startLoadingWithMessage:_message
+ partUniqueID:partUniqueID
+ data:data
+ request:mutableRequest];
+
+ return [mutableRequest autorelease];
+ }
+ else if ([_message isKindOfClass:[MCOMessageParser class]]) {
+ NSMutableURLRequest * mutableRequest = [request mutableCopy];
+ NSString * partUniqueID = [part uniqueID];
+ NSData * data = [(MCOAttachment *) part data];
+ NSData * previewData = [[self delegate] MCOMessageView:self previewForData:data isHTMLInlineImage:[MCOCIDURLProtocol isCID:[request URL]]];
+ [MCOCIDURLProtocol startLoadingWithMessage:_message
+ partUniqueID:partUniqueID
+ data:previewData
+ request:mutableRequest];
+
+ return [mutableRequest autorelease];
+ }
+ else {
+ return request;
+ }
+ }
+ else {
+ return request;
+ }
+}
+
+- (BOOL) MCOAbstractMessage:(MCOAbstractMessage *)msg canPreviewPart:(MCOAbstractPart *)part
+{
+ static NSMutableSet * supportedImageMimeTypes = NULL;
+ if (supportedImageMimeTypes == NULL) {
+ supportedImageMimeTypes = [[NSMutableSet alloc] init];
+ [supportedImageMimeTypes addObject:@"image/png"];
+ [supportedImageMimeTypes addObject:@"image/gif"];
+ [supportedImageMimeTypes addObject:@"image/jpg"];
+ [supportedImageMimeTypes addObject:@"image/jpeg"];
+ }
+ static NSMutableSet * supportedImageExtension = NULL;
+ if (supportedImageExtension == NULL) {
+ supportedImageExtension = [[NSMutableSet alloc] init];
+ [supportedImageExtension addObject:@"png"];
+ [supportedImageExtension addObject:@"gif"];
+ [supportedImageExtension addObject:@"jpg"];
+ [supportedImageExtension addObject:@"jpeg"];
+ }
+
+ if ([supportedImageMimeTypes containsObject:[[part mimeType] lowercaseString]])
+ return YES;
+
+ NSString * ext = nil;
+ if ([part filename] != nil) {
+ if ([[part filename] pathExtension] != nil) {
+ ext = [[[part filename] pathExtension] lowercaseString];
+ }
+ }
+ if (ext != nil) {
+ if ([supportedImageExtension containsObject:ext])
+ return YES;
+ }
+
+ if (![[self delegate] respondsToSelector:@selector(MCOMessageView:canPreviewPart:)]) {
+ return false;
+ }
+ return [[self delegate] MCOMessageView:self canPreviewPart:part];
+}
+
+- (NSDictionary *) MCOAbstractMessage:(MCOAbstractMessage *)msg templateValuesForHeader:(MCOMessageHeader *)header
+{
+ if (![[self delegate] respondsToSelector:@selector(MCOMessageView:templateValuesForHeader:)]) {
+ return nil;
+ }
+ return [[self delegate] MCOMessageView:self templateValuesForHeader:header];
+}
+
+- (NSDictionary *) MCOAbstractMessage:(MCOAbstractMessage *)msg templateValuesForPart:(MCOAbstractPart *)part
+{
+ if (![[self delegate] respondsToSelector:@selector(MCOMessageView:templateValuesForPartWithUniqueID:)]) {
+ return nil;
+ }
+ return [[self delegate] MCOMessageView:self templateValuesForPartWithUniqueID:[part uniqueID]];
+}
+
+- (NSString *) MCOAbstractMessage_templateForMainHeader:(MCOAbstractMessage *)msg
+{
+ if (![[self delegate] respondsToSelector:@selector(MCOMessageView_templateForMainHeader:)]) {
+ return nil;
+ }
+ return [[self delegate] MCOMessageView_templateForMainHeader:self];
+}
+
+- (NSString *) MCOAbstractMessage_templateForImage:(MCOAbstractMessage *)msg
+{
+ NSString * templateString;
+ if ([[self delegate] respondsToSelector:@selector(MCOMessageView_templateForImage:)]) {
+ templateString = [[self delegate] MCOMessageView_templateForImage:self];
+ }
+ else {
+ templateString = @"<img src=\"{{URL}}\"/>";
+ }
+ templateString = [NSString stringWithFormat:@"<div id=\"{{CONTENTID}}\">%@</div>", templateString];
+ return templateString;
+}
+
+- (NSString *) MCOAbstractMessage_templateForAttachment:(MCOAbstractMessage *)msg
+{
+ if (![[self delegate] respondsToSelector:@selector(MCOMessageView_templateForAttachment:)]) {
+ return NULL;
+ }
+ NSString * templateString = [[self delegate] MCOMessageView_templateForAttachment:self];
+ templateString = [NSString stringWithFormat:@"<div id=\"{{CONTENTID}}\">%@</div>", templateString];
+ return templateString;
+}
+
+- (NSString *) MCOAbstractMessage_templateForMessage:(MCOAbstractMessage *)msg
+{
+ if (![[self delegate] respondsToSelector:@selector(MCOMessageView_templateForMessage:)]) {
+ return NULL;
+ }
+ return [[self delegate] MCOMessageView_templateForMessage:self];
+}
+
+- (NSString *) MCOAbstractMessage_templateForEmbeddedMessage:(MCOAbstractMessage *)msg
+{
+ if (![[self delegate] respondsToSelector:@selector(MCOMessageView_templateForEmbeddedMessage:)]) {
+ return NULL;
+ }
+ return [[self delegate] MCOMessageView_templateForEmbeddedMessage:self];
+}
+
+- (NSString *) MCOAbstractMessage_templateForEmbeddedMessageHeader:(MCOAbstractMessage *)msg
+{
+ if (![[self delegate] respondsToSelector:@selector(MCOMessageView_templateForEmbeddedMessageHeader:)]) {
+ return NULL;
+ }
+ return [[self delegate] MCOMessageView_templateForEmbeddedMessageHeader:self];
+}
+
+- (NSString *) MCOAbstractMessage_templateForAttachmentSeparator:(MCOAbstractMessage *)msg
+{
+ if (![[self delegate] respondsToSelector:@selector(MCOMessageView_templateForAttachmentSeparator:)]) {
+ return NULL;
+ }
+ return [[self delegate] MCOMessageView_templateForAttachmentSeparator:self];
+}
+
+- (NSString *) MCOAbstractMessage:(MCOAbstractMessage *)msg filterHTMLForPart:(NSString *)html
+{
+ if (![[self delegate] respondsToSelector:@selector(MCOMessageView:filteredHTMLForPart:)]) {
+ return html;
+ }
+ return [[self delegate] MCOMessageView:self filteredHTMLForPart:html];
+}
+
+- (NSString *) MCOAbstractMessage:(MCOAbstractMessage *)msg filterHTMLForMessage:(NSString *)html
+{
+ if (![[self delegate] respondsToSelector:@selector(MCOMessageView:filteredHTMLForMessage:)]) {
+ return html;
+ }
+ return [[self delegate] MCOMessageView:self filteredHTMLForMessage:html];
+}
+
+- (NSData *) MCOAbstractMessage:(MCOAbstractMessage *)msg dataForIMAPPart:(MCOIMAPPart *)part folder:(NSString *)folder
+{
+ return [self _dataForIMAPPart:part folder:folder];
+}
+
+- (void) MCOAbstractMessage:(MCOAbstractMessage *)msg prefetchAttachmentIMAPPart:(MCOIMAPPart *)part folder:(NSString *)folder
+{
+ if (!_prefetchIMAPAttachmentsEnabled)
+ return;
+
+ NSString * partUniqueID = [part uniqueID];
+ [[self delegate] MCOMessageView:self fetchDataForPartWithUniqueID:partUniqueID downloadedFinished:^(NSError * error) {
+ // do nothing
+ }];
+}
+
+- (void) MCOAbstractMessage:(MCOAbstractMessage *)msg prefetchImageIMAPPart:(MCOIMAPPart *)part folder:(NSString *)folder
+{
+ if (!_prefetchIMAPImagesEnabled)
+ return;
+
+ NSString * partUniqueID = [part uniqueID];
+ [[self delegate] MCOMessageView:self fetchDataForPartWithUniqueID:partUniqueID downloadedFinished:^(NSError * error) {
+ // do nothing
+ }];
+}
+
+@end