From 6aeb50c1ddbf6b75298fa2853c39c82211f46f9a Mon Sep 17 00:00:00 2001 From: helge Date: Sun, 30 Jan 2005 17:20:10 +0000 Subject: [PATCH] various cleanups, work on forward/reply git-svn-id: http://svn.opengroupware.org/SOGo/trunk@506 d1b88da0-ebda-0310-925b-ed51d893ca5b --- SOGo/SoObjects/Mailer/ChangeLog | 13 ++ SOGo/SoObjects/Mailer/SOGoDraftObject.h | 10 +- SOGo/SoObjects/Mailer/SOGoDraftObject.m | 127 +++++++++++---- SOGo/SoObjects/Mailer/SOGoDraftsFolder.m | 3 +- SOGo/SoObjects/Mailer/SOGoMailAccount.m | 33 ++-- SOGo/SoObjects/Mailer/SOGoMailObject.h | 2 +- SOGo/SoObjects/Mailer/Version | 2 +- SOGo/UI/Mailer/ChangeLog | 23 +++ SOGo/UI/Mailer/UIxFilterList.m | 6 +- SOGo/UI/Mailer/UIxFilterList.wox | 2 +- SOGo/UI/Mailer/UIxMailAccountView.m | 17 +- SOGo/UI/Mailer/UIxMailAccountView.wox | 2 +- SOGo/UI/Mailer/UIxMailAccountsView.m | 7 +- SOGo/UI/Mailer/UIxMailAccountsView.wox | 5 +- SOGo/UI/Mailer/UIxMailEditor.m | 12 +- SOGo/UI/Mailer/UIxMailEditor.wox | 2 +- SOGo/UI/Mailer/UIxMailEditorAction.m | 197 ++++++++++++++++++++++- SOGo/UI/Mailer/UIxMailEditorAttach.m | 23 ++- SOGo/UI/Mailer/UIxMailFormatter.h | 8 +- SOGo/UI/Mailer/UIxMailListView.m | 17 +- SOGo/UI/Mailer/UIxMailListView.wox | 2 +- SOGo/UI/Mailer/UIxMailMainFrame.m | 6 +- SOGo/UI/Mailer/UIxMailView.m | 17 +- SOGo/UI/Mailer/UIxMailView.wox | 5 +- SOGo/UI/Mailer/UIxSieveEditor.m | 4 + SOGo/UI/Mailer/UIxSieveEditor.wox | 2 +- SOGo/UI/Mailer/UIxSubjectFormatter.m | 2 +- SOGo/UI/Mailer/Version | 3 +- SOGo/UI/Mailer/product.plist | 10 +- 29 files changed, 467 insertions(+), 95 deletions(-) diff --git a/SOGo/SoObjects/Mailer/ChangeLog b/SOGo/SoObjects/Mailer/ChangeLog index 93da62fa..80443409 100644 --- a/SOGo/SoObjects/Mailer/ChangeLog +++ b/SOGo/SoObjects/Mailer/ChangeLog @@ -1,3 +1,16 @@ +2005-01-30 Helge Hess + + * v0.9.59 + + * SOGoDraftObject.m: improved attachment/info API to return exceptions, + minor improvement to attachment name check, properly generate + message/rfc822 mime type for mail attachments, properly generate + "text/plain; utf8" header + + * SOGoMailAccount.m: use a constant for INBOX folder name, disabled + 'Filters' folder unless the 'SOGoEnableSieveFolder' is set (since + Sieve support is incomplete) + 2005-01-28 Helge Hess * v0.9.58 diff --git a/SOGo/SoObjects/Mailer/SOGoDraftObject.h b/SOGo/SoObjects/Mailer/SOGoDraftObject.h index 0043021c..0c975366 100644 --- a/SOGo/SoObjects/Mailer/SOGoDraftObject.h +++ b/SOGo/SoObjects/Mailer/SOGoDraftObject.h @@ -32,6 +32,8 @@ The SOGoDraftObject is used for composing new messages. It is necessary because we can't cache objects in a session. So the contents of the drafts folder are some kind of "mail creation transaction". + + TODO: store-info should be an own object, not NSDictionary. */ @class NSString, NSArray, NSDictionary, NSData, NSException; @@ -47,12 +49,14 @@ /* contents */ - (NSDictionary *)fetchInfo; -- (BOOL)storeInfo:(NSDictionary *)_info; +- (NSException *)storeInfo:(NSDictionary *)_info; + +/* attachments */ - (NSArray *)fetchAttachmentNames; - (BOOL)isValidAttachmentName:(NSString *)_name; -- (BOOL)saveAttachment:(NSData *)_attachment withName:(NSString *)_name; -- (BOOL)deleteAttachmentWithName:(NSString *)_name; +- (NSException *)saveAttachment:(NSData *)_attach withName:(NSString *)_name; +- (NSException *)deleteAttachmentWithName:(NSString *)_name; /* NGMime representations */ diff --git a/SOGo/SoObjects/Mailer/SOGoDraftObject.m b/SOGo/SoObjects/Mailer/SOGoDraftObject.m index be9909bd..5add8897 100644 --- a/SOGo/SoObjects/Mailer/SOGoDraftObject.m +++ b/SOGo/SoObjects/Mailer/SOGoDraftObject.m @@ -98,21 +98,27 @@ static BOOL debugOn = NO; /* contents */ -- (BOOL)storeInfo:(NSDictionary *)_info { +- (NSException *)storeInfo:(NSDictionary *)_info { if (_info == nil) { - [self warnWithFormat:@"got no info to write for draft!"]; - return NO; + return [NSException exceptionWithHTTPStatus:500 /* server error */ + reason:@"got no info to write for draft!"]; } if (![self _ensureDraftFolderPath]) { [self errorWithFormat:@"could not create folder for draft: '%@'", [self draftFolderPath]]; - return NO; + return [NSException exceptionWithHTTPStatus:500 /* server error */ + reason:@"could not create folder for draft!"]; } if (![_info writeToFile:[self infoPath] atomically:YES]) { [self errorWithFormat:@"could not write info: '%@'", [self infoPath]]; - return NO; + return [NSException exceptionWithHTTPStatus:500 /* server error */ + reason:@"could not write draft info!"]; } - return YES; + + /* reset info cache */ + [self->info release]; self->info = nil; + + return nil /* everything is excellent */; } - (NSDictionary *)fetchInfo { NSString *p; @@ -166,21 +172,18 @@ static BOOL debugOn = NO; } - (BOOL)isValidAttachmentName:(NSString *)_name { - NSRange r; + static NSString *sescape[] = { @"/", @"..", @"~", @"\"", @"'", @" ", nil }; + unsigned i; + NSRange r; if (![_name isNotNull]) return NO; if ([_name length] == 0) return NO; if ([_name hasPrefix:@"."]) return NO; - r = [_name rangeOfString:@"/"]; - if (r.length > 0) return NO; - r = [_name rangeOfString:@".."]; - if (r.length > 0) return NO; - r = [_name rangeOfString:@"~"]; - if (r.length > 0) return NO; - r = [_name rangeOfString:@"\""]; - if (r.length > 0) return NO; - + for (i = 0; sescape[i] != nil; i++) { + r = [_name rangeOfString:sescape[i]]; + if (r.length > 0) return NO; + } return YES; } @@ -191,36 +194,53 @@ static BOOL debugOn = NO; return [[self draftFolderPath] stringByAppendingPathComponent:_name]; } -- (BOOL)saveAttachment:(NSData *)_attachment withName:(NSString *)_name { - NSString *p; +- (NSException *)invalidAttachmentNameError:(NSString *)_name { + return [NSException exceptionWithHTTPStatus:400 /* Bad Request */ + reason:@"Invalid attachment name!"]; +} - if (_attachment == nil) - return NO; +- (NSException *)saveAttachment:(NSData *)_attach withName:(NSString *)_name { + NSString *p; + + if (![_attach isNotNull]) { + return [NSException exceptionWithHTTPStatus:400 /* Bad Request */ + reason:@"Missing attachment content!"]; + } if (![self _ensureDraftFolderPath]) { - [self errorWithFormat:@"could not create folder for draft!"]; - return NO; + return [NSException exceptionWithHTTPStatus:500 /* Server Error */ + reason:@"Could not create folder for draft!"]; } if (![self isValidAttachmentName:_name]) - return NO; + return [self invalidAttachmentNameError:_name]; p = [self pathToAttachmentWithName:_name]; - return [_attachment writeToFile:p atomically:YES]; + if (![_attach writeToFile:p atomically:YES]) { + return [NSException exceptionWithHTTPStatus:500 /* Server Error */ + reason:@"Could not write attachment to draft!"]; + } + + return nil; /* everything OK */ } -- (BOOL)deleteAttachmentWithName:(NSString *)_name { +- (NSException *)deleteAttachmentWithName:(NSString *)_name { NSFileManager *fm; NSString *p; if (![self isValidAttachmentName:_name]) - return NO; + return [self invalidAttachmentNameError:_name]; fm = [self spoolFileManager]; p = [self pathToAttachmentWithName:_name]; if (![fm fileExistsAtPath:p]) - return YES; /* well, doesn't exist, so its deleted ;-) */ + return nil; /* well, doesn't exist, so its deleted ;-) */ - return [fm removeFileAtPath:p handler:nil]; + if (![fm removeFileAtPath:p handler:nil]) { + [self logWithFormat:@"ERROR: failed to delete file: %@", p]; + return [NSException exceptionWithHTTPStatus:500 /* Server Error */ + reason:@"Could not delete attachment from draft!"]; + } + return nil; /* everything OK */ } /* NGMime representations */ @@ -229,43 +249,63 @@ static BOOL debugOn = NO; NGMutableHashMap *map; NGMimeBodyPart *bodyPart; NSDictionary *lInfo; - + id body; + if ((lInfo = [self fetchInfo]) == nil) return nil; /* prepare header of body part */ - + map = [[[NGMutableHashMap alloc] initWithCapacity:2] autorelease]; + + // TODO: set charset in header! [map setObject:@"text/plain" forKey:@"content-type"]; + if ((body = [lInfo objectForKey:@"text"]) != nil) { + if ([body isKindOfClass:[NSString class]]) { + [map setObject:@"text/plain; charset=utf-8" forKey:@"content-type"]; + body = [body dataUsingEncoding:NSUTF8StringEncoding]; + } + } /* prepare body content */ bodyPart = [[[NGMimeBodyPart alloc] initWithHeader:map] autorelease]; - [bodyPart setBody:[lInfo objectForKey:@"text"]]; + [bodyPart setBody:body]; return bodyPart; } - (NGMimeMessage *)mimeMessageForContentWithHeaderMap:(NGMutableHashMap *)map { NSDictionary *lInfo; NGMimeMessage *message; + id body; if ((lInfo = [self fetchInfo]) == nil) return nil; [map setObject:@"text/plain" forKey:@"content-type"]; + if ((body = [lInfo objectForKey:@"text"]) != nil) { + if ([body isKindOfClass:[NSString class]]) { + /* Note: just 'utf8' is displayed wrong in Mail.app */ + [map setObject:@"text/plain; charset=utf-8" forKey:@"content-type"]; + body = [body dataUsingEncoding:NSUTF8StringEncoding]; + } + } + message = [[[NGMimeMessage alloc] initWithHeader:map] autorelease]; - [message setBody:[lInfo objectForKey:@"text"]]; + [message setBody:body]; return message; } - (NSString *)mimeTypeForExtension:(NSString *)_ext { // TODO: make configurable + // TODO: use /etc/mime-types if ([_ext isEqualToString:@"txt"]) return @"text/plain"; if ([_ext isEqualToString:@"html"]) return @"text/html"; if ([_ext isEqualToString:@"htm"]) return @"text/html"; if ([_ext isEqualToString:@"gif"]) return @"image/gif"; if ([_ext isEqualToString:@"jpg"]) return @"image/jpeg"; if ([_ext isEqualToString:@"jpeg"]) return @"image/jpeg"; + if ([_ext isEqualToString:@"mail"]) return @"message/rfc822"; return @"application/octet-stream"; } @@ -289,11 +329,11 @@ static BOOL debugOn = NO; if ([type hasPrefix:@"text/"]) cdtype = @"inline"; - else if ([type hasPrefix:@"image/"]) + else if ([type hasPrefix:@"image/"] || [type hasPrefix:@"message"]) cdtype = @"inline"; else cdtype = @"attachment"; - + cd = [cdtype stringByAppendingString:@"; filename=\""]; cd = [cd stringByAppendingString:_name]; cd = [cd stringByAppendingString:@"\""]; @@ -308,7 +348,7 @@ static BOOL debugOn = NO; NGMimeBodyPart *bodyPart; NSString *s; NSData *content; - BOOL attachAsString; + BOOL attachAsString, is7bit; NSString *p; id body; @@ -323,6 +363,7 @@ static BOOL debugOn = NO; return nil; } attachAsString = NO; + is7bit = NO; /* prepare header of body part */ @@ -332,6 +373,8 @@ static BOOL debugOn = NO; [map setObject:s forKey:@"content-type"]; if ([s hasPrefix:@"text/"]) attachAsString = YES; + else if ([s hasPrefix:@"message/rfc822"]) + is7bit = YES; } if ((s = [self contentDispositionForAttachmentWithName:_name])) [map setObject:s forKey:@"content-disposition"]; @@ -356,6 +399,16 @@ static BOOL debugOn = NO; content = nil; } } + else if (is7bit) { + /* + Note: Apparently NGMimeFileData objects are not processed by the MIME + generator! + */ + body = [[NGMimeFileData alloc] initWithPath:p removeFile:NO]; + [map setObject:@"7bit" forKey:@"content-transfer-encoding"]; + [map setObject:[NSNumber numberWithInt:[body length]] + forKey:@"content-length"]; + } else { /* Note: in OGo this is done in LSWImapMailEditor.m:2477. Apparently @@ -531,6 +584,10 @@ static BOOL debugOn = NO; message = [self mimeMessage]; if (![message isNotNull]) return nil; + if ([message isKindOfClass:[NSException class]]) { + [self errorWithFormat:@"error: %@", message]; + return nil; + } gen = [[NGMimeMessageGenerator alloc] init]; tmpPath = [[gen generateMimeFromPartToFile:message] copy]; diff --git a/SOGo/SoObjects/Mailer/SOGoDraftsFolder.m b/SOGo/SoObjects/Mailer/SOGoDraftsFolder.m index f31d6f49..62f10ab5 100644 --- a/SOGo/SoObjects/Mailer/SOGoDraftsFolder.m +++ b/SOGo/SoObjects/Mailer/SOGoDraftsFolder.m @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 SKYRIX Software AG + Copyright (C) 2004-2005 SKYRIX Software AG This file is part of OpenGroupware.org. @@ -18,7 +18,6 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id$ #include "SOGoDraftsFolder.h" #include "SOGoDraftObject.h" diff --git a/SOGo/SoObjects/Mailer/SOGoMailAccount.m b/SOGo/SoObjects/Mailer/SOGoMailAccount.m index 1e3c6741..658af71e 100644 --- a/SOGo/SoObjects/Mailer/SOGoMailAccount.m +++ b/SOGo/SoObjects/Mailer/SOGoMailAccount.m @@ -27,19 +27,34 @@ @implementation SOGoMailAccount +static NSString *inboxFolderName = @"INBOX"; static NSString *draftsFolderName = @"Drafts"; static NSString *sieveFolderName = @"Filters"; +static NSArray *rootFolderNames = nil; + ++ (void)initialize { + NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; + + if ([ud boolForKey:@"SOGoEnableSieveFolder"]) { + rootFolderNames = [[NSArray alloc] initWithObjects: + inboxFolderName, + draftsFolderName, + sieveFolderName, + nil]; + } + else { + rootFolderNames = [[NSArray alloc] initWithObjects: + inboxFolderName, + draftsFolderName, + nil]; + } +} /* listing the available folders */ - (NSArray *)toManyRelationshipKeys { // TODO: hardcoded, if we want to support shared fldrs, this needs to change - static NSArray *accFolderNames = nil; - if (accFolderNames == nil) { - accFolderNames = [[NSArray alloc] initWithObjects: - @"INBOX", @"Drafts", @"Filters", nil]; - } - return accFolderNames; + return rootFolderNames; } /* hierarchy */ @@ -145,20 +160,20 @@ static NSString *sieveFolderName = @"Filters"; /* special folders */ - (SOGoMailFolder *)inboxFolderInContext:(id)_ctx { - // TODO: use some profile to determine real location + // TODO: use some profile to determine real location, use a -traverse lookup SOGoMailFolder *folder; if (self->inboxFolder != nil) return self->inboxFolder; - folder = [self lookupName:@"INBOX" inContext:_ctx acquire:NO]; + folder = [self lookupName:inboxFolderName inContext:_ctx acquire:NO]; if ([folder isKindOfClass:[NSException class]]) return folder; return ((self->inboxFolder = [folder retain])); } - (SOGoMailFolder *)sentFolderInContext:(id)_ctx { - // TODO: use some profile to determine real location + // TODO: use some profile to determine real location, use a -traverse lookup SOGoMailFolder *folder; if (self->sentFolder != nil) diff --git a/SOGo/SoObjects/Mailer/SOGoMailObject.h b/SOGo/SoObjects/Mailer/SOGoMailObject.h index e35ad5d1..eea288f1 100644 --- a/SOGo/SoObjects/Mailer/SOGoMailObject.h +++ b/SOGo/SoObjects/Mailer/SOGoMailObject.h @@ -51,7 +51,7 @@ /* core infos */ -- (id)fetchCoreInfos; +- (id)fetchCoreInfos; // TODO: what does it do? - (NGImap4Envelope *)envelope; - (NSString *)subject; diff --git a/SOGo/SoObjects/Mailer/Version b/SOGo/SoObjects/Mailer/Version index 6d5b940e..563de9bc 100644 --- a/SOGo/SoObjects/Mailer/Version +++ b/SOGo/SoObjects/Mailer/Version @@ -1,6 +1,6 @@ # Version file -SUBMINOR_VERSION:=58 +SUBMINOR_VERSION:=59 # v0.9.55 requires NGExtensions v4.5.136 # v0.9.44 requires libNGMime v4.3.194 diff --git a/SOGo/UI/Mailer/ChangeLog b/SOGo/UI/Mailer/ChangeLog index 6923eee3..5559e5ef 100644 --- a/SOGo/UI/Mailer/ChangeLog +++ b/SOGo/UI/Mailer/ChangeLog @@ -1,3 +1,26 @@ +2005-01-30 Helge Hess + + * v0.9.80 + + * UIxMailEditorAction.m: work on forwarding and reply + + * UIxFilterList.wox, UIxMailAccountView.wox, UIxMailAccountsView.wox, + UIxSieveEditor.wox: fixed title (needs localization) + + * UIxMailMainFrame.m: always generate title as given by the parent + component (titles need to get fixed!), was fixed to OpenGroupware.org + before unless in debug mode + + * UIxMailEditor.m: use new storeInfo API, generate a proper panelTitle + (needs localization) + + * UIxMailEditorAttach.m: use new attachment API + + * UIxMailView.wox: remoted link to screenshot, use mail subject as + title + + * UIxMailListView.m: disabled a log + 2005-01-28 Helge Hess * v0.9.79 diff --git a/SOGo/UI/Mailer/UIxFilterList.m b/SOGo/UI/Mailer/UIxFilterList.m index d6d99966..08cb7831 100644 --- a/SOGo/UI/Mailer/UIxFilterList.m +++ b/SOGo/UI/Mailer/UIxFilterList.m @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 SKYRIX Software AG + Copyright (C) 2004-2005 SKYRIX Software AG This file is part of OpenGroupware.org. @@ -69,6 +69,10 @@ return self->filters; } +- (NSString *)panelTitle { + return [self labelForKey:@"Mail Filters"]; +} + /* JavaScript code */ - (NSString *)clickedFilterJS { diff --git a/SOGo/UI/Mailer/UIxFilterList.wox b/SOGo/UI/Mailer/UIxFilterList.wox index 1306ab49..3bbdc149 100644 --- a/SOGo/UI/Mailer/UIxFilterList.wox +++ b/SOGo/UI/Mailer/UIxFilterList.wox @@ -7,7 +7,7 @@ xmlns:rsrc="OGo:url" xmlns:label="OGo:label" className="UIxMailMainFrame" - title="name" + title="panelTitle" >
diff --git a/SOGo/UI/Mailer/UIxMailAccountView.m b/SOGo/UI/Mailer/UIxMailAccountView.m index baeaa01c..a0d60577 100644 --- a/SOGo/UI/Mailer/UIxMailAccountView.m +++ b/SOGo/UI/Mailer/UIxMailAccountView.m @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 SKYRIX Software AG + Copyright (C) 2004-2005 SKYRIX Software AG This file is part of OpenGroupware.org. @@ -18,7 +18,6 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id: UIxMailAccountView.m 308 2004-09-20 10:51:12Z helge $ #include @@ -32,4 +31,18 @@ @implementation UIxMailAccountView +/* title */ + +- (NSString *)objectTitle { + return [[self clientObject] nameInContainer]; +} +- (NSString *)panelTitle { + NSString *s; + + s = [self labelForKey:@"Mail Account"]; + s = [s stringByAppendingString:@": "]; + s = [s stringByAppendingString:[self objectTitle]]; + return s; +} + @end /* UIxMailAccountView */ diff --git a/SOGo/UI/Mailer/UIxMailAccountView.wox b/SOGo/UI/Mailer/UIxMailAccountView.wox index 954e4edd..28b145c0 100644 --- a/SOGo/UI/Mailer/UIxMailAccountView.wox +++ b/SOGo/UI/Mailer/UIxMailAccountView.wox @@ -7,7 +7,7 @@ xmlns:rsrc="OGo:url" xmlns:label="OGo:label" className="UIxMailMainFrame" - title="name" + title="panelTitle" >
diff --git a/SOGo/UI/Mailer/UIxMailAccountsView.m b/SOGo/UI/Mailer/UIxMailAccountsView.m index 15fed209..cbef1b2b 100644 --- a/SOGo/UI/Mailer/UIxMailAccountsView.m +++ b/SOGo/UI/Mailer/UIxMailAccountsView.m @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 SKYRIX Software AG + Copyright (C) 2004-2005 SKYRIX Software AG This file is part of OpenGroupware.org. @@ -18,7 +18,6 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id: UIxMailAccountsView.m 308 2004-09-20 10:51:12Z helge $ #include @@ -32,4 +31,8 @@ @implementation UIxMailAccountsView +- (NSString *)panelTitle { + return [self labelForKey:@"SOGo Mail Accounts"]; +} + @end /* UIxMailAccountsView */ diff --git a/SOGo/UI/Mailer/UIxMailAccountsView.wox b/SOGo/UI/Mailer/UIxMailAccountsView.wox index 2ab332b2..1198cf8a 100644 --- a/SOGo/UI/Mailer/UIxMailAccountsView.wox +++ b/SOGo/UI/Mailer/UIxMailAccountsView.wox @@ -7,13 +7,16 @@ xmlns:label="OGo:label" xmlns:rsrc="OGo:url" className="UIxMailMainFrame" - title="name" + title="panelTitle" >
+ +
diff --git a/SOGo/UI/Mailer/UIxMailEditor.m b/SOGo/UI/Mailer/UIxMailEditor.m index b6954df4..627052d2 100644 --- a/SOGo/UI/Mailer/UIxMailEditor.m +++ b/SOGo/UI/Mailer/UIxMailEditor.m @@ -127,6 +127,12 @@ static NSArray *infoKeys = nil; return [self->bcc isNotNull] ? self->bcc : [NSArray array]; } +/* title */ + +- (NSString *)panelTitle { + return [self labelForKey:@"Compose Mail"]; +} + /* info loading */ - (void)loadInfo:(NSDictionary *)_info { @@ -197,8 +203,10 @@ static NSArray *infoKeys = nil; NSDictionary *info; if ((info = [self storeInfo]) != nil) { - if (![[self clientObject] storeInfo:info]) { - [self errorWithFormat:@"failed to store draft!"]; + NSException *error; + + if ((error = [[self clientObject] storeInfo:info]) != nil) { + [self errorWithFormat:@"failed to store draft: %@", error]; // TODO: improve error handling return NO; } diff --git a/SOGo/UI/Mailer/UIxMailEditor.wox b/SOGo/UI/Mailer/UIxMailEditor.wox index 08dbe640..c51c4dad 100644 --- a/SOGo/UI/Mailer/UIxMailEditor.wox +++ b/SOGo/UI/Mailer/UIxMailEditor.wox @@ -7,7 +7,7 @@ xmlns:rsrc="OGo:url" xmlns:label="OGo:label" className="UIxMailMainFrame" - title="name" + title="panelTitle" const:hideFolderTree="1" >
diff --git a/SOGo/UI/Mailer/UIxMailEditorAction.m b/SOGo/UI/Mailer/UIxMailEditorAction.m index 69d64667..6a88bdd5 100644 --- a/SOGo/UI/Mailer/UIxMailEditorAction.m +++ b/SOGo/UI/Mailer/UIxMailEditorAction.m @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 SKYRIX Software AG + Copyright (C) 2004-2005 SKYRIX Software AG This file is part of OpenGroupware.org. @@ -18,7 +18,6 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id$ #include @@ -30,15 +29,34 @@ needs to be created in advance. */ +@class SOGoDraftObject; + @interface UIxMailEditorAction : WODirectAction +{ + SOGoDraftObject *newDraft; +} + @end #include +#include #include +#include #include "common.h" @implementation UIxMailEditorAction +- (void)dealloc { + [self->newDraft release]; + [super dealloc]; +} + +/* caches */ + +- (void)reset { + [self->newDraft release]; self->newDraft = nil; +} + /* lookups */ - (SOGoDraftsFolder *)draftsFolder { @@ -58,7 +76,7 @@ /* errors */ - (id)didNotFindDraftsError { - // TODO: make a nice page + // TODO: make a nice error page return [@"did not find drafts folder in object: " stringByAppendingString:[[self clientObject] description]]; } @@ -66,8 +84,12 @@ return [@"could not create a new draft in folder: " stringByAppendingString:[_draftsFolder description]]; } +- (id)didNotFindMailError { + return [NSException exceptionWithHTTPStatus:404 /* Not Found */ + reason:@"Did not find mail for operation!"]; +} -/* actions */ +/* compose */ - (id)composeAction { SOGoDraftsFolder *drafts; @@ -87,12 +109,179 @@ if (![url hasSuffix:@"/"]) url = [url stringByAppendingString:@"/"]; url = [url stringByAppendingString:@"edit"]; + // TODO: debug log [self logWithFormat:@"compose on %@: %@", drafts, url]; r = [[self context] response]; [r setStatus:302 /* moved */]; [r setHeader:url forKey:@"location"]; + [self reset]; return r; } +/* creating new draft object */ + +- (id)newDraftObject { + SOGoDraftsFolder *drafts; + + drafts = [self draftsFolder]; + if (![drafts isNotNull]) + return [self didNotFindDraftsError]; + if ([drafts isKindOfClass:[NSException class]]) + return drafts; + + return [drafts newObjectInContext:[self context]]; +} + +- (NSException *)_setupNewDraft { + SOGoDraftObject *tmp; + + /* create draft object */ + + if ([(tmp = [self newDraftObject]) isKindOfClass:[NSException class]]) + return (NSException *)tmp; + if (![tmp isNotNull]) { /* Note: should never happen? */ + [self logWithFormat:@"WARNING: got no new draft object and no error!"]; + return [self didNotFindDraftsError]; // TODO: not exact + } + + ASSIGN(self->newDraft, tmp); + [self logWithFormat:@"NEW DRAFT: %@", self->newDraft]; + + return nil; +} + +- (WOResponse *)redirectToEditNewDraft { + WOResponse *r; + NSString *url; + + if (![self->newDraft isNotNull]) { + [self logWithFormat:@"ERROR(%s): missing new draft (already -reset?)", + __PRETTY_FUNCTION__]; + return nil; + } + + url = [self->newDraft baseURLInContext:[self context]]; + if (![url hasSuffix:@"/"]) url = [url stringByAppendingString:@"/"]; + url = [url stringByAppendingString:@"edit"]; + + // TODO: debug log + [self logWithFormat:@"compose on %@", url]; + + r = [[self context] response]; + [r setStatus:302 /* moved */]; + [r setHeader:url forKey:@"location"]; + [self reset]; + return r; +} + +/* response actions */ + +- (id)replyToAll:(BOOL)_replyToAll { + NSException *error; + id tmp; + + /* ensure mail exists and is filled */ + + // TODO: we could transport the body structure in a hidden field of the mail + // viewer to avoid refetching the core-info? + tmp = [[self clientObject] fetchCoreInfos]; + if ([tmp isKindOfClass:[NSException class]]) + return tmp; + if (![tmp isNotNull]) + return [self didNotFindMailError]; + + /* setup draft */ + + if ((error = [self _setupNewDraft]) != nil) + return error; + +#if 0 + [self logWithFormat:@"CORE: %@", [[self clientObject] fetchCoreInfos]]; +#endif + [self reset]; + return [NSException exceptionWithHTTPStatus:501 /* Not Implemented */ + reason:@"Sorry, reply is not yet implemented!"]; +} + +- (id)replyAction { + return [self replyToAll:NO]; +} +- (id)replyallAction { + return [self replyToAll:YES]; +} + +- (NSString *)getAttachmentNameForSubject:(NSString *)_subject { + /* SOGoDraftObject disallows some strings - anything else required? */ + static NSString *sescape[] = { + @"/", @"..", @"~", @"\"", @"'", @" ", @".", nil + }; + static int maxFilenameLength = 64; + NSString *s; + unsigned i; + + if (![_subject isNotNull] || [_subject length] == 0) + return _subject; + s = _subject; + + if ([s length] > maxFilenameLength) + s = [s substringToIndex:maxFilenameLength]; + + for (i = 0; sescape[i] != nil; i++) + s = [s stringByReplacingString:sescape[i] withString:@"_"]; + + return [s stringByAppendingString:@".mail"]; +} + +- (NSString *)forwardSubject:(NSString *)_subject { + if (![_subject isNotNull] || [_subject length] == 0) + return _subject; + + /* Note: this is how Thunderbird 1.0 creates the subject */ + _subject = [@"[Fwd: " stringByAppendingString:_subject]; + _subject = [_subject stringByAppendingString:@"]"]; + return _subject; +} + +- (id)forwardAction { + NSException *error; + NSData *content; + NSDictionary *info; + id result; + + /* fetch message */ + + if ((content = [[self clientObject] content]) == nil) + return [self didNotFindMailError]; + if ([content isKindOfClass:[NSException class]]) + return content; + + /* setup draft */ + + if ((error = [self _setupNewDraft]) != nil) + return error; + + /* set subject (do we need to set anything else?) */ + + info = [NSDictionary dictionaryWithObjectsAndKeys: + [self forwardSubject:[[self clientObject] subject]], + @"subject", + nil]; + if ((error = [self->newDraft storeInfo:info]) != nil) + return error; + + /* attach message */ + + // TODO: use subject for filename? + error = [self->newDraft saveAttachment:content withName:@"forward.mail"]; + if (error != nil) + return error; + + // TODO: we might want to pass the original URL to the editor for a final + // redirect back to the message? + result = [self redirectToEditNewDraft]; + [self reset]; + return result; +} + @end /* UIxMailEditorAction */ diff --git a/SOGo/UI/Mailer/UIxMailEditorAttach.m b/SOGo/UI/Mailer/UIxMailEditorAttach.m index 11b54a12..900e78bc 100644 --- a/SOGo/UI/Mailer/UIxMailEditorAttach.m +++ b/SOGo/UI/Mailer/UIxMailEditorAttach.m @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 SKYRIX Software AG + Copyright (C) 2004-2005 SKYRIX Software AG This file is part of OpenGroupware.org. @@ -18,7 +18,6 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id$ #include @@ -190,6 +189,8 @@ } - (BOOL)saveFileData:(NSData *)_data name:(NSString *)_name { + NSException *error; + if (_data == nil) return NO; if ([_name length] == 0) { @@ -201,7 +202,12 @@ return NO; // TODO: add size limit? - return [[self clientObject] saveAttachment:_data withName:_name]; + error = [[self clientObject] saveAttachment:_data withName:_name]; + if (error != nil) { + [self logWithFormat:@"ERROR: could not save: %@", error]; + return NO; + } + return YES; } /* actions */ @@ -232,11 +238,12 @@ } - (id)deleteAttachmentAction { - if (![[self clientObject] deleteAttachmentWithName:[self attachmentName]]) { - // TODO: improve error handling - return [NSException exceptionWithHTTPStatus:500 /* server error */ - reason:@"failed to delete attachment ..."]; - } + NSException *error; + + error = [[self clientObject] deleteAttachmentWithName:[self attachmentName]]; + + if (error != nil) + return error; return [self redirectToLocation:@"viewAttachments"]; } diff --git a/SOGo/UI/Mailer/UIxMailFormatter.h b/SOGo/UI/Mailer/UIxMailFormatter.h index c197eb29..49dded89 100644 --- a/SOGo/UI/Mailer/UIxMailFormatter.h +++ b/SOGo/UI/Mailer/UIxMailFormatter.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 SKYRIX Software AG + Copyright (C) 2004-2005 SKYRIX Software AG This file is part of OpenGroupware.org. @@ -61,6 +61,12 @@ @end +/* + TODO: the subject formatter should deal with the various 're:' like prefixes + and translate them into the native languages? + (or something like Re(5): ?) +*/ + @interface UIxSubjectFormatter : UIxMailFormatter { unsigned maxLength; diff --git a/SOGo/UI/Mailer/UIxMailListView.m b/SOGo/UI/Mailer/UIxMailListView.m index 09c7338d..3e061676 100644 --- a/SOGo/UI/Mailer/UIxMailListView.m +++ b/SOGo/UI/Mailer/UIxMailListView.m @@ -82,6 +82,20 @@ static int attachmentFlagSize = 8096; return NO; } +/* title */ + +- (NSString *)objectTitle { + return [[self clientObject] nameInContainer]; +} +- (NSString *)panelTitle { + NSString *s; + + s = [self labelForKey:@"View Mail Folder"]; + s = [s stringByAppendingString:@": "]; + s = [s stringByAppendingString:[self objectTitle]]; + return s; +} + /* derived accessors */ - (BOOL)isMessageDeleted { @@ -379,8 +393,9 @@ static int attachmentFlagSize = 8096; /* actions */ - (id)defaultAction { - // TODO: remove log +#if 0 [self logWithFormat:@"default action ..."]; +#endif self->firstMessageNumber = [[[[self context] request] formValueForKey:@"idx"] intValue]; return self; diff --git a/SOGo/UI/Mailer/UIxMailListView.wox b/SOGo/UI/Mailer/UIxMailListView.wox index 6b550ec1..6e4bbf12 100644 --- a/SOGo/UI/Mailer/UIxMailListView.wox +++ b/SOGo/UI/Mailer/UIxMailListView.wox @@ -7,7 +7,7 @@ xmlns:rsrc="OGo:url" xmlns:label="OGo:label" className="UIxMailMainFrame" - title="name" + title="panelTitle" >
+ diff --git a/SOGo/UI/Mailer/UIxSieveEditor.m b/SOGo/UI/Mailer/UIxSieveEditor.m index 7a25bded..1046401d 100644 --- a/SOGo/UI/Mailer/UIxSieveEditor.m +++ b/SOGo/UI/Mailer/UIxSieveEditor.m @@ -64,6 +64,10 @@ return [self->scriptText isNotNull] ? self->scriptText : @""; } +- (NSString *)panelTitle { + return [self labelForKey:@"Edit Mail Filter"]; +} + /* requests */ - (BOOL)shouldTakeValuesFromRequest:(WORequest *)_rq inContext:(WOContext*)_c { diff --git a/SOGo/UI/Mailer/UIxSieveEditor.wox b/SOGo/UI/Mailer/UIxSieveEditor.wox index 34b70998..d3d7fcfa 100644 --- a/SOGo/UI/Mailer/UIxSieveEditor.wox +++ b/SOGo/UI/Mailer/UIxSieveEditor.wox @@ -7,7 +7,7 @@ xmlns:rsrc="OGo:url" xmlns:label="OGo:label" className="UIxMailMainFrame" - title="name" + title="panelTitle" const:hideFolderTree="1" >
diff --git a/SOGo/UI/Mailer/UIxSubjectFormatter.m b/SOGo/UI/Mailer/UIxSubjectFormatter.m index 1ef2fc1a..60647c66 100644 --- a/SOGo/UI/Mailer/UIxSubjectFormatter.m +++ b/SOGo/UI/Mailer/UIxSubjectFormatter.m @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 SKYRIX Software AG + Copyright (C) 2004-2005 SKYRIX Software AG This file is part of OpenGroupware.org. diff --git a/SOGo/UI/Mailer/Version b/SOGo/UI/Mailer/Version index 209d038c..cbd97192 100644 --- a/SOGo/UI/Mailer/Version +++ b/SOGo/UI/Mailer/Version @@ -1,7 +1,8 @@ # version file -SUBMINOR_VERSION:=79 +SUBMINOR_VERSION:=80 +# v0.9.80 requires SoObjects/Mailer v0.9.59 # v0.9.78 requires SoObjects/Mailer v0.9.58 # v0.9.77 requires SoObjects/Mailer v0.9.57 # v0.9.74 requires SoObjects/Mailer v0.9.56 diff --git a/SOGo/UI/Mailer/product.plist b/SOGo/UI/Mailer/product.plist index edefca9b..c35e679d 100644 --- a/SOGo/UI/Mailer/product.plist +++ b/SOGo/UI/Mailer/product.plist @@ -180,17 +180,11 @@ ( // third group { link = "delete"; cssClass = "tbicon_delete"; label = "Delete"; }, - ), -/* TODO: enable when implemented - ( // third group -// TODO: enable when delete works (#1212) - { link = "#"; - cssClass = "tbicon_delete"; label = "Delete"; }, -// TODO: enable when we know how to mark junk (#971) +/* TODO: enable when we know how to mark junk (#971) { link = "#"; cssClass = "tbicon_junk"; label = "Junk"; }, - ), */ + ), ( /* fourth group */ /* TODO: enable when we can print (#1207) { link = "#"; cssClass = "tbicon_print"; label = "Print"; }, -- 2.39.5